2026-06-01 16:15:15 +09:00
|
|
|
|
<?php
|
|
|
|
|
|
$refDate = (string) ($refDate ?? date('Y-m-d'));
|
|
|
|
|
|
$leadDays = (int) ($leadDays ?? 40);
|
|
|
|
|
|
$stockScope = (string) ($stockScope ?? 'all');
|
|
|
|
|
|
$salesScope = (string) ($salesScope ?? 'all');
|
|
|
|
|
|
$rows = is_array($rows ?? null) ? $rows : [];
|
|
|
|
|
|
$queried = (bool) ($queried ?? false);
|
|
|
|
|
|
$stockLabel = (string) ($stockLabel ?? 'ALL');
|
|
|
|
|
|
$salesLabel = (string) ($salesLabel ?? 'ALL');
|
|
|
|
|
|
|
|
|
|
|
|
$fmtKrRef = static function (string $ymd): string {
|
|
|
|
|
|
$ts = strtotime($ymd);
|
|
|
|
|
|
|
|
|
|
|
|
return $ts ? date('Y.m.d', $ts) . ' 현재' : $ymd;
|
|
|
|
|
|
};
|
|
|
|
|
|
|
2026-06-08 00:46:51 +09:00
|
|
|
|
/** 툴팁: 의미 + 계산(간단) */
|
|
|
|
|
|
$tipPage = "봉투 품목별로 재고가 며칠 버티는지, 언제·얼마나 발주할지 보는 수급·발주 계획표입니다.";
|
|
|
|
|
|
$tipLead = "의미: 발주 후 입고까지 걸리는 제작기일(일). 재고 소진 전에 발주하려는 여유.\n계산: 발주예정일 = 기준일 + 소진일수 − 보유일수";
|
|
|
|
|
|
$tipStock = "의미: 표에 넣을 현재고·총재고 범위.\n기존=바코드 미등록(수기), 바코드=등록 품목.";
|
|
|
|
|
|
$tipSales = "의미: 소진일수에 쓸 판매 속도 범위.\n최근 12개월 순판매(또는 바코드 판매) 월평균.";
|
|
|
|
|
|
$tipTotal = "의미: 지금·곧 쓸 수 있는 재고 합계.\n계산: 현재고 + 입고예정량";
|
|
|
|
|
|
$tipMonth = "의미: 요즘 한 달 판매 규모(평균).\n최근 12개월 월평균 판매량.";
|
|
|
|
|
|
$tipDepl = "의미: 이 판매 속도면 재고가 며칠 남는지.\n계산: (총재고 ÷ 월판매량) × 30";
|
|
|
|
|
|
$tipSched = "의미: 발주를 넣기 좋은 날(제작기일 반영).\n계산: 기준일 + 소진일수 − 보유일수. 기한 지남=빨간색·긴급";
|
|
|
|
|
|
$tipOrder = "의미: 그 시점에 맞춰 제안하는 추가 발주 장수.\n촉박하거나 발주예정일이 지난 품목만 표시.";
|
|
|
|
|
|
|
2026-06-01 16:15:15 +09:00
|
|
|
|
$printExtraLines = [
|
|
|
|
|
|
$fmtKrRef($refDate),
|
|
|
|
|
|
'적정재고 보유일수(제작기일): ' . $leadDays . '일',
|
|
|
|
|
|
'현재고: ' . $stockLabel . ' · 월평균판매량: ' . $salesLabel,
|
|
|
|
|
|
'※ 제작기일 ' . $leadDays . '일 기준으로 발주예정일 산정 (레거시 화면 유추)',
|
|
|
|
|
|
];
|
|
|
|
|
|
?>
|
|
|
|
|
|
<?= view('components/print_header', [
|
|
|
|
|
|
'printTitle' => '쓰레기봉투 수급 계획',
|
|
|
|
|
|
'printExtraLines' => $printExtraLines,
|
|
|
|
|
|
]) ?>
|
|
|
|
|
|
|
|
|
|
|
|
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel no-print">
|
2026-03-26 16:40:49 +09:00
|
|
|
|
<div class="flex flex-wrap items-center justify-between gap-y-2">
|
2026-06-08 00:46:51 +09:00
|
|
|
|
<span class="text-sm font-bold text-gray-700 inline-flex items-center gap-1">
|
|
|
|
|
|
쓰레기봉투 수급 계획
|
|
|
|
|
|
<?= view('components/field_tooltip', ['text' => $tipPage, 'placement' => 'below']) ?>
|
|
|
|
|
|
</span>
|
2026-06-01 16:15:15 +09:00
|
|
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
|
|
|
|
<button type="button" onclick="window.print()" class="border border-btn-print-border text-gray-600 px-3 py-1 rounded-sm text-sm hover:bg-gray-50">인쇄</button>
|
|
|
|
|
|
<a href="<?= base_url('dashboard') ?>" class="border border-gray-400 text-gray-700 px-3 py-1 rounded-sm text-sm hover:bg-gray-50">종료</a>
|
|
|
|
|
|
</div>
|
2026-03-26 16:40:49 +09:00
|
|
|
|
</div>
|
2026-03-25 18:29:31 +09:00
|
|
|
|
</section>
|
|
|
|
|
|
|
2026-06-01 16:15:15 +09:00
|
|
|
|
<section class="p-2 bg-white border-b border-gray-200 no-print text-sm">
|
|
|
|
|
|
<form method="get" action="<?= mgmt_url('reports/supply-demand') ?>" class="flex flex-wrap items-end gap-x-4 gap-y-3">
|
|
|
|
|
|
<input type="hidden" name="search" value="1"/>
|
2026-03-25 18:29:31 +09:00
|
|
|
|
|
2026-06-01 16:15:15 +09:00
|
|
|
|
<div class="flex flex-wrap items-center gap-2">
|
|
|
|
|
|
<label class="font-bold text-gray-700 whitespace-nowrap">기준일</label>
|
|
|
|
|
|
<input type="date" name="ref_date" value="<?= esc($refDate) ?>" class="border border-gray-300 rounded px-2 py-1" required/>
|
|
|
|
|
|
<span class="text-gray-600"><?= esc($fmtKrRef($refDate)) ?></span>
|
2026-03-25 18:29:31 +09:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-06-01 16:15:15 +09:00
|
|
|
|
<div class="flex flex-wrap items-center gap-2">
|
2026-06-08 00:46:51 +09:00
|
|
|
|
<label class="font-bold text-gray-700 whitespace-nowrap inline-flex items-center gap-0.5">
|
|
|
|
|
|
적정재고 보유일수
|
|
|
|
|
|
<?= view('components/field_tooltip', ['text' => $tipLead]) ?>
|
|
|
|
|
|
</label>
|
2026-06-01 16:15:15 +09:00
|
|
|
|
<input type="number" name="lead_days" value="<?= (int) $leadDays ?>" min="1" max="365"
|
2026-06-08 00:46:51 +09:00
|
|
|
|
class="border border-gray-300 rounded px-2 py-1 w-20 text-right"/>
|
2026-03-25 18:29:31 +09:00
|
|
|
|
</div>
|
|
|
|
|
|
|
2026-06-01 16:15:15 +09:00
|
|
|
|
<fieldset class="flex flex-wrap items-center gap-2 border-0 p-0 m-0">
|
2026-06-08 00:46:51 +09:00
|
|
|
|
<legend class="font-bold text-gray-700 whitespace-nowrap mr-1 inline-flex items-center gap-0.5">
|
|
|
|
|
|
현재고 선택 옵션
|
|
|
|
|
|
<?= view('components/field_tooltip', ['text' => $tipStock]) ?>
|
|
|
|
|
|
</legend>
|
2026-06-01 16:15:15 +09:00
|
|
|
|
<?php foreach (['all' => 'ALL', 'legacy' => '기존 봉투', 'barcode' => '바코드 봉투'] as $val => $lab): ?>
|
|
|
|
|
|
<label class="inline-flex items-center gap-1">
|
|
|
|
|
|
<input type="radio" name="stock_scope" value="<?= esc($val) ?>" <?= $stockScope === $val ? 'checked' : '' ?>/>
|
|
|
|
|
|
<?= esc($lab) ?>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</fieldset>
|
|
|
|
|
|
|
|
|
|
|
|
<fieldset class="flex flex-wrap items-center gap-2 border-0 p-0 m-0">
|
2026-06-08 00:46:51 +09:00
|
|
|
|
<legend class="font-bold text-gray-700 whitespace-nowrap mr-1 inline-flex items-center gap-0.5">
|
|
|
|
|
|
월 평균판매량 선택 옵션
|
|
|
|
|
|
<?= view('components/field_tooltip', ['text' => $tipSales]) ?>
|
|
|
|
|
|
</legend>
|
2026-06-01 16:15:15 +09:00
|
|
|
|
<?php foreach (['all' => 'ALL', 'legacy' => '기존 봉투', 'barcode' => '바코드 봉투'] as $val => $lab): ?>
|
|
|
|
|
|
<label class="inline-flex items-center gap-1">
|
|
|
|
|
|
<input type="radio" name="sales_scope" value="<?= esc($val) ?>" <?= $salesScope === $val ? 'checked' : '' ?>/>
|
|
|
|
|
|
<?= esc($lab) ?>
|
|
|
|
|
|
</label>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</fieldset>
|
|
|
|
|
|
|
|
|
|
|
|
<button type="submit" class="bg-btn-search text-white px-4 py-1 rounded-sm">조회</button>
|
|
|
|
|
|
</form>
|
|
|
|
|
|
</section>
|
|
|
|
|
|
|
|
|
|
|
|
<?php if (! $queried): ?>
|
|
|
|
|
|
<div class="m-2 p-3 border border-blue-200 bg-blue-50 text-sm text-blue-900 no-print">
|
|
|
|
|
|
기준일·옵션을 선택한 뒤 <strong>조회</strong>를 눌러 주세요.
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
|
|
|
|
|
|
<div class="supply-plan-print-sheet">
|
|
|
|
|
|
<div class="supply-plan-print m-2 border border-gray-300 overflow-auto print:m-0">
|
|
|
|
|
|
<table class="w-full data-table text-sm supply-plan-table">
|
|
|
|
|
|
<thead>
|
|
|
|
|
|
<tr class="bg-gray-100">
|
|
|
|
|
|
<th colspan="4" class="text-center border-b border-gray-300 sp-group-h">최근 발주 내역</th>
|
|
|
|
|
|
<th colspan="5" class="text-center border-b border-gray-300 border-l sp-group-h">현재고 및 예상 판매일수</th>
|
|
|
|
|
|
<th colspan="2" class="text-center border-b border-gray-300 border-l sp-group-h">추가발주 예정내역</th>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<th class="sp-col-date">발주일자</th>
|
|
|
|
|
|
<th class="sp-col-name">봉투종류</th>
|
|
|
|
|
|
<th class="sp-col-num text-right">발주량</th>
|
|
|
|
|
|
<th class="sp-col-num text-right">발주시재고</th>
|
|
|
|
|
|
<th class="sp-col-num text-right border-l">현재고</th>
|
|
|
|
|
|
<th class="sp-col-num text-right">입고예정량</th>
|
2026-06-08 00:46:51 +09:00
|
|
|
|
<th class="sp-col-num text-right">
|
|
|
|
|
|
<span class="inline-flex items-center justify-end gap-0.5 w-full">총재고<?= view('components/field_tooltip', ['text' => $tipTotal, 'placement' => 'below']) ?></span>
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th class="sp-col-num text-right">
|
|
|
|
|
|
<span class="inline-flex items-center justify-end gap-0.5 w-full">월판매량<?= view('components/field_tooltip', ['text' => $tipMonth, 'placement' => 'below']) ?></span>
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th class="sp-col-num text-right">
|
|
|
|
|
|
<span class="inline-flex items-center justify-end gap-0.5 w-full">소진일수(일)<?= view('components/field_tooltip', ['text' => $tipDepl, 'placement' => 'below']) ?></span>
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th class="sp-col-date text-center border-l">
|
|
|
|
|
|
<span class="inline-flex items-center justify-center gap-0.5">발주예정일<?= view('components/field_tooltip', ['text' => $tipSched, 'placement' => 'below']) ?></span>
|
|
|
|
|
|
</th>
|
|
|
|
|
|
<th class="sp-col-num text-right">
|
|
|
|
|
|
<span class="inline-flex items-center justify-end gap-0.5 w-full">발주수량<?= view('components/field_tooltip', ['text' => $tipOrder, 'placement' => 'below']) ?></span>
|
|
|
|
|
|
</th>
|
2026-06-01 16:15:15 +09:00
|
|
|
|
</tr>
|
|
|
|
|
|
</thead>
|
|
|
|
|
|
<tbody>
|
|
|
|
|
|
<?php if ($queried && $rows === []): ?>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td colspan="11" class="text-center text-gray-500 py-8">표시할 품목이 없습니다.</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<?php endif; ?>
|
|
|
|
|
|
<?php foreach ($rows as $row): ?>
|
|
|
|
|
|
<?php
|
|
|
|
|
|
$depl = (int) ($row['depletion_days'] ?? 0);
|
|
|
|
|
|
$deplDisplay = $depl <= 0 ? '—' : number_format($depl);
|
|
|
|
|
|
$sched = (string) ($row['schedule_date'] ?? '');
|
|
|
|
|
|
$schedOver = (bool) ($row['schedule_overdue'] ?? false);
|
|
|
|
|
|
$schedDisplay = '—';
|
|
|
|
|
|
if (preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $sched, $m)) {
|
|
|
|
|
|
$y = (int) $m[1];
|
|
|
|
|
|
if ($y >= 1990 && $y <= 2200) {
|
|
|
|
|
|
$schedDisplay = $m[1] . '.' . $m[2] . '.' . $m[3];
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
?>
|
|
|
|
|
|
<tr>
|
|
|
|
|
|
<td class="sp-col-date text-center"><?= ($row['last_order_date'] ?? '') !== '' ? esc(str_replace('-', '.', (string) $row['last_order_date'])) : '—' ?></td>
|
|
|
|
|
|
<td class="sp-col-name text-left"><?= esc((string) ($row['bag_name'] ?? $row['bag_code'] ?? '')) ?></td>
|
|
|
|
|
|
<td class="sp-col-num text-right tabular-nums"><?= (int) ($row['last_order_qty'] ?? 0) > 0 ? number_format((int) $row['last_order_qty']) : '—' ?></td>
|
|
|
|
|
|
<td class="sp-col-num text-right tabular-nums"><?= (int) ($row['stock_at_order'] ?? 0) > 0 ? number_format((int) $row['stock_at_order']) : '—' ?></td>
|
|
|
|
|
|
<td class="sp-col-num text-right tabular-nums border-l"><?= number_format((int) ($row['current_stock'] ?? 0)) ?></td>
|
|
|
|
|
|
<td class="sp-col-num text-right tabular-nums"><?= number_format((int) ($row['pending_inbound'] ?? 0)) ?></td>
|
|
|
|
|
|
<td class="sp-col-num text-right tabular-nums font-semibold"><?= number_format((int) ($row['total_stock'] ?? 0)) ?></td>
|
|
|
|
|
|
<td class="sp-col-num text-right tabular-nums"><?= number_format((int) ($row['monthly_avg_sales'] ?? 0)) ?></td>
|
|
|
|
|
|
<td class="sp-col-num text-right tabular-nums"><?= esc($deplDisplay) ?></td>
|
|
|
|
|
|
<td class="sp-col-date text-center border-l <?= $schedOver ? 'text-red-600 font-bold' : '' ?>"><?= esc($schedDisplay) ?></td>
|
|
|
|
|
|
<td class="sp-col-num text-right tabular-nums <?= (int) ($row['order_qty'] ?? 0) > 0 ? 'text-red-600 font-bold' : '' ?>">
|
|
|
|
|
|
<?= number_format((int) ($row['order_qty'] ?? 0)) ?>
|
|
|
|
|
|
</td>
|
|
|
|
|
|
</tr>
|
|
|
|
|
|
<?php endforeach; ?>
|
|
|
|
|
|
</tbody>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
</div>
|
2026-03-25 18:29:31 +09:00
|
|
|
|
</div>
|
2026-06-01 16:15:15 +09:00
|
|
|
|
|
|
|
|
|
|
<style>
|
2026-06-08 00:46:51 +09:00
|
|
|
|
.field-tip { position: relative; display: inline-flex; vertical-align: middle; }
|
|
|
|
|
|
.field-tip-btn {
|
|
|
|
|
|
display: inline-flex; align-items: center; justify-content: center;
|
|
|
|
|
|
width: 14px; height: 14px; font-size: 10px; font-weight: 700; line-height: 1;
|
|
|
|
|
|
color: #6b7280; background: #f3f4f6; border: 1px solid #d1d5db; border-radius: 50%;
|
|
|
|
|
|
cursor: help; user-select: none;
|
|
|
|
|
|
}
|
|
|
|
|
|
.field-tip-btn:hover, .field-tip-btn:focus { color: #1d4ed8; border-color: #93c5fd; background: #eff6ff; outline: none; }
|
|
|
|
|
|
.field-tip-panel {
|
|
|
|
|
|
position: absolute; z-index: 60; left: 50%; transform: translateX(-50%);
|
|
|
|
|
|
bottom: calc(100% + 6px); width: max-content; max-width: 280px;
|
|
|
|
|
|
padding: 0.35rem 0.5rem; border-radius: 4px;
|
|
|
|
|
|
background: #1f2937; color: #f9fafb; font-size: 11px; font-weight: 500; line-height: 1.35;
|
|
|
|
|
|
text-align: left; white-space: pre-line; box-shadow: 0 2px 8px rgba(0,0,0,.15);
|
|
|
|
|
|
opacity: 0; visibility: hidden; pointer-events: none; transition: opacity .12s, visibility .12s;
|
|
|
|
|
|
}
|
|
|
|
|
|
.field-tip--below .field-tip-panel { bottom: auto; top: calc(100% + 6px); }
|
|
|
|
|
|
.field-tip:hover .field-tip-panel,
|
|
|
|
|
|
.field-tip:focus-within .field-tip-panel { opacity: 1; visibility: visible; }
|
|
|
|
|
|
|
|
|
|
|
|
.supply-plan-table thead th { font-size: 0.75rem; line-height: 1.2; padding: 0.35rem 0.25rem; overflow: visible; }
|
|
|
|
|
|
.supply-plan-table thead th .field-tip-panel { max-width: 260px; }
|
2026-06-01 16:15:15 +09:00
|
|
|
|
.supply-plan-table tbody td { padding: 0.25rem 0.35rem; }
|
|
|
|
|
|
|
|
|
|
|
|
@media screen {
|
|
|
|
|
|
.supply-plan-print { overflow-x: auto; }
|
|
|
|
|
|
.supply-plan-table { min-width: 960px; }
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
@media print {
|
|
|
|
|
|
@page {
|
|
|
|
|
|
size: A4 portrait;
|
|
|
|
|
|
margin: 10mm 8mm;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.no-print { display: none !important; }
|
|
|
|
|
|
|
|
|
|
|
|
.supply-plan-print-sheet {
|
|
|
|
|
|
width: 100% !important;
|
|
|
|
|
|
max-width: 100% !important;
|
|
|
|
|
|
box-sizing: border-box;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.supply-plan-print {
|
|
|
|
|
|
border: none !important;
|
|
|
|
|
|
margin: 0 !important;
|
|
|
|
|
|
padding: 0 !important;
|
|
|
|
|
|
overflow: hidden !important;
|
|
|
|
|
|
width: 100% !important;
|
|
|
|
|
|
max-width: 100% !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.supply-plan-table.data-table {
|
|
|
|
|
|
min-width: 0 !important;
|
|
|
|
|
|
width: 100% !important;
|
|
|
|
|
|
max-width: 100% !important;
|
|
|
|
|
|
table-layout: fixed !important;
|
|
|
|
|
|
font-size: 6px !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.supply-plan-table.data-table th,
|
|
|
|
|
|
.supply-plan-table.data-table td {
|
|
|
|
|
|
white-space: normal !important;
|
|
|
|
|
|
word-break: keep-all;
|
|
|
|
|
|
overflow-wrap: anywhere;
|
|
|
|
|
|
padding: 1px 1px !important;
|
|
|
|
|
|
line-height: 1.1;
|
|
|
|
|
|
vertical-align: middle;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.supply-plan-table .sp-group-h {
|
|
|
|
|
|
font-size: 5px !important;
|
|
|
|
|
|
padding: 1px !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* 세로 A4: 날짜 2×4.5% + 품목 11% + 수치 8×10% = 100% */
|
|
|
|
|
|
.supply-plan-table .sp-col-date {
|
|
|
|
|
|
width: 4.5%;
|
|
|
|
|
|
font-size: 5px !important;
|
|
|
|
|
|
text-align: center;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.supply-plan-table .sp-col-name {
|
|
|
|
|
|
width: 11%;
|
|
|
|
|
|
text-align: left !important;
|
|
|
|
|
|
font-size: 5px !important;
|
|
|
|
|
|
line-height: 1.2;
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
.supply-plan-table .sp-col-num {
|
|
|
|
|
|
width: 10%;
|
|
|
|
|
|
font-size: 5px !important;
|
|
|
|
|
|
text-align: right !important;
|
|
|
|
|
|
}
|
|
|
|
|
|
}
|
|
|
|
|
|
</style>
|