Files
jongryangje/app/Views/bag/inventory_inspection_select.php

397 lines
19 KiB
PHP
Raw Normal View History

<?php
$startDate = (string) ($startDate ?? date('Y-m-01'));
$endDate = (string) ($endDate ?? date('Y-m-d'));
$workDate = (string) ($workDate ?? date('Y-m-d'));
$itemCode = (string) ($itemCode ?? '');
$viewType = (string) ($viewType ?? 'box');
$inspectionRuns = is_array($inspectionRuns ?? null) ? $inspectionRuns : [];
$popupItems = is_array($popupItems ?? null) ? $popupItems : [];
$items = is_array($items ?? null) ? $items : [];
$overviewRows = is_array($overviewRows ?? null) ? $overviewRows : [];
$selectedInspectionItemId = (int) ($selectedInspectionItemId ?? 0);
$selectedInspectionId = (int) ($selectedInspectionId ?? 0);
$boxRows = is_array($boxRows ?? null) ? $boxRows : [];
$selectedBoxCode = (string) ($selectedBoxCode ?? '');
$selectedPackCode = (string) ($selectedPackCode ?? '');
$sheetRows = is_array($sheetRows ?? null) ? $sheetRows : [];
$overviewTotalQty = 0;
foreach ($overviewRows as $row) {
$overviewTotalQty += (int) ($row['bisi_system_qty'] ?? 0);
}
$overviewTotalActual = 0;
foreach ($overviewRows as $row) {
$overviewTotalActual += (int) ($row['bisi_actual_qty'] ?? 0);
}
$overviewTotalDiff = $overviewTotalActual - $overviewTotalQty;
$packTotalQty = 0;
foreach ($boxRows as $row) {
$packTotalQty += (int) ($row['bisp_sheet_qty'] ?? 0);
}
$packTotalActual = 0;
foreach ($boxRows as $row) {
$packTotalActual += (int) ($row['bisp_actual_qty'] ?? 0);
}
$packTotalDiff = $packTotalActual - $packTotalQty;
$sheetTotalQty = 0;
foreach ($sheetRows as $row) {
$sheetTotalQty += (int) ($row['biss_system_qty'] ?? 0);
}
$sheetTotalActual = 0;
foreach ($sheetRows as $row) {
$sheetTotalActual += (int) ($row['biss_actual_qty'] ?? 0);
}
$sheetTotalDiff = $sheetTotalActual - $sheetTotalQty;
?>
<div class="space-y-2">
<section class="border border-gray-300 bg-white p-2">
<form method="get" class="flex flex-wrap items-end justify-between gap-2 text-sm">
<div class="flex flex-wrap items-end gap-2">
<label class="font-bold text-gray-700">실사기간</label>
<input type="date" name="start_date" value="<?= esc($startDate) ?>" class="border border-gray-300 rounded px-2 py-1">
<span>~</span>
<input type="date" name="end_date" value="<?= esc($endDate) ?>" class="border border-gray-300 rounded px-2 py-1">
<label class="font-bold text-gray-700 ml-2">실사품목</label>
<select name="item_code" class="border border-gray-300 rounded px-2 py-1 min-w-[11rem]">
<option value="">전체</option>
<?php foreach ($items as $it): ?>
<?php $code = (string) ($it['bag_code'] ?? ''); ?>
<option value="<?= esc($code) ?>" <?= $itemCode === $code ? 'selected' : '' ?>>
<?= esc((string) ($it['bag_name'] ?? '')) ?>
</option>
<?php endforeach; ?>
</select>
<label class="font-bold text-gray-700 ml-2">조회구분</label>
<select name="view_type" class="border border-gray-300 rounded px-2 py-1 min-w-[7rem]">
<option value="box" <?= $viewType === 'box' ? 'selected' : '' ?>>박스별</option>
<option value="pack" <?= $viewType === 'pack' ? 'selected' : '' ?>>팩별</option>
</select>
</div>
<div class="flex items-center gap-2">
<button type="submit" class="bg-btn-search text-white px-3 py-1 rounded-sm">조회</button>
<button type="button" id="open-inspection-popup" class="border border-blue-300 text-blue-700 px-3 py-1 rounded-sm hover:bg-blue-50">실사 선별</button>
</div>
</form>
<p class="mt-1 text-xs text-blue-700"> 해당 박스와 팩을 클릭하면 팩과 낱장이 조회됩니다.</p>
</section>
<section class="grid grid-cols-1 xl:grid-cols-2 gap-2">
<div class="border border-gray-300 bg-white">
<div class="border-b border-gray-300 bg-gray-50 px-2 py-1 text-sm font-bold text-gray-700">실사 선별자</div>
<div class="overflow-auto max-h-[500px]">
<table class="w-full data-table text-sm">
<thead>
<tr>
<th class="w-24">실사일자</th>
<th>종류</th>
<th class="w-40">박스</th>
<th class="w-20">전산재고</th>
<th class="w-20">실사재고</th>
</tr>
</thead>
<tbody>
<?php if ($overviewRows !== []): ?>
<?php $prevBagName = null; ?>
<?php foreach ($overviewRows as $row): ?>
<?php
$itemId = (int) ($row['bisi_idx'] ?? 0);
$bagName = (string) ($row['bisi_bag_name'] ?? '');
$showBagName = $prevBagName !== $bagName;
$prevBagName = $bagName;
$boxCode = (string) ($row['box_code'] ?? '');
$isSelected = $itemId === $selectedInspectionItemId
&& ($selectedBoxCode === '' || $selectedBoxCode === $boxCode);
$url = base_url('bag/inventory/inspection-work?' . http_build_query([
'start_date' => $startDate,
'end_date' => $endDate,
'bis_id' => $selectedInspectionId,
'item_code' => $itemCode,
'view_type' => $viewType,
'sel_item_id' => $itemId,
'sel_box_code' => $boxCode,
'sel_pack_code' => '',
]));
?>
<tr class="<?= $isSelected ? 'bg-blue-100' : 'cursor-pointer hover:bg-blue-50' ?>" onclick="window.location.href='<?= esc($url, 'attr') ?>'">
<td class="text-center"><?= esc((string) ($row['bis_work_date'] ?? '')) ?></td>
<td class="pl-2"><?= $showBagName ? esc($bagName) : '' ?></td>
<td class="text-center"><?= esc((string) ($row['box_code'] ?? '')) ?></td>
<td class="text-right pr-2"><?= number_format((int) ($row['bisi_system_qty'] ?? 0)) ?></td>
<td class="text-right pr-2"><?= number_format((int) ($row['bisi_actual_qty'] ?? 0)) ?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="5" class="text-center text-gray-400 py-4">조회 결과가 없습니다.</td></tr>
<?php endif; ?>
</tbody>
<tfoot>
<tr class="bg-gray-100 font-semibold">
<td class="text-center" colspan="3">합계</td>
<td class="text-right pr-2"><?= number_format($overviewTotalQty) ?></td>
<td class="text-right pr-2"><?= number_format($overviewTotalActual) ?></td>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="space-y-2">
<div class="border border-gray-300 bg-white">
<div class="border-b border-gray-300 bg-gray-50 px-2 py-1 text-sm font-bold text-gray-700">실사 선별 품목(선택 박스 조회)</div>
<form method="post" action="<?= base_url('bag/inventory/inspection-select/save') ?>" id="inspection-save-form">
<?= csrf_field() ?>
<input type="hidden" name="bisi_idx" value="<?= esc((string) $selectedInspectionItemId) ?>">
<input type="hidden" name="bis_id" value="<?= esc((string) $selectedInspectionId) ?>">
<input type="hidden" name="start_date" value="<?= esc($startDate) ?>">
<input type="hidden" name="end_date" value="<?= esc($endDate) ?>">
<input type="hidden" name="item_code" value="<?= esc($itemCode) ?>">
<input type="hidden" name="view_type" value="<?= esc($viewType) ?>">
<input type="hidden" name="sel_item_id" value="<?= esc((string) $selectedInspectionItemId) ?>">
<input type="hidden" name="sel_box_code" value="<?= esc($selectedBoxCode) ?>">
<input type="hidden" name="sel_pack_code" value="<?= esc($selectedPackCode) ?>">
<input type="hidden" name="pack_actual_json" value="">
<div class="overflow-auto max-h-[260px]">
<table class="w-full data-table text-sm">
<thead>
<tr>
<th>팩코드</th>
<th class="w-16">포장량</th>
<th class="w-16">재고</th>
<th class="w-20">실사재고</th>
<th class="w-16">차이</th>
<th>낱장(시작)</th>
<th>낱장()</th>
</tr>
</thead>
<tbody>
<?php if ($boxRows !== []): ?>
<?php foreach ($boxRows as $row): ?>
<?php
$code = (string) ($row['bisp_box_code'] ?? '');
$packCode = (string) ($row['bisp_pack_code'] ?? '');
$systemQty = (int) ($row['bisp_sheet_qty'] ?? 0);
$actualQty = isset($row['bisp_actual_qty']) ? (int) $row['bisp_actual_qty'] : $systemQty;
$url = base_url('bag/inventory/inspection-work?' . http_build_query([
'start_date' => $startDate,
'end_date' => $endDate,
'bis_id' => $selectedInspectionId,
'item_code' => $itemCode,
'view_type' => $viewType,
'sel_item_id' => $selectedInspectionItemId,
'sel_box_code' => $code,
'sel_pack_code' => $packCode,
]));
$isSelected = $selectedBoxCode === $code && $selectedPackCode === $packCode;
?>
<tr class="<?= $isSelected ? 'bg-blue-100' : 'cursor-pointer hover:bg-blue-50' ?>" onclick="window.location.href='<?= esc($url, 'attr') ?>'">
<td class="pl-2"><?= esc($packCode) ?></td>
<td class="text-center js-pack-system"><?= number_format($systemQty) ?></td>
<td class="text-right pr-2 js-pack-stock"><?= number_format($systemQty) ?></td>
<td class="text-right pr-2">
<input type="number" min="0"
value="<?= esc((string) $actualQty) ?>"
data-pack-idx="<?= esc((string) ($row['bisp_idx'] ?? 0), 'attr') ?>"
data-original-value="<?= esc((string) $systemQty, 'attr') ?>"
data-system-qty="<?= esc((string) $systemQty, 'attr') ?>"
class="border border-gray-300 rounded px-1 py-0.5 w-20 text-right"
onclick="event.stopPropagation();">
</td>
<?php $diff = (int) ($row['bisp_diff_qty'] ?? 0); ?>
<td class="text-right pr-2 js-pack-diff <?= $diff === 0 ? '' : ($diff > 0 ? 'text-blue-700' : 'text-red-700') ?>"><?= number_format($diff) ?></td>
<td class="text-center"><?= esc((string) ($row['bisp_sheet_start_code'] ?? '')) ?></td>
<td class="text-center"><?= esc((string) ($row['bisp_sheet_end_code'] ?? '')) ?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="7" class="text-center text-gray-400 py-4">선택된 품목이 없습니다.</td></tr>
<?php endif; ?>
</tbody>
<tfoot>
<tr class="bg-gray-100 font-semibold">
<td class="text-center" colspan="2">합계</td>
<td class="text-right pr-2"><?= number_format($packTotalQty) ?></td>
<td class="text-right pr-2"><?= number_format($packTotalActual) ?></td>
<td class="text-right pr-2 <?= $packTotalDiff === 0 ? '' : ($packTotalDiff > 0 ? 'text-blue-700' : 'text-red-700') ?>"><?= number_format($packTotalDiff) ?></td>
<td colspan="2"></td>
</tr>
</tfoot>
</table>
</div>
<div class="p-2 border-t border-gray-300 flex items-center justify-between">
<span class="text-xs text-gray-500">선택 품목의 실사수량을 입력 저장하세요.</span>
<div class="flex items-center gap-2">
<button type="submit" class="bg-btn-search text-white px-3 py-1 rounded-sm text-sm">실사 저장</button>
</div>
</div>
</form>
</div>
<div class="border border-gray-300 bg-white">
<div class="border-b border-gray-300 bg-gray-50 px-2 py-1 text-sm font-bold text-gray-700">실사 선별 내용(선택 낱장 코드 조회)</div>
<div class="overflow-auto max-h-[240px]">
<table class="w-full data-table text-sm">
<thead>
<tr>
<th class="w-12">No</th>
<th>낱장</th>
<th class="w-16">전산</th>
<th class="w-16">실사</th>
<th class="w-16">차이</th>
</tr>
</thead>
<tbody>
<?php if ($sheetRows !== []): ?>
<?php foreach ($sheetRows as $row): ?>
<?php
$sSystem = (int) ($row['biss_system_qty'] ?? 1);
$sActual = (int) ($row['biss_actual_qty'] ?? 0);
$sDiff = (int) ($row['biss_diff_qty'] ?? 0);
?>
<tr>
<td class="text-center"><?= esc((string) ($row['no'] ?? '')) ?></td>
<td class="pl-2"><?= esc((string) ($row['biss_sheet_code'] ?? '')) ?></td>
<td class="text-right pr-2"><?= number_format($sSystem) ?></td>
<td class="text-right pr-2"><?= number_format($sActual) ?></td>
<td class="text-right pr-2 <?= $sDiff === 0 ? '' : ($sDiff > 0 ? 'text-blue-700' : 'text-red-700') ?>"><?= number_format($sDiff) ?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="5" class="text-center text-gray-400 py-4">선택된 /박스가 없습니다.</td></tr>
<?php endif; ?>
</tbody>
<tfoot>
<tr class="bg-gray-100 font-semibold">
<td class="text-center" colspan="2">합계</td>
<td class="text-right pr-2"><?= number_format($sheetTotalQty) ?></td>
<td class="text-right pr-2"><?= number_format($sheetTotalActual) ?></td>
<td class="text-right pr-2 <?= $sheetTotalDiff === 0 ? '' : ($sheetTotalDiff > 0 ? 'text-blue-700' : 'text-red-700') ?>"><?= number_format($sheetTotalDiff) ?></td>
</tr>
</tfoot>
</table>
</div>
</div>
<div class="border border-gray-300 bg-white p-2 text-sm text-gray-600">
실사 저장 차이수량이 즉시 장부 재고에 반영됩니다.
</div>
</div>
</section>
</div>
<div id="inspection-popup" class="fixed inset-0 bg-black/40 hidden items-center justify-center z-[999]">
<div class="bg-white border border-gray-400 w-[min(720px,95vw)] max-h-[90vh] overflow-auto p-4">
<div class="flex items-center justify-between mb-3">
<h3 class="text-lg font-bold">실사 선별</h3>
<button type="button" id="close-inspection-popup" class="text-gray-600 hover:text-gray-900">닫기</button>
</div>
<form method="post" action="<?= base_url('bag/inventory/inspection-run') ?>" id="inspection-run-form" class="space-y-3">
<?= csrf_field() ?>
<div class="flex items-center gap-2">
<label class="font-bold text-gray-700 text-sm">작업 일자</label>
<input type="date" name="work_date" value="<?= esc($workDate) ?>" class="border border-gray-300 rounded px-2 py-1 text-sm">
</div>
<p class="text-red-600 font-semibold">바코드가 없는 봉투는 실사에서 제외 됩니다.</p>
<div class="overflow-auto border border-gray-300 max-h-[55vh]">
<table class="w-full data-table text-sm">
<thead>
<tr><th>종류</th><th class="w-20">선택구분</th></tr>
</thead>
<tbody>
<?php foreach ($popupItems as $row): ?>
<?php $hasBarcode = (bool) ($row['has_barcode'] ?? false); ?>
<tr class="<?= $hasBarcode ? '' : 'bg-gray-50 text-gray-400' ?>">
<td class="pl-2"><?= esc((string) ($row['bag_name'] ?? '')) ?></td>
<td class="text-center">
<input type="checkbox" name="bag_codes[]" value="<?= esc((string) ($row['bag_code'] ?? ''), 'attr') ?>" <?= $hasBarcode ? '' : 'disabled' ?>>
</td>
</tr>
<?php endforeach; ?>
</tbody>
</table>
</div>
<div class="flex justify-end gap-2">
<button type="submit" class="bg-btn-search text-white px-5 py-1.5 rounded-sm text-sm">실행</button>
</div>
</form>
</div>
</div>
<script>
(() => {
const popup = document.getElementById('inspection-popup');
const openBtn = document.getElementById('open-inspection-popup');
const closeBtn = document.getElementById('close-inspection-popup');
if (openBtn && popup) {
openBtn.addEventListener('click', () => {
popup.classList.remove('hidden');
popup.classList.add('flex');
});
}
if (closeBtn && popup) {
closeBtn.addEventListener('click', () => {
popup.classList.add('hidden');
popup.classList.remove('flex');
});
}
const form = document.getElementById('inspection-run-form');
if (form) {
form.addEventListener('submit', (event) => {
if (!window.confirm('전산 선별 처리를 실행하시겠습니까?')) {
event.preventDefault();
}
});
}
const saveForm = document.getElementById('inspection-save-form');
if (saveForm) {
const formatNumber = (value) => {
const n = Number.isFinite(value) ? value : 0;
return n.toLocaleString('ko-KR');
};
const updateDiff = (input) => {
const row = input.closest('tr');
if (!row) {
return;
}
const system = parseInt(String(input.getAttribute('data-system-qty') ?? '0'), 10) || 0;
const actual = Math.max(0, parseInt(String(input.value ?? '0'), 10) || 0);
const diff = actual - system;
const diffCell = row.querySelector('.js-pack-diff');
if (!diffCell) {
return;
}
diffCell.textContent = formatNumber(diff);
diffCell.classList.remove('text-blue-700', 'text-red-700');
if (diff > 0) {
diffCell.classList.add('text-blue-700');
} else if (diff < 0) {
diffCell.classList.add('text-red-700');
}
};
const qtyInputs = saveForm.querySelectorAll('input[data-pack-idx]');
qtyInputs.forEach((input) => {
input.addEventListener('input', () => updateDiff(input));
updateDiff(input);
});
saveForm.addEventListener('submit', () => {
const payload = {};
qtyInputs.forEach((input) => {
const idx = String(input.getAttribute('data-pack-idx') ?? '').trim();
if (idx === '') {
return;
}
payload[idx] = Math.max(0, parseInt(String(input.value ?? '0'), 10) || 0);
});
const jsonInput = saveForm.querySelector('input[name="pack_actual_json"]');
if (jsonInput) {
jsonInput.value = JSON.stringify(payload);
}
});
}
})();
</script>