feat: 판매대장 크기 필터를 봉투/음식물/폐기물 카테고리별 그룹으로

- 크기 드롭다운을 카테고리별 optgroup(봉투(일반용)/음식물/폐기물 등)으로 묶음
- 선택값을 '카테고리|크기'(예: general|3L)로 바꿔 카테고리+크기 조합 필터링
- 엑셀저장에도 size 파라미터 반영(기존 누락 수정)

Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
taekyoungc
2026-06-25 14:41:55 +09:00
parent d366661b4b
commit bdeef2c69d
2 changed files with 58 additions and 15 deletions

View File

@@ -87,25 +87,60 @@ class SalesReport extends BaseController
} }
return ''; return '';
}; };
// 현재(카테고리 필터까지 적용된) 결과에서 선택 가능한 크기 목록 구성 // 봉투(일반용)/음식물/폐기물 등 카테고리별로 선택 가능한 크기 목록 구성한다.
$sizeOptions = []; // (카테고리 필터까지 적용된 현재 결과 기준)
$sizeCatLabels = [
'general' => '봉투(일반용)',
'food' => '음식물',
'waste' => '폐기물',
'sticker' => '스티커',
'reuse' => '재사용',
'apt' => '공동주택용',
'public_use' => '공공용',
'container' => '용기',
];
$sizeCatOrder = ['general', 'food', 'waste', 'sticker', 'reuse', 'apt', 'public_use', 'container'];
$sizeByCat = []; // catKey => [size => true]
foreach ($filtered as $row) { foreach ($filtered as $row) {
$sz = $sizeOf((string) ($row->bs_bag_name ?? '')); $sz = $sizeOf((string) ($row->bs_bag_name ?? ''));
if ($sz !== '') { if ($sz === '') {
$sizeOptions[$sz] = true; continue;
} }
$ck = $this->classifyLedgerProductCategory(
(string) ($row->bs_bag_name ?? ''),
(string) ($row->bs_bag_code ?? '')
);
$sizeByCat[$ck][$sz] = true;
} }
$sizeOptions = array_keys($sizeOptions); $sizeGroups = [];
usort($sizeOptions, static function (string $a, string $b): int { foreach ($sizeCatOrder as $ck) {
$na = (int) preg_replace('/\D/', '', $a); if (empty($sizeByCat[$ck])) {
$nb = (int) preg_replace('/\D/', '', $b); continue;
return $na <=> $nb; }
$sizes = array_keys($sizeByCat[$ck]);
usort($sizes, static function (string $a, string $b): int {
return (int) preg_replace('/\D/', '', $a) <=> (int) preg_replace('/\D/', '', $b);
}); });
$sizeGroups[] = ['key' => $ck, 'label' => $sizeCatLabels[$ck] ?? $ck, 'sizes' => $sizes];
}
// 선택값은 "카테고리|크기" 형식(예: general|10L). 구버전(크기만) 값도 호환.
$size = trim((string) ($this->request->getGet('size') ?? '')); $size = trim((string) ($this->request->getGet('size') ?? ''));
if ($size !== '') { if ($size !== '') {
if (strpos($size, '|') !== false) {
[$selCat, $selSize] = array_pad(explode('|', $size, 2), 2, '');
$filtered = array_values(array_filter($filtered, function ($row) use ($sizeOf, $selCat, $selSize): bool {
$ck = $this->classifyLedgerProductCategory(
(string) ($row->bs_bag_name ?? ''),
(string) ($row->bs_bag_code ?? '')
);
return $ck === $selCat && $sizeOf((string) ($row->bs_bag_name ?? '')) === $selSize;
}));
} else {
$filtered = array_values(array_filter($filtered, static fn ($row): bool => $sizeOf((string) ($row->bs_bag_name ?? '')) === $size)); $filtered = array_values(array_filter($filtered, static fn ($row): bool => $sizeOf((string) ($row->bs_bag_name ?? '')) === $size));
} }
}
if ($mode === 'daily') { if ($mode === 'daily') {
$built = $this->buildDailyLedgerPresentation($filtered, $hasBsFee); $built = $this->buildDailyLedgerPresentation($filtered, $hasBsFee);
@@ -199,7 +234,7 @@ class SalesReport extends BaseController
'dsIdx' => $dsIdx, 'dsIdx' => $dsIdx,
'saIdx' => $saIdx, 'saIdx' => $saIdx,
'cats' => $cats, 'cats' => $cats,
'sizeOptions' => $sizeOptions, 'sizeGroups' => $sizeGroups,
'size' => $size, 'size' => $size,
'shops' => $shops, 'shops' => $shops,
'agencies' => $agencies, 'agencies' => $agencies,

View File

@@ -41,6 +41,9 @@ $exportParams = [
if ($cats !== []) { if ($cats !== []) {
$exportParams['cat'] = $cats; $exportParams['cat'] = $cats;
} }
if (($size ?? '') !== '') {
$exportParams['size'] = $size;
}
$excelUrl = mgmt_url('reports/sales-ledger?' . http_build_query($exportParams)); $excelUrl = mgmt_url('reports/sales-ledger?' . http_build_query($exportParams));
?> ?>
<?= view('components/print_header', [ <?= view('components/print_header', [
@@ -117,10 +120,15 @@ $excelUrl = mgmt_url('reports/sales-ledger?' . http_build_query($exportParams));
<?php endforeach; ?> <?php endforeach; ?>
<span class="inline-flex items-center gap-1 ml-2 pl-3 border-l border-gray-200"> <span class="inline-flex items-center gap-1 ml-2 pl-3 border-l border-gray-200">
<span class="text-xs text-gray-600">크기</span> <span class="text-xs text-gray-600">크기</span>
<select name="size" class="border border-gray-300 rounded px-2 py-1 text-sm"> <select name="size" class="border border-gray-300 rounded px-2 py-1 text-sm min-w-[10rem]">
<option value="">전체</option> <option value="">전체</option>
<?php foreach (($sizeOptions ?? []) as $sz): ?> <?php foreach (($sizeGroups ?? []) as $g): ?>
<option value="<?= esc($sz, 'attr') ?>" <?= ($size ?? '') === $sz ? 'selected' : '' ?>><?= esc($sz) ?></option> <optgroup label="<?= esc($g['label'], 'attr') ?>">
<?php foreach (($g['sizes'] ?? []) as $sz): ?>
<?php $val = $g['key'] . '|' . $sz; ?>
<option value="<?= esc($val, 'attr') ?>" <?= ($size ?? '') === $val ? 'selected' : '' ?>><?= esc($sz) ?></option>
<?php endforeach; ?>
</optgroup>
<?php endforeach; ?> <?php endforeach; ?>
</select> </select>
</span> </span>