사이트·관리자 봉투 물류 기능(수불·통계·레포트·재고·발주)과 DB·메뉴·E2E를 운영 반영한다.
통계 분석(전년대비·월별·계절별), 수급계획·LOT 수불, 지정판매소·실사·메뉴 링크 등을 포함한다. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
322
app/Views/admin/sales_report/hometax_process.php
Normal file
322
app/Views/admin/sales_report/hometax_process.php
Normal file
@@ -0,0 +1,322 @@
|
||||
<?php
|
||||
declare(strict_types=1);
|
||||
|
||||
/** @var string $startDate */
|
||||
/** @var string $endDate */
|
||||
/** @var string $writeDate */
|
||||
/** @var bool $searched */
|
||||
/** @var list<string> $headers */
|
||||
/** @var list<list<string>> $displayRows */
|
||||
/** @var int $totalCount */
|
||||
/** @var float $totalSupplyAmount */
|
||||
/** @var float $totalTaxAmount */
|
||||
/** @var int $missingBizCount */
|
||||
/** @var string $lgName */
|
||||
/** @var list<string> $printExtraLines */
|
||||
/** @var list<array{label: string, sheet_name: string, cols: list<int>}> $hometaxPrintPages */
|
||||
/** @var list<int> $hometaxColMinPx */
|
||||
|
||||
helper('admin');
|
||||
|
||||
$baseParams = [
|
||||
'start_date' => $startDate ?? '',
|
||||
'end_date' => $endDate ?? '',
|
||||
'write_date' => $writeDate ?? '',
|
||||
];
|
||||
$searchParams = array_merge($baseParams, ['search' => '1']);
|
||||
$exportParams = array_merge($searchParams, ['export' => '1']);
|
||||
|
||||
$searchUrl = mgmt_url('reports/hometax-export?' . http_build_query($searchParams));
|
||||
$excelUrl = mgmt_url('reports/hometax-export?' . http_build_query($exportParams));
|
||||
|
||||
$totalGrand = (float) ($totalSupplyAmount ?? 0) + (float) ($totalTaxAmount ?? 0);
|
||||
$colCount = max(1, count($headers ?? []));
|
||||
|
||||
/** 홈택스 28열 — 주소·상호·이메일 등 텍스트 열을 넓게 (합계 100%) */
|
||||
$hometaxColWidths = [
|
||||
'4.5%', '4%', '4%', '6%', '3%', '6.5%', '3.5%', '11%', '3%', '3%', '5.5%',
|
||||
'6%', '3%', '6.5%', '3.5%', '11%', '3%', '3%', '5.5%',
|
||||
'4%', '4%', '3%', '5.5%', '3%', '3%', '3.5%', '3.5%', '3.5%',
|
||||
];
|
||||
$hometaxColMinPx = $hometaxColMinPx ?? [];
|
||||
$hometaxPrintPages = $hometaxPrintPages ?? [];
|
||||
|
||||
$hometaxWrapColIdx = [7, 15, 5, 6, 13, 14, 10, 18, 22, 27];
|
||||
$hometaxNumColIdx = [19, 20, 24, 25, 26, 27];
|
||||
|
||||
$hometaxNormalizeColWidths = static function (array $colIndices) use ($hometaxColWidths): array {
|
||||
$sum = 0.0;
|
||||
foreach ($colIndices as $ci) {
|
||||
$sum += (float) str_replace('%', '', (string) ($hometaxColWidths[$ci] ?? '3'));
|
||||
}
|
||||
$normalized = [];
|
||||
foreach ($colIndices as $ci) {
|
||||
$pct = (float) str_replace('%', '', (string) ($hometaxColWidths[$ci] ?? '3'));
|
||||
$normalized[$ci] = ($sum > 0 ? round($pct / $sum * 100, 2) : round(100 / max(1, count($colIndices)), 2)) . '%';
|
||||
}
|
||||
|
||||
return $normalized;
|
||||
};
|
||||
|
||||
$hometaxCellClass = static function (int $ci) use ($hometaxWrapColIdx, $hometaxNumColIdx): string {
|
||||
$class = 'text-left px-1 py-1';
|
||||
if (in_array($ci, $hometaxWrapColIdx, true)) {
|
||||
$class .= ' ht-wrap';
|
||||
}
|
||||
if (in_array($ci, $hometaxNumColIdx, true)) {
|
||||
$class .= ' ht-num';
|
||||
}
|
||||
|
||||
return $class;
|
||||
};
|
||||
|
||||
/**
|
||||
* @param list<int> $colIndices
|
||||
*/
|
||||
$hometaxRenderTable = static function (
|
||||
array $colIndices,
|
||||
string $tableExtraClass,
|
||||
string $tableId,
|
||||
bool $forPrint
|
||||
) use (
|
||||
$headers,
|
||||
$displayRows,
|
||||
$searched,
|
||||
$colCount,
|
||||
$hometaxColWidths,
|
||||
$hometaxColMinPx,
|
||||
$hometaxCellClass,
|
||||
$hometaxNormalizeColWidths
|
||||
): void {
|
||||
$sliceCount = count($colIndices);
|
||||
$widthsForSet = $hometaxNormalizeColWidths($colIndices);
|
||||
?>
|
||||
<table
|
||||
class="w-full data-table text-xs <?= esc($tableExtraClass, 'attr') ?>"
|
||||
id="<?= esc($tableId, 'attr') ?>"
|
||||
<?= $forPrint ? 'data-hometax-print="1"' : '' ?>
|
||||
>
|
||||
<colgroup>
|
||||
<?php foreach ($colIndices as $ci):
|
||||
$wPct = $widthsForSet[$ci] ?? (string) round(100 / max(1, $sliceCount), 2) . '%';
|
||||
$wPx = (int) ($hometaxColMinPx[$ci] ?? 56);
|
||||
?>
|
||||
<col style="width: <?= esc($wPct, 'attr') ?>;<?= $forPrint ? '' : ' min-width: ' . $wPx . 'px' ?>"/>
|
||||
<?php endforeach; ?>
|
||||
</colgroup>
|
||||
<thead>
|
||||
<tr>
|
||||
<?php foreach ($colIndices as $ci): ?>
|
||||
<th class="<?= esc($hometaxCellClass($ci), 'attr') ?>"><?= esc((string) ($headers[$ci] ?? '')) ?></th>
|
||||
<?php endforeach; ?>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody class="text-right">
|
||||
<?php if (! ($searched ?? true)): ?>
|
||||
<tr>
|
||||
<td colspan="<?= (int) $sliceCount ?>" class="text-center text-gray-500 py-8">조회를 건너뛴 상태입니다. <strong>조회</strong>를 눌러 주세요.</td>
|
||||
</tr>
|
||||
<?php elseif (($displayRows ?? []) === []): ?>
|
||||
<tr>
|
||||
<td colspan="<?= (int) $sliceCount ?>" class="text-center text-gray-500 py-8">조회된 판매 내역이 없습니다.</td>
|
||||
</tr>
|
||||
<?php else: ?>
|
||||
<?php foreach ($displayRows as $row): ?>
|
||||
<tr>
|
||||
<?php foreach ($colIndices as $ci):
|
||||
$tdClass = 'tabular-nums text-left px-1 py-0.5 border-t border-gray-100 ' . $hometaxCellClass($ci);
|
||||
?>
|
||||
<td class="<?= esc(trim($tdClass), 'attr') ?>"><?= esc((string) ($row[$ci] ?? '')) ?></td>
|
||||
<?php endforeach; ?>
|
||||
</tr>
|
||||
<?php endforeach; ?>
|
||||
<?php endif; ?>
|
||||
</tbody>
|
||||
</table>
|
||||
<?php
|
||||
};
|
||||
?>
|
||||
<?= view('components/print_header', [
|
||||
'printTitle' => '홈택스 처리',
|
||||
'printExtraLines' => $printExtraLines ?? [],
|
||||
]) ?>
|
||||
|
||||
<section class="border-b border-gray-300 p-3 shrink-0 bg-control-panel no-print">
|
||||
<div class="flex flex-wrap items-center justify-between gap-2 mb-2">
|
||||
<h1 class="text-base font-bold text-gray-800">홈택스 처리</h1>
|
||||
<div class="flex flex-wrap gap-2 items-center">
|
||||
<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 transition">인쇄</button>
|
||||
<a href="<?= esc($excelUrl, 'attr') ?>" class="inline-flex items-center border border-green-600 text-green-700 px-3 py-1 rounded-sm text-sm hover:bg-green-50 transition">엑셀저장</a>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<form method="get" action="<?= esc(mgmt_url('reports/hometax-export'), 'attr') ?>" id="hometax-process-form" class="flex flex-wrap items-end gap-3 text-sm">
|
||||
<input type="hidden" name="search" value="1"/>
|
||||
<div>
|
||||
<label class="block text-gray-600 mb-0.5">판매일자</label>
|
||||
<div class="flex items-center gap-1">
|
||||
<input type="date" name="start_date" value="<?= esc($startDate ?? '') ?>" class="border border-gray-300 rounded px-2 py-1 text-sm"/>
|
||||
<span class="text-gray-500">~</span>
|
||||
<input type="date" name="end_date" value="<?= esc($endDate ?? '') ?>" class="border border-gray-300 rounded px-2 py-1 text-sm"/>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<label class="block text-gray-600 mb-0.5">작성일자</label>
|
||||
<input type="date" name="write_date" value="<?= esc($writeDate ?? '') ?>" class="border border-gray-300 rounded px-2 py-1 text-sm"/>
|
||||
</div>
|
||||
<div class="pt-5">
|
||||
<button type="submit" class="border border-blue-600 bg-blue-50 text-blue-800 px-4 py-1 rounded-sm text-sm font-medium hover:bg-blue-100 transition">조회</button>
|
||||
</div>
|
||||
</form>
|
||||
</section>
|
||||
|
||||
<section class="p-3 bg-white border-b border-gray-200 hometax-report-section">
|
||||
<style>
|
||||
.hometax-print-only { display: none; }
|
||||
@media print {
|
||||
@page {
|
||||
size: A4 landscape;
|
||||
margin: 4mm 5mm;
|
||||
}
|
||||
.hometax-report-section {
|
||||
padding: 0 !important;
|
||||
border: none !important;
|
||||
}
|
||||
.hometax-screen-only {
|
||||
display: none !important;
|
||||
}
|
||||
.hometax-print-only {
|
||||
display: block !important;
|
||||
}
|
||||
.hometax-print-page {
|
||||
page-break-after: always;
|
||||
break-after: page;
|
||||
}
|
||||
.hometax-print-page:last-child {
|
||||
page-break-after: auto;
|
||||
break-after: auto;
|
||||
}
|
||||
.hometax-print-page-label {
|
||||
font-size: 8pt;
|
||||
font-weight: 700;
|
||||
margin: 0 0 4px;
|
||||
}
|
||||
.hometax-print-scroll {
|
||||
overflow: visible !important;
|
||||
border: 1px solid #333 !important;
|
||||
}
|
||||
.hometax-print-table {
|
||||
font-size: 8pt !important;
|
||||
width: 100% !important;
|
||||
table-layout: fixed !important;
|
||||
}
|
||||
.hometax-print-table th,
|
||||
.hometax-print-table td {
|
||||
padding: 3px 5px !important;
|
||||
white-space: normal !important;
|
||||
word-break: break-word;
|
||||
overflow-wrap: break-word;
|
||||
line-height: 1.3;
|
||||
vertical-align: top;
|
||||
}
|
||||
.hometax-print-table th {
|
||||
font-size: 7.5pt !important;
|
||||
font-weight: 600;
|
||||
}
|
||||
.hometax-print-table .ht-num {
|
||||
white-space: nowrap !important;
|
||||
word-break: normal !important;
|
||||
}
|
||||
.hometax-print-table thead {
|
||||
display: table-header-group;
|
||||
}
|
||||
.hometax-print-table tr {
|
||||
page-break-inside: avoid;
|
||||
break-inside: avoid;
|
||||
}
|
||||
}
|
||||
@media screen {
|
||||
#hometax-result-table {
|
||||
width: max(100%, 4200px);
|
||||
min-width: 4200px;
|
||||
table-layout: fixed;
|
||||
}
|
||||
#hometax-result-table th,
|
||||
#hometax-result-table td {
|
||||
white-space: nowrap;
|
||||
padding: 4px 6px !important;
|
||||
}
|
||||
#hometax-result-table .ht-wrap {
|
||||
white-space: normal;
|
||||
word-break: break-word;
|
||||
max-width: 220px;
|
||||
}
|
||||
}
|
||||
</style>
|
||||
<div class="text-sm font-semibold text-gray-700 mb-2 no-print">조회결과</div>
|
||||
<div class="hometax-screen-only hometax-scroll-wrap overflow-x-auto border border-gray-300" style="max-width: 100%;">
|
||||
<?php
|
||||
$hometaxRenderTable(
|
||||
range(0, max(0, $colCount - 1)),
|
||||
'',
|
||||
'hometax-result-table',
|
||||
false
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
|
||||
<div class="hometax-print-only" aria-hidden="true">
|
||||
<?php foreach ($hometaxPrintPages as $ppi => $page):
|
||||
$pageCols = $page['cols'];
|
||||
if ($pageCols === []) {
|
||||
continue;
|
||||
}
|
||||
?>
|
||||
<section class="hometax-print-page">
|
||||
<p class="hometax-print-page-label"><?= esc((string) ($page['label'] ?? '')) ?></p>
|
||||
<div class="hometax-print-scroll">
|
||||
<?php
|
||||
$hometaxRenderTable(
|
||||
$pageCols,
|
||||
'hometax-print-table',
|
||||
'hometax-print-table-' . (int) $ppi,
|
||||
true
|
||||
);
|
||||
?>
|
||||
</div>
|
||||
</section>
|
||||
<?php endforeach; ?>
|
||||
</div>
|
||||
|
||||
<div class="mt-4 flex flex-wrap gap-6 text-sm border-t border-gray-200 pt-3 no-print">
|
||||
<div><span class="text-gray-600">총 건수</span> <strong class="tabular-nums"><?= (int) ($totalCount ?? 0) ?></strong> 건</div>
|
||||
<div><span class="text-gray-600">총 금액</span> <strong class="tabular-nums"><?= esc(number_format((int) round($totalGrand))) ?></strong> 원 <span class="text-gray-400 text-xs">(공급가액+세액)</span></div>
|
||||
<div><span class="text-gray-600">사업자등록번호 없음</span> <strong class="tabular-nums text-amber-800"><?= (int) ($missingBizCount ?? 0) ?></strong> 건</div>
|
||||
</div>
|
||||
|
||||
<div class="mt-2 text-xs text-gray-500 no-print print:hidden">
|
||||
인쇄·엑셀저장은 동일하게 2쪽 열 구성입니다(1쪽: 공급자·공급받는자, 2쪽: 금액·품목). 요약·결재란은 인쇄용 헤더에 포함됩니다.
|
||||
</div>
|
||||
</section>
|
||||
|
||||
<style media="print">
|
||||
.no-print { display: none !important; }
|
||||
</style>
|
||||
|
||||
<script>
|
||||
(function () {
|
||||
let savedTitle = document.title;
|
||||
function stamp() {
|
||||
const d = new Date();
|
||||
const p = (n) => String(n).padStart(2, '0');
|
||||
return d.getFullYear() + p(d.getMonth() + 1) + p(d.getDate()) + '_' + p(d.getHours()) + p(d.getMinutes()) + p(d.getSeconds());
|
||||
}
|
||||
window.addEventListener('beforeprint', function () {
|
||||
savedTitle = document.title;
|
||||
document.title = '홈택스처리_' + stamp();
|
||||
});
|
||||
window.addEventListener('afterprint', function () {
|
||||
document.title = savedTitle;
|
||||
});
|
||||
})();
|
||||
</script>
|
||||
Reference in New Issue
Block a user