발주 변경·입고 화면을 사이트 흐름에 맞게 반영한다.
발주 등록/변경 및 스캐너·일괄·입고현황 화면의 라우팅과 화면 구성을 운영과 동일한 최신 형태로 정리한다. Made-with: Cursor
This commit is contained in:
@@ -42,10 +42,20 @@ $routes->get('bag/issue/create', 'Bag::issueCreate');
|
|||||||
$routes->post('bag/issue/store', 'Bag::issueStore');
|
$routes->post('bag/issue/store', 'Bag::issueStore');
|
||||||
$routes->post('bag/issue/cancel/(:num)', 'Bag::issueCancel/$1');
|
$routes->post('bag/issue/cancel/(:num)', 'Bag::issueCancel/$1');
|
||||||
$routes->get('bag/order/create', 'Bag::orderCreate');
|
$routes->get('bag/order/create', 'Bag::orderCreate');
|
||||||
|
$routes->get('bag/order/change', 'Bag::orderChange');
|
||||||
|
$routes->get('bag/order/revise/(:num)', 'Bag::orderRevise/$1');
|
||||||
$routes->post('bag/order/store', 'Bag::orderStore');
|
$routes->post('bag/order/store', 'Bag::orderStore');
|
||||||
$routes->post('bag/order/cancel/(:num)', 'Bag::orderCancel/$1');
|
$routes->post('bag/order/cancel/(:num)', 'Bag::orderCancel/$1');
|
||||||
|
$routes->post('bag/order/delete', 'Bag::orderDeletePost');
|
||||||
|
$routes->post('bag/order/delete/(:num)', 'Bag::orderDelete/$1');
|
||||||
$routes->get('bag/receiving/create', 'Bag::receivingCreate');
|
$routes->get('bag/receiving/create', 'Bag::receivingCreate');
|
||||||
$routes->post('bag/receiving/store', 'Bag::receivingStore');
|
$routes->post('bag/receiving/store', 'Bag::receivingStore');
|
||||||
|
$routes->get('bag/receiving/scanner', 'Bag::receivingScanner');
|
||||||
|
$routes->post('bag/receiving/scanner/store', 'Bag::receivingScannerStore');
|
||||||
|
$routes->get('bag/receiving/batch', 'Bag::receivingBatch');
|
||||||
|
$routes->post('bag/receiving/batch/store', 'Bag::receivingBatchStore');
|
||||||
|
$routes->get('bag/receiving/status', 'Bag::receivingStatus');
|
||||||
|
$routes->get('bag/receiving/status/export', 'Bag::receivingStatusExport');
|
||||||
$routes->get('bag/sale/create', 'Bag::saleCreate');
|
$routes->get('bag/sale/create', 'Bag::saleCreate');
|
||||||
$routes->post('bag/sale/store', 'Bag::saleStore');
|
$routes->post('bag/sale/store', 'Bag::saleStore');
|
||||||
$routes->get('bag/shop-order/create', 'Bag::shopOrderCreate');
|
$routes->get('bag/shop-order/create', 'Bag::shopOrderCreate');
|
||||||
@@ -108,6 +118,7 @@ $routes->group('bag', ['filter' => 'adminAuth'], static function ($routes): void
|
|||||||
$routes->get('bag-orders/export', 'Admin\BagOrder::export');
|
$routes->get('bag-orders/export', 'Admin\BagOrder::export');
|
||||||
$routes->get('bag-orders', 'Admin\BagOrder::index');
|
$routes->get('bag-orders', 'Admin\BagOrder::index');
|
||||||
$routes->get('bag-orders/create', 'Admin\BagOrder::create');
|
$routes->get('bag-orders/create', 'Admin\BagOrder::create');
|
||||||
|
$routes->get('bag-orders/revise/(:num)', 'Admin\BagOrder::revise/$1');
|
||||||
$routes->post('bag-orders/store', 'Admin\BagOrder::store');
|
$routes->post('bag-orders/store', 'Admin\BagOrder::store');
|
||||||
$routes->get('bag-orders/detail/(:num)', 'Admin\BagOrder::detail/$1');
|
$routes->get('bag-orders/detail/(:num)', 'Admin\BagOrder::detail/$1');
|
||||||
$routes->post('bag-orders/cancel/(:num)', 'Admin\BagOrder::cancel/$1');
|
$routes->post('bag-orders/cancel/(:num)', 'Admin\BagOrder::cancel/$1');
|
||||||
|
|||||||
@@ -50,7 +50,7 @@ class BagReceiving extends BaseController
|
|||||||
return redirect()->to(mgmt_url('bag-receivings'))->with('error', '지자체를 선택해 주세요.');
|
return redirect()->to(mgmt_url('bag-receivings'))->with('error', '지자체를 선택해 주세요.');
|
||||||
}
|
}
|
||||||
|
|
||||||
$orders = model(BagOrderModel::class)->where('bo_lg_idx', $lgIdx)->where('bo_status', 'normal')->orderBy('bo_order_date', 'DESC')->findAll();
|
$orders = model(BagOrderModel::class)->where('bo_lg_idx', $lgIdx)->whereLatestHead($lgIdx)->where('bo_status', 'normal')->orderBy('bo_order_date', 'DESC')->findAll();
|
||||||
|
|
||||||
return $this->renderWorkPage('입고 처리', 'admin/bag_receiving/create', compact('orders'));
|
return $this->renderWorkPage('입고 처리', 'admin/bag_receiving/create', compact('orders'));
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,83 +1,443 @@
|
|||||||
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel">
|
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel">
|
||||||
<span class="text-sm font-bold text-gray-700">발주 등록</span>
|
<span class="text-sm font-bold text-gray-700">발주 등록</span>
|
||||||
</section>
|
</section>
|
||||||
<div class="border border-gray-300 p-4 mt-2 bg-white max-w-4xl">
|
|
||||||
<form action="<?= mgmt_url('bag-orders/store') ?>" method="POST" class="space-y-4">
|
<?php
|
||||||
|
$oldBagCodes = old('item_bag_code');
|
||||||
|
$oldQtyBoxes = old('item_qty_box');
|
||||||
|
$oldQtySheets = old('item_qty_sheet');
|
||||||
|
$oldBagCodes = is_array($oldBagCodes) ? $oldBagCodes : [];
|
||||||
|
$oldQtyBoxes = is_array($oldQtyBoxes) ? $oldQtyBoxes : [];
|
||||||
|
$oldQtySheets = is_array($oldQtySheets) ? $oldQtySheets : [];
|
||||||
|
$defaultOrderDate = old('bo_order_date', date('Y-m-d'));
|
||||||
|
$defaultOrderMonth = old('bo_order_month_ui', substr($defaultOrderDate, 0, 7));
|
||||||
|
|
||||||
|
$bagMeta = [];
|
||||||
|
foreach (($bagReferenceRows ?? []) as $row) {
|
||||||
|
$bagMeta[$row['code']] = [
|
||||||
|
'name' => $row['name'],
|
||||||
|
'orderPrice' => (float) $row['orderPrice'],
|
||||||
|
'boxPerPack' => (int) $row['boxPerPack'],
|
||||||
|
'packPerSheet' => (int) $row['packPerSheet'],
|
||||||
|
'totalPerBox' => max(1, (int) $row['totalPerBox']),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$initialSelectedItems = [];
|
||||||
|
$maxOldCount = max(count($oldBagCodes), count($oldQtySheets), count($oldQtyBoxes));
|
||||||
|
for ($i = 0; $i < $maxOldCount; $i++) {
|
||||||
|
$code = trim((string) ($oldBagCodes[$i] ?? ''));
|
||||||
|
if ($code === '' || ! isset($bagMeta[$code])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$fallbackQtyBox = (int) ($oldQtyBoxes[$i] ?? 0);
|
||||||
|
$rawQtySheet = (int) ($oldQtySheets[$i] ?? 0);
|
||||||
|
$fallbackTotalPerBox = (int) ($bagMeta[$code]['totalPerBox'] ?? 1);
|
||||||
|
if ($fallbackQtyBox <= 0 && $rawQtySheet > 0) {
|
||||||
|
$fallbackQtyBox = intdiv($rawQtySheet, max(1, $fallbackTotalPerBox));
|
||||||
|
}
|
||||||
|
$initialSelectedItems[] = [
|
||||||
|
'code' => $code,
|
||||||
|
'qtyBox' => max(0, $fallbackQtyBox),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$statusMap = ['normal' => '정상', 'cancelled' => '취소', 'deleted' => '삭제'];
|
||||||
|
?>
|
||||||
|
|
||||||
|
<form action="<?= mgmt_url('bag-orders/store') ?>" method="POST" class="mt-2 space-y-2">
|
||||||
<?= csrf_field() ?>
|
<?= csrf_field() ?>
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="border border-gray-300 bg-white p-2">
|
||||||
<label class="block text-sm font-bold text-gray-700 w-28">발주일 <span class="text-red-500">*</span></label>
|
<div class="flex flex-wrap items-center gap-4 text-sm">
|
||||||
<input class="border border-gray-300 rounded px-3 py-1.5 text-sm w-44" name="bo_order_date" type="date" value="<?= esc(old('bo_order_date', date('Y-m-d'))) ?>" required/>
|
<div class="flex items-center gap-2">
|
||||||
|
<label for="bo_order_month_ui" class="font-bold text-gray-700">발주월</label>
|
||||||
|
<input id="bo_order_month_ui" name="bo_order_month_ui" type="month" value="<?= esc($defaultOrderMonth) ?>" class="border border-gray-300 rounded px-2 py-1" />
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<label for="bo_order_date" class="font-bold text-gray-700">발주일 <span class="text-red-500">*</span></label>
|
||||||
|
<input id="bo_order_date" name="bo_order_date" type="date" value="<?= esc($defaultOrderDate) ?>" required class="border border-gray-300 rounded px-2 py-1" />
|
||||||
|
</div>
|
||||||
|
<p class="text-blue-600 font-bold">※ 발주수량은 박스단위로 입력해 주세요. (발주일은 미래일도 선택 가능)</p>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<div class="grid grid-cols-1 xl:grid-cols-12 gap-2">
|
||||||
<label class="block text-sm font-bold text-gray-700 w-28">수수료율</label>
|
<section class="xl:col-span-5 border border-gray-300 bg-white">
|
||||||
<input class="border border-gray-300 rounded px-3 py-1.5 text-sm w-32 text-right" name="bo_fee_rate" type="number" step="0.01" value="<?= esc(old('bo_fee_rate', '0')) ?>"/>
|
<div class="border-b border-gray-300 bg-gray-50 px-2 py-1 text-sm font-bold text-gray-700">발주 이력</div>
|
||||||
<span class="text-sm text-gray-500">%</span>
|
<div class="overflow-auto max-h-[410px]">
|
||||||
</div>
|
<table class="w-full data-table text-sm">
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
|
||||||
<label class="block text-sm font-bold text-gray-700 w-28">제작업체</label>
|
|
||||||
<select class="border border-gray-300 rounded px-3 py-1.5 text-sm w-60" name="bo_company_idx">
|
|
||||||
<option value="">선택</option>
|
|
||||||
<?php foreach ($companies as $cp): ?>
|
|
||||||
<option value="<?= esc($cp->cp_idx) ?>" <?= (int) old('bo_company_idx') === (int) $cp->cp_idx ? 'selected' : '' ?>>
|
|
||||||
<?= esc($cp->cp_name) ?>
|
|
||||||
</option>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
|
||||||
<label class="block text-sm font-bold text-gray-700 w-28">입고처</label>
|
|
||||||
<select class="border border-gray-300 rounded px-3 py-1.5 text-sm w-60" name="bo_agency_idx">
|
|
||||||
<option value="">선택</option>
|
|
||||||
<?php foreach ($agencies as $ag): ?>
|
|
||||||
<option value="<?= esc($ag->sa_idx) ?>" <?= (int) old('bo_agency_idx') === (int) $ag->sa_idx ? 'selected' : '' ?>>
|
|
||||||
[<?= esc($ag->sa_kind ?? '') ?>] <?= esc($ag->sa_code ?? '') ?> — <?= esc($ag->sa_name) ?>
|
|
||||||
</option>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-4">
|
|
||||||
<label class="block text-sm font-bold text-gray-700 mb-2">발주 품목</label>
|
|
||||||
<div class="border border-gray-300 overflow-auto">
|
|
||||||
<table class="w-full data-table">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="w-16">순번</th>
|
<th class="w-28">발주일</th>
|
||||||
<th>봉투</th>
|
<th>제작업체</th>
|
||||||
<th class="w-32">박스수</th>
|
<th>입고처</th>
|
||||||
|
<th class="w-16">상태</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php for ($i = 0; $i < 3; $i++): ?>
|
<?php foreach (($recentOrders ?? []) as $history): ?>
|
||||||
<tr>
|
<tr>
|
||||||
<td class="text-center"><?= $i + 1 ?></td>
|
<td class="text-center"><?= esc((string) $history->bo_order_date) ?></td>
|
||||||
<td>
|
<td class="text-left pl-2"><?= esc((string) ($companyMap[(int) $history->bo_company_idx] ?? '-')) ?></td>
|
||||||
<select class="border border-gray-300 rounded px-2 py-1 text-sm w-full" name="item_bag_code[]">
|
<td class="text-left pl-2"><?= esc((string) ($agencyMap[(int) $history->bo_agency_idx] ?? '-')) ?></td>
|
||||||
<option value="">선택</option>
|
<td class="text-center"><?= esc((string) ($statusMap[(string) $history->bo_status] ?? $history->bo_status)) ?></td>
|
||||||
<?php foreach ($bagCodes as $cd): ?>
|
|
||||||
<option value="<?= esc($cd->cd_code) ?>">
|
|
||||||
<?= esc($cd->cd_code) ?> — <?= esc($cd->cd_name) ?>
|
|
||||||
</option>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input class="border border-gray-300 rounded px-2 py-1 text-sm w-full text-right" name="item_qty_box[]" type="number" min="0" value="0"/>
|
|
||||||
</td>
|
|
||||||
</tr>
|
</tr>
|
||||||
<?php endfor; ?>
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($recentOrders)): ?>
|
||||||
|
<tr><td colspan="4" class="text-center text-gray-400 py-4">발주 이력이 없습니다.</td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="xl:col-span-7 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">발주 Form</div>
|
||||||
|
<div class="p-2 space-y-2">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||||
|
<div class="flex items-center gap-2 text-sm">
|
||||||
|
<label for="bo_fee_rate" class="w-20 font-bold text-gray-700">수수료</label>
|
||||||
|
<input id="bo_fee_rate" name="bo_fee_rate" type="number" step="0.01" value="<?= esc(old('bo_fee_rate', '0')) ?>" class="border border-gray-300 rounded px-2 py-1 w-24 text-right" />
|
||||||
|
<span>%</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-sm">
|
||||||
|
<label for="bo_association_idx" class="w-20 font-bold text-gray-700">협회</label>
|
||||||
|
<select id="bo_association_idx" name="bo_association_idx" class="border border-gray-300 rounded px-2 py-1 w-full">
|
||||||
|
<option value="">선택</option>
|
||||||
|
<?php foreach (($associations ?? []) as $association): ?>
|
||||||
|
<option value="<?= esc((string) $association->cp_idx) ?>" <?= (int) old('bo_association_idx') === (int) $association->cp_idx ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) $association->cp_name) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-sm">
|
||||||
|
<label for="bo_company_idx" class="w-20 font-bold text-gray-700">제작업체</label>
|
||||||
|
<select id="bo_company_idx" name="bo_company_idx" class="border border-gray-300 rounded px-2 py-1 w-full">
|
||||||
|
<option value="">선택</option>
|
||||||
|
<?php foreach (($companies ?? []) as $company): ?>
|
||||||
|
<option value="<?= esc((string) $company->cp_idx) ?>" <?= (int) old('bo_company_idx') === (int) $company->cp_idx ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) $company->cp_name) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-sm">
|
||||||
|
<label for="bo_agency_idx" class="w-20 font-bold text-gray-700">입고처</label>
|
||||||
|
<select id="bo_agency_idx" name="bo_agency_idx" class="border border-gray-300 rounded px-2 py-1 w-full">
|
||||||
|
<option value="">선택</option>
|
||||||
|
<?php foreach (($agencies ?? []) as $agency): ?>
|
||||||
|
<option value="<?= esc((string) $agency->sa_idx) ?>" <?= (int) old('bo_agency_idx') === (int) $agency->sa_idx ? 'selected' : '' ?>>
|
||||||
|
[<?= esc((string) ($agency->sa_kind ?? '')) ?>] <?= esc((string) ($agency->sa_code ?? '')) ?> — <?= esc((string) $agency->sa_name) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
<div class="flex gap-2 pt-2">
|
<div class="border border-gray-300 overflow-auto">
|
||||||
<button type="submit" class="bg-btn-search text-white px-6 py-1.5 rounded-sm text-sm shadow hover:opacity-90 transition">등록</button>
|
<table class="w-full data-table text-sm order-input-table" id="order-item-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="w-12">번호</th>
|
||||||
|
<th class="w-16">선택</th>
|
||||||
|
<th>품명</th>
|
||||||
|
<th class="w-28">수량(BOX)</th>
|
||||||
|
<th class="w-24">단가</th>
|
||||||
|
<th class="w-24">환산수량</th>
|
||||||
|
<th class="w-28">금액</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="selected-order-items-body"></tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th colspan="3" class="text-center">계</th>
|
||||||
|
<th class="text-right pr-2" id="sum-box-qty">0</th>
|
||||||
|
<th></th>
|
||||||
|
<th class="text-right pr-2" id="sum-sheet-qty">0</th>
|
||||||
|
<th class="text-right pr-2" id="sum-amount">0</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2 pt-1">
|
||||||
|
<button type="submit" class="bg-btn-search text-white px-6 py-1.5 rounded-sm text-sm shadow hover:opacity-90 transition">발주</button>
|
||||||
<a href="<?= mgmt_url('bag-orders') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
|
<a href="<?= mgmt_url('bag-orders') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
|
||||||
</div>
|
</div>
|
||||||
</form>
|
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section 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>
|
||||||
|
<p class="text-xs text-gray-600 px-2 py-1">아래 목록에서 봉투를 선택하면 발주 품목에 추가됩니다. (개수 제한 없음)</p>
|
||||||
|
<div class="overflow-auto">
|
||||||
|
<table class="w-full data-table text-sm order-reference-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="w-12">번호</th>
|
||||||
|
<th class="w-20">선택</th>
|
||||||
|
<th>봉투 종류</th>
|
||||||
|
<th class="w-24">발주단가</th>
|
||||||
|
<th class="w-24">Box당 팩</th>
|
||||||
|
<th class="w-24">팩당 낱장</th>
|
||||||
|
<th class="w-28">1박스 총 낱장</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach (($bagReferenceRows ?? []) as $idx => $row): ?>
|
||||||
|
<tr data-reference-row data-code="<?= esc((string) $row['code']) ?>" class="cursor-pointer">
|
||||||
|
<td class="text-center"><?= $idx + 1 ?></td>
|
||||||
|
<td class="text-center">
|
||||||
|
<button type="button" class="js-toggle-bag border border-gray-300 rounded px-2 py-0.5 text-xs hover:bg-gray-100" data-code="<?= esc((string) $row['code']) ?>">선택</button>
|
||||||
|
</td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) $row['name']) ?></td>
|
||||||
|
<td class="text-right pr-2"><?= number_format((float) $row['orderPrice'], 2) ?></td>
|
||||||
|
<td class="text-right pr-2"><?= number_format((int) $row['boxPerPack']) ?></td>
|
||||||
|
<td class="text-right pr-2"><?= number_format((int) $row['packPerSheet']) ?></td>
|
||||||
|
<td class="text-right pr-2"><?= number_format((int) $row['totalPerBox']) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($bagReferenceRows)): ?>
|
||||||
|
<tr><td colspan="7" class="text-center text-gray-400 py-4">표시할 봉투 기준 데이터가 없습니다.</td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.order-input-table tbody tr,
|
||||||
|
.order-reference-table tbody tr {
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
.order-input-table tbody td,
|
||||||
|
.order-reference-table tbody td {
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(() => {
|
||||||
|
const bagMeta = <?= json_encode($bagMeta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||||||
|
const initialSelectedItems = <?= json_encode($initialSelectedItems, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||||||
|
const selectedBody = document.getElementById('selected-order-items-body');
|
||||||
|
const referenceRows = Array.from(document.querySelectorAll('[data-reference-row]'));
|
||||||
|
const sumBoxQtyEl = document.getElementById('sum-box-qty');
|
||||||
|
const sumSheetQtyEl = document.getElementById('sum-sheet-qty');
|
||||||
|
const sumAmountEl = document.getElementById('sum-amount');
|
||||||
|
const monthInput = document.getElementById('bo_order_month_ui');
|
||||||
|
const orderDateInput = document.getElementById('bo_order_date');
|
||||||
|
const orderForm = document.querySelector('form[action*="bag-orders/store"]');
|
||||||
|
const selectedItems = new Map();
|
||||||
|
let activeCode = null;
|
||||||
|
|
||||||
|
const formatNumber = (value) => new Intl.NumberFormat('ko-KR').format(Number.isFinite(value) ? value : 0);
|
||||||
|
const escapeHtml = (value) => String(value ?? '')
|
||||||
|
.replaceAll('&', '&')
|
||||||
|
.replaceAll('<', '<')
|
||||||
|
.replaceAll('>', '>')
|
||||||
|
.replaceAll('"', '"')
|
||||||
|
.replaceAll("'", ''');
|
||||||
|
|
||||||
|
const syncMonthFromDate = () => {
|
||||||
|
if (!orderDateInput || !monthInput || !orderDateInput.value) return;
|
||||||
|
monthInput.value = orderDateInput.value.substring(0, 7);
|
||||||
|
};
|
||||||
|
|
||||||
|
const syncDateFromMonth = () => {
|
||||||
|
if (!orderDateInput || !monthInput || !monthInput.value) return;
|
||||||
|
const parts = monthInput.value.split('-');
|
||||||
|
if (parts.length !== 2) return;
|
||||||
|
const year = Number(parts[0]);
|
||||||
|
const month = Number(parts[1]);
|
||||||
|
if (!Number.isFinite(year) || !Number.isFinite(month)) return;
|
||||||
|
|
||||||
|
const currentDay = orderDateInput.value ? Number(orderDateInput.value.split('-')[2]) : 1;
|
||||||
|
const lastDay = new Date(year, month, 0).getDate();
|
||||||
|
const day = String(Math.min(Math.max(currentDay, 1), lastDay)).padStart(2, '0');
|
||||||
|
orderDateInput.value = `${String(year)}-${String(month).padStart(2, '0')}-${day}`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateReferenceSelectionUi = () => {
|
||||||
|
referenceRows.forEach((row) => {
|
||||||
|
const code = row.dataset.code || '';
|
||||||
|
const button = row.querySelector('.js-toggle-bag');
|
||||||
|
const isSelected = selectedItems.has(code);
|
||||||
|
row.classList.toggle('bg-blue-50', isSelected);
|
||||||
|
if (button) {
|
||||||
|
button.textContent = isSelected ? '선택됨' : '선택';
|
||||||
|
button.classList.toggle('bg-blue-600', isSelected);
|
||||||
|
button.classList.toggle('text-white', isSelected);
|
||||||
|
button.classList.toggle('border-blue-600', isSelected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateTotals = () => {
|
||||||
|
let sumBoxQty = 0;
|
||||||
|
let sumSheetQty = 0;
|
||||||
|
let sumAmount = 0;
|
||||||
|
|
||||||
|
selectedBody.querySelectorAll('tr[data-item-row]').forEach((row) => {
|
||||||
|
const code = row.dataset.code || '';
|
||||||
|
const qtyInput = row.querySelector('.item-qty-box');
|
||||||
|
const qtyBox = Math.max(0, parseInt(qtyInput?.value || '0', 10));
|
||||||
|
const meta = bagMeta[code] || { orderPrice: 0, totalPerBox: 1 };
|
||||||
|
const unitPrice = Number(meta.orderPrice || 0);
|
||||||
|
const totalPerBox = Math.max(1, Number(meta.totalPerBox || 1));
|
||||||
|
const qtySheet = qtyBox * totalPerBox;
|
||||||
|
const amount = qtySheet * unitPrice;
|
||||||
|
|
||||||
|
const unitPriceEl = row.querySelector('.item-unit-price');
|
||||||
|
const qtySheetEl = row.querySelector('.item-qty-sheet');
|
||||||
|
const sheetHelpEl = row.querySelector('.item-sheet-help');
|
||||||
|
const amountEl = row.querySelector('.item-amount');
|
||||||
|
if (unitPriceEl) unitPriceEl.textContent = formatNumber(unitPrice);
|
||||||
|
if (qtySheetEl) qtySheetEl.textContent = formatNumber(qtySheet);
|
||||||
|
if (sheetHelpEl) sheetHelpEl.textContent = `낱장 ${formatNumber(qtySheet)}장`;
|
||||||
|
if (amountEl) amountEl.textContent = formatNumber(amount);
|
||||||
|
|
||||||
|
selectedItems.set(code, { qtyBox });
|
||||||
|
sumBoxQty += qtyBox;
|
||||||
|
sumSheetQty += qtySheet;
|
||||||
|
sumAmount += amount;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sumBoxQtyEl) sumBoxQtyEl.textContent = formatNumber(sumBoxQty);
|
||||||
|
if (sumSheetQtyEl) sumSheetQtyEl.textContent = formatNumber(sumSheetQty);
|
||||||
|
if (sumAmountEl) sumAmountEl.textContent = formatNumber(sumAmount);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setActiveRow = (code) => {
|
||||||
|
activeCode = code || null;
|
||||||
|
selectedBody.querySelectorAll('tr[data-item-row]').forEach((row) => {
|
||||||
|
row.classList.toggle('bg-amber-50', row.dataset.code === activeCode);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderSelectedRows = () => {
|
||||||
|
const codes = Object.keys(bagMeta).filter((code) => selectedItems.has(code));
|
||||||
|
if (codes.length === 0) {
|
||||||
|
selectedBody.innerHTML = '<tr><td colspan="7" class="text-center text-gray-400 py-4">아래 "발주 등록 종류"에서 봉투를 선택해 주세요.</td></tr>';
|
||||||
|
setActiveRow(null);
|
||||||
|
updateTotals();
|
||||||
|
updateReferenceSelectionUi();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedBody.innerHTML = codes.map((code, idx) => {
|
||||||
|
const meta = bagMeta[code];
|
||||||
|
const qtyBox = Math.max(0, parseInt(String(selectedItems.get(code)?.qtyBox ?? 0), 10));
|
||||||
|
const name = meta?.name || code;
|
||||||
|
|
||||||
|
return `
|
||||||
|
<tr data-item-row data-code="${escapeHtml(code)}" class="cursor-pointer">
|
||||||
|
<td class="text-center">${idx + 1}</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<button type="button" class="js-remove-selected text-xs text-red-600 hover:underline" data-code="${escapeHtml(code)}">해제</button>
|
||||||
|
</td>
|
||||||
|
<td class="text-left pl-2">
|
||||||
|
${escapeHtml(name)}
|
||||||
|
<input type="hidden" name="item_bag_code[]" value="${escapeHtml(code)}" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input name="item_qty_box[]" type="number" min="0" step="1" value="${qtyBox}" class="item-qty-box border border-gray-300 rounded px-2 py-1 text-sm w-full text-right leading-tight" />
|
||||||
|
<p class="text-[11px] text-gray-500 mt-1 item-sheet-help">낱장 0장</p>
|
||||||
|
</td>
|
||||||
|
<td class="text-right pr-2 item-unit-price">0</td>
|
||||||
|
<td class="text-right pr-2 item-qty-sheet">0</td>
|
||||||
|
<td class="text-right pr-2 item-amount">0</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
if (!activeCode || !selectedItems.has(activeCode)) {
|
||||||
|
activeCode = codes[0];
|
||||||
|
}
|
||||||
|
setActiveRow(activeCode);
|
||||||
|
updateTotals();
|
||||||
|
updateReferenceSelectionUi();
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleSelection = (code) => {
|
||||||
|
if (!code || !bagMeta[code]) return;
|
||||||
|
if (selectedItems.has(code)) {
|
||||||
|
selectedItems.delete(code);
|
||||||
|
if (activeCode === code) activeCode = null;
|
||||||
|
} else {
|
||||||
|
selectedItems.set(code, { qtyBox: 0 });
|
||||||
|
activeCode = code;
|
||||||
|
}
|
||||||
|
renderSelectedRows();
|
||||||
|
};
|
||||||
|
|
||||||
|
initialSelectedItems.forEach((item) => {
|
||||||
|
if (!item || !item.code || !bagMeta[item.code]) return;
|
||||||
|
selectedItems.set(item.code, { qtyBox: Math.max(0, parseInt(String(item.qtyBox ?? 0), 10)) });
|
||||||
|
activeCode = item.code;
|
||||||
|
});
|
||||||
|
|
||||||
|
selectedBody.addEventListener('click', (event) => {
|
||||||
|
const removeButton = event.target.closest('.js-remove-selected');
|
||||||
|
if (removeButton) {
|
||||||
|
toggleSelection(removeButton.dataset.code || '');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = event.target.closest('tr[data-item-row]');
|
||||||
|
if (!row) return;
|
||||||
|
const code = row.dataset.code || '';
|
||||||
|
setActiveRow(code);
|
||||||
|
const qtyInput = row.querySelector('.item-qty-box');
|
||||||
|
if (qtyInput) qtyInput.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
selectedBody.addEventListener('input', (event) => {
|
||||||
|
const qtyInput = event.target.closest('.item-qty-box');
|
||||||
|
if (!qtyInput) return;
|
||||||
|
const row = qtyInput.closest('tr[data-item-row]');
|
||||||
|
if (!row) return;
|
||||||
|
const code = row.dataset.code || '';
|
||||||
|
selectedItems.set(code, { qtyBox: Math.max(0, parseInt(qtyInput.value || '0', 10)) });
|
||||||
|
updateTotals();
|
||||||
|
});
|
||||||
|
|
||||||
|
referenceRows.forEach((row) => {
|
||||||
|
row.addEventListener('click', (event) => {
|
||||||
|
const button = event.target.closest('.js-toggle-bag');
|
||||||
|
if (button) {
|
||||||
|
toggleSelection(button.dataset.code || '');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.target.closest('td')) {
|
||||||
|
toggleSelection(row.dataset.code || '');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (monthInput) monthInput.addEventListener('change', () => { syncDateFromMonth(); updateTotals(); });
|
||||||
|
if (orderDateInput) orderDateInput.addEventListener('change', syncMonthFromDate);
|
||||||
|
|
||||||
|
if (orderForm) {
|
||||||
|
orderForm.addEventListener('submit', (event) => {
|
||||||
|
const hasValidItem = Array.from(selectedBody.querySelectorAll('tr[data-item-row]')).some((row) => {
|
||||||
|
const qtyInput = row.querySelector('.item-qty-box');
|
||||||
|
return Math.max(0, parseInt(qtyInput?.value || '0', 10)) > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasValidItem) {
|
||||||
|
event.preventDefault();
|
||||||
|
alert('봉투를 선택하고 수량을 1 이상 입력해 주세요.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
syncMonthFromDate();
|
||||||
|
renderSelectedRows();
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
|||||||
@@ -1,81 +1,200 @@
|
|||||||
<?= view('components/print_header', ['printTitle' => '발주 현황']) ?>
|
<?php
|
||||||
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel">
|
// 발주기간: native month 입력은 로케일에 따라 Jan 등 영문 표기될 수 있어 YYYY-MM select + 한글 라벨 사용
|
||||||
|
$bagOrderYmChoices = [];
|
||||||
|
$bagOrderYmCenterY = (int) date('Y');
|
||||||
|
for ($by = $bagOrderYmCenterY - 4; $by <= $bagOrderYmCenterY + 2; $by++) {
|
||||||
|
for ($bm = 1; $bm <= 12; $bm++) {
|
||||||
|
$bagOrderYmChoices[] = sprintf('%04d-%02d', $by, $bm);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
foreach ([(string) ($startMonth ?? ''), (string) ($endMonth ?? '')] as $ymExtra) {
|
||||||
|
if (preg_match('/^\d{4}-\d{2}$/', $ymExtra) && ! in_array($ymExtra, $bagOrderYmChoices, true)) {
|
||||||
|
$bagOrderYmChoices[] = $ymExtra;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sort($bagOrderYmChoices);
|
||||||
|
$bagOrderYmLabel = static function (string $ym): string {
|
||||||
|
if (preg_match('/^(\d{4})-(\d{2})$/', $ym, $m)) {
|
||||||
|
return $m[1] . '년 ' . (int) $m[2] . '월';
|
||||||
|
}
|
||||||
|
|
||||||
|
return $ym;
|
||||||
|
};
|
||||||
|
?>
|
||||||
|
<?= view('components/print_header', ['printTitle' => '봉투 발주 현황', 'printShowApproval' => false]) ?>
|
||||||
|
<section class="no-print border-b border-gray-300 p-2 shrink-0 bg-control-panel">
|
||||||
<div class="flex flex-wrap items-center justify-between gap-y-2">
|
<div class="flex flex-wrap items-center justify-between gap-y-2">
|
||||||
<span class="text-sm font-bold text-gray-700">발주 현황</span>
|
|
||||||
<div class="flex items-center gap-2">
|
<div class="flex items-center gap-2">
|
||||||
<a href="<?= mgmt_url('bag-orders/export') . '?' . http_build_query(array_filter(['start_date' => $startDate ?? '', 'end_date' => $endDate ?? '', 'status' => $status ?? ''])) ?>" class="no-print border border-btn-excel-border text-btn-excel-text px-3 py-1 rounded-sm text-sm hover:bg-green-50 transition">엑셀저장</a>
|
<a href="<?= mgmt_url('bag-orders/export') . '?' . http_build_query(array_filter(['start_month' => $startMonth ?? '', 'end_month' => $endMonth ?? '', 'company_idx' => $companyIdx ?? 0, 'bag_code' => $bagCode ?? '', 'receive_type' => $receiveType ?? ''])) ?>" class="no-print border border-btn-excel-border text-btn-excel-text px-3 py-1 rounded-sm text-sm hover:bg-green-50 transition">엑셀저장</a>
|
||||||
<button onclick="window.print()" class="no-print border border-btn-print-border text-gray-600 px-3 py-1 rounded-sm text-sm hover:bg-gray-50 transition">인쇄</button>
|
<button onclick="window.print()" class="no-print border border-btn-print-border text-gray-600 px-3 py-1 rounded-sm text-sm hover:bg-gray-50 transition">인쇄</button>
|
||||||
<a href="<?= mgmt_url('bag-orders/create') ?>" class="bg-btn-search text-white px-4 py-1.5 rounded-sm flex items-center gap-1 text-sm shadow hover:opacity-90 transition border border-transparent">발주 등록</a>
|
<a href="<?= mgmt_url('bag-orders/create') ?>" class="bg-btn-search text-white px-4 py-1.5 rounded-sm flex items-center gap-1 text-sm shadow hover:opacity-90 transition border border-transparent">발주 등록</a>
|
||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
</section>
|
</section>
|
||||||
<section class="p-2 bg-white border-b border-gray-200">
|
|
||||||
<form method="GET" action="<?= mgmt_url('bag-orders') ?>" class="flex flex-wrap items-center gap-2">
|
<section class="no-print p-2 bg-white border-b border-gray-200">
|
||||||
<label class="text-sm text-gray-600">발주일</label>
|
<!-- GBMS 발주현황: 발주기간은 [시작] ~ [끝] 한 줄 고정, 필터 블록은 가로 나열 후 좁으면 블록 단위로만 줄바꿈 -->
|
||||||
<input type="date" name="start_date" value="<?= esc($startDate ?? '') ?>" class="border border-gray-300 rounded px-2 py-1 text-sm"/>
|
<form method="GET" action="<?= mgmt_url('bag-orders') ?>" class="flex flex-wrap items-end gap-x-5 gap-y-3 w-full">
|
||||||
<label class="text-sm text-gray-600">~</label>
|
<div class="flex flex-nowrap items-center gap-2 shrink-0">
|
||||||
<input type="date" name="end_date" value="<?= esc($endDate ?? '') ?>" class="border border-gray-300 rounded px-2 py-1 text-sm"/>
|
<label class="text-sm text-gray-600 whitespace-nowrap">발주 기간</label>
|
||||||
<label class="text-sm text-gray-600">상태</label>
|
<select name="start_month" class="border border-gray-300 rounded px-2 py-1 text-sm w-[11.5rem] max-w-[13rem] shrink-0">
|
||||||
<select name="status" class="border border-gray-300 rounded px-2 py-1 text-sm">
|
<?php foreach ($bagOrderYmChoices as $ym): ?>
|
||||||
<option value="">전체</option>
|
<option value="<?= esc($ym) ?>" <?= ($startMonth ?? date('Y-m')) === $ym ? 'selected' : '' ?>><?= esc($bagOrderYmLabel($ym)) ?></option>
|
||||||
<option value="normal" <?= ($status ?? '') === 'normal' ? 'selected' : '' ?>>정상</option>
|
<?php endforeach; ?>
|
||||||
<option value="cancelled" <?= ($status ?? '') === 'cancelled' ? 'selected' : '' ?>>취소</option>
|
|
||||||
<option value="deleted" <?= ($status ?? '') === 'deleted' ? 'selected' : '' ?>>삭제</option>
|
|
||||||
</select>
|
</select>
|
||||||
|
<span class="text-sm text-gray-500 select-none">~</span>
|
||||||
|
<select name="end_month" class="border border-gray-300 rounded px-2 py-1 text-sm w-[11.5rem] max-w-[13rem] shrink-0">
|
||||||
|
<?php foreach ($bagOrderYmChoices as $ym): ?>
|
||||||
|
<option value="<?= esc($ym) ?>" <?= ($endMonth ?? date('Y-m')) === $ym ? 'selected' : '' ?>><?= esc($bagOrderYmLabel($ym)) ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-nowrap items-center gap-2 shrink-0">
|
||||||
|
<label class="text-sm text-gray-600 whitespace-nowrap">제작 업체</label>
|
||||||
|
<select name="company_idx" class="border border-gray-300 rounded px-2 py-1 text-sm w-[11rem] max-w-[14rem]">
|
||||||
|
<option value="0">전 체</option>
|
||||||
|
<?php foreach (($companyOptions ?? []) as $company): ?>
|
||||||
|
<option value="<?= (int) $company->cp_idx ?>" <?= (int) ($companyIdx ?? 0) === (int) $company->cp_idx ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) $company->cp_name) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-nowrap items-center gap-2 shrink-0">
|
||||||
|
<label class="text-sm text-gray-600 whitespace-nowrap">품 명</label>
|
||||||
|
<select name="bag_code" class="border border-gray-300 rounded px-2 py-1 text-sm w-[11rem] max-w-[16rem]">
|
||||||
|
<option value="">전 체</option>
|
||||||
|
<?php foreach (($bagCodeOptions ?? []) as $bag): ?>
|
||||||
|
<option value="<?= esc((string) $bag->cd_code) ?>" <?= (string) ($bagCode ?? '') === (string) $bag->cd_code ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) $bag->cd_name) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-nowrap items-center gap-2 shrink-0">
|
||||||
|
<label class="text-sm text-gray-600 whitespace-nowrap">입고 구분</label>
|
||||||
|
<select name="receive_type" class="border border-gray-300 rounded px-2 py-1 text-sm w-[8.5rem]">
|
||||||
|
<option value="all" <?= ($receiveType ?? 'all') === 'all' ? 'selected' : '' ?>>전 체</option>
|
||||||
|
<option value="received" <?= ($receiveType ?? 'all') === 'received' ? 'selected' : '' ?>>입고완료</option>
|
||||||
|
<option value="pending" <?= ($receiveType ?? 'all') === 'pending' ? 'selected' : '' ?>>미입고</option>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex flex-nowrap items-center gap-2 shrink-0 sm:ml-auto">
|
||||||
<button type="submit" class="bg-btn-search text-white px-4 py-1 rounded-sm text-sm">조회</button>
|
<button type="submit" class="bg-btn-search text-white px-4 py-1 rounded-sm text-sm">조회</button>
|
||||||
<a href="<?= mgmt_url('bag-orders') ?>" class="text-sm text-gray-500 hover:underline">초기화</a>
|
<a href="<?= mgmt_url('bag-orders') ?>" class="text-sm text-gray-500 hover:underline whitespace-nowrap">초기화</a>
|
||||||
|
</div>
|
||||||
</form>
|
</form>
|
||||||
</section>
|
</section>
|
||||||
<div class="border border-gray-300 overflow-auto mt-2">
|
|
||||||
<table class="w-full data-table">
|
<div class="bag-order-print-wrap border border-gray-300 overflow-auto mt-2">
|
||||||
|
<table class="bag-order-print-table w-full data-table">
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="w-16">번호</th>
|
<th class="w-32">발주일자</th>
|
||||||
<th>LOT번호</th>
|
<th class="min-w-[10rem]">제작 업체</th>
|
||||||
<th>발주일</th>
|
<th class="min-w-[12rem]">품 명</th>
|
||||||
<th>제작업체</th>
|
<th class="w-28">발주 수량</th>
|
||||||
<th>입고처</th>
|
<th class="w-28">입고 수량</th>
|
||||||
<th>품목수</th>
|
<th class="w-28">미입고수량</th>
|
||||||
<th>총수량</th>
|
<th class="w-32">발주 금액</th>
|
||||||
<th>총금액</th>
|
<th class="min-w-[9rem]">입고처</th>
|
||||||
<th class="w-20">상태</th>
|
<th class="min-w-[8rem]">비 고</th>
|
||||||
<th class="w-44">작업</th>
|
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody class="text-right">
|
<tbody class="text-right">
|
||||||
<?php foreach ($list as $row): ?>
|
<?php $printedGroup = []; ?>
|
||||||
<tr>
|
<?php foreach (($rows ?? []) as $row): ?>
|
||||||
<td class="text-center"><?= esc($row->bo_idx) ?></td>
|
<?php if (! empty($row['is_subtotal'])): ?>
|
||||||
<td class="text-center font-mono"><?= esc($row->bo_lot_no) ?></td>
|
<tr class="bg-gray-50 font-semibold">
|
||||||
<td class="text-center"><?= esc($row->bo_order_date) ?></td>
|
<td colspan="3" class="text-center"><?= esc((string) ($row['label'] ?? '소계')) ?></td>
|
||||||
<td class="text-left pl-2"><?= esc($companyMap[$row->bo_company_idx] ?? '') ?></td>
|
<td><?= number_format((int) ($row['order_qty'] ?? 0)) ?></td>
|
||||||
<td class="text-left pl-2"><?= esc($agencyMap[$row->bo_agency_idx] ?? '') ?></td>
|
<td><?= number_format((int) ($row['received_qty'] ?? 0)) ?></td>
|
||||||
<td><?= number_format((int) ($itemSummary[$row->bo_idx]['count'] ?? 0)) ?></td>
|
<td><?= number_format((int) ($row['pending_qty'] ?? 0)) ?></td>
|
||||||
<td><?= number_format((int) ($itemSummary[$row->bo_idx]['qty'] ?? 0)) ?></td>
|
<td><?= number_format((float) ($row['amount'] ?? 0)) ?></td>
|
||||||
<td><?= number_format((int) ($itemSummary[$row->bo_idx]['amount'] ?? 0)) ?></td>
|
<td></td>
|
||||||
<td class="text-center">
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<?php continue; ?>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
<?php
|
<?php
|
||||||
$statusMap = ['normal' => '정상', 'cancelled' => '취소', 'deleted' => '삭제'];
|
$boIdx = (int) ($row['bo_idx'] ?? 0);
|
||||||
echo esc($statusMap[$row->bo_status] ?? $row->bo_status);
|
$showGroup = ! isset($printedGroup[$boIdx]);
|
||||||
|
$rowspan = (int) (($groupRows[$boIdx] ?? 1));
|
||||||
|
if ($showGroup) {
|
||||||
|
$printedGroup[$boIdx] = true;
|
||||||
|
}
|
||||||
?>
|
?>
|
||||||
</td>
|
<tr>
|
||||||
<td class="text-center">
|
<?php if ($showGroup): ?>
|
||||||
<a href="<?= mgmt_url('bag-orders/detail/' . (int) $row->bo_idx) ?>" class="text-blue-600 hover:underline text-sm mr-1">상세</a>
|
<td class="text-center align-top" rowspan="<?= $rowspan ?>"><?= esc((string) ($row['order_date'] ?? '')) ?></td>
|
||||||
<form action="<?= mgmt_url('bag-orders/cancel/' . (int) $row->bo_idx) ?>" method="POST" class="inline" onsubmit="return confirm('취소하시겠습니까?');">
|
<td class="text-left pl-2 align-top" rowspan="<?= $rowspan ?>"><?= esc((string) ($row['company_name'] ?? '')) ?></td>
|
||||||
<?= csrf_field() ?>
|
<?php endif; ?>
|
||||||
<button type="submit" class="text-orange-600 hover:underline text-sm mr-1">취소</button>
|
<td class="text-left pl-2"><?= esc((string) ($row['bag_name'] ?? '')) ?></td>
|
||||||
</form>
|
<td><?= number_format((int) ($row['order_qty'] ?? 0)) ?></td>
|
||||||
<form action="<?= mgmt_url('bag-orders/delete/' . (int) $row->bo_idx) ?>" method="POST" class="inline" onsubmit="return confirm('삭제하시겠습니까?');">
|
<td><?= number_format((int) ($row['received_qty'] ?? 0)) ?></td>
|
||||||
<?= csrf_field() ?>
|
<td><?= number_format((int) ($row['pending_qty'] ?? 0)) ?></td>
|
||||||
<button type="submit" class="text-red-600 hover:underline text-sm">삭제</button>
|
<td><?= number_format((float) ($row['amount'] ?? 0)) ?></td>
|
||||||
</form>
|
<td class="text-left pl-2"><?= esc((string) ($row['agency_name'] ?? '')) ?></td>
|
||||||
</td>
|
<td></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endforeach; ?>
|
<?php endforeach; ?>
|
||||||
<?php if (empty($list)): ?>
|
|
||||||
<tr><td colspan="10" class="text-center text-gray-400 py-4">등록된 발주가 없습니다.</td></tr>
|
<?php if (empty($rows ?? [])): ?>
|
||||||
|
<tr><td colspan="9" class="text-center text-gray-400 py-6">조회 조건에 해당하는 발주 내역이 없습니다.</td></tr>
|
||||||
<?php endif; ?>
|
<?php endif; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr class="bg-gray-100 font-bold">
|
||||||
|
<td colspan="3" class="text-center">총계</td>
|
||||||
|
<td class="text-right"><?= number_format((int) ($grandTotals['order_qty'] ?? 0)) ?></td>
|
||||||
|
<td class="text-right"><?= number_format((int) ($grandTotals['received_qty'] ?? 0)) ?></td>
|
||||||
|
<td class="text-right"><?= number_format((int) ($grandTotals['pending_qty'] ?? 0)) ?></td>
|
||||||
|
<td class="text-right"><?= number_format((float) ($grandTotals['amount'] ?? 0)) ?></td>
|
||||||
|
<td></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
<?php if (isset($pager)): ?><div class="mt-3"><?= $pager->links() ?></div><?php endif; ?>
|
|
||||||
|
<style>
|
||||||
|
@media print {
|
||||||
|
#debug-icon,
|
||||||
|
#debug-bar,
|
||||||
|
#debug-bar-contents,
|
||||||
|
#debug-toolbar,
|
||||||
|
.debug-toolbar,
|
||||||
|
.ci-debug-toolbar,
|
||||||
|
[id^='debug-bar-'],
|
||||||
|
[id^='debug-icon'],
|
||||||
|
[class*='debug-toolbar'] {
|
||||||
|
display: none !important;
|
||||||
|
visibility: hidden !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bag-order-print-wrap {
|
||||||
|
overflow: visible !important;
|
||||||
|
border: none !important;
|
||||||
|
margin-top: 0 !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bag-order-print-table {
|
||||||
|
width: 100% !important;
|
||||||
|
table-layout: auto !important;
|
||||||
|
}
|
||||||
|
|
||||||
|
.bag-order-print-table th,
|
||||||
|
.bag-order-print-table td {
|
||||||
|
white-space: nowrap !important;
|
||||||
|
word-break: keep-all !important;
|
||||||
|
overflow-wrap: normal !important;
|
||||||
|
font-size: 10px !important;
|
||||||
|
padding: 2px 3px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -1,83 +1,701 @@
|
|||||||
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel">
|
<?php
|
||||||
<span class="text-sm font-bold text-gray-700">발주 등록</span>
|
$editDefaults = is_array($editDefaults ?? null) ? $editDefaults : [];
|
||||||
|
$editMode = (bool) ($editMode ?? false);
|
||||||
|
$oldBagCodes = old('item_bag_code', $editDefaults['item_bag_code'] ?? []);
|
||||||
|
$oldQtySheets = old('item_qty_sheet', $editDefaults['item_qty_sheet'] ?? []);
|
||||||
|
$oldQtyBoxes = old('item_qty_box', $editDefaults['item_qty_box'] ?? []);
|
||||||
|
$oldBagCodes = is_array($oldBagCodes) ? $oldBagCodes : [];
|
||||||
|
$oldQtySheets = is_array($oldQtySheets) ? $oldQtySheets : [];
|
||||||
|
$oldQtyBoxes = is_array($oldQtyBoxes) ? $oldQtyBoxes : [];
|
||||||
|
$itemRowCount = max(8, count($oldBagCodes), count($oldQtySheets), count($oldQtyBoxes));
|
||||||
|
$defaultOrderDate = old('bo_order_date', $editDefaults['bo_order_date'] ?? date('Y-m-d'));
|
||||||
|
$defaultOrderMonth = old('bo_order_month_ui', substr($defaultOrderDate, 0, 7));
|
||||||
|
$defaultOrderYear = (int) substr($defaultOrderMonth, 0, 4);
|
||||||
|
$monthOptionValues = [];
|
||||||
|
for ($year = $defaultOrderYear - 2; $year <= $defaultOrderYear + 2; $year++) {
|
||||||
|
for ($month = 1; $month <= 12; $month++) {
|
||||||
|
$monthValue = sprintf('%04d-%02d', $year, $month);
|
||||||
|
$monthLabel = $year . '년 ' . $month . '월';
|
||||||
|
$monthOptionValues[] = ['value' => $monthValue, 'label' => $monthLabel];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$bagMeta = [];
|
||||||
|
foreach (($bagReferenceRows ?? []) as $row) {
|
||||||
|
$bagMeta[$row['code']] = [
|
||||||
|
'name' => $row['name'],
|
||||||
|
'orderPrice' => (float) $row['orderPrice'],
|
||||||
|
'boxPerPack' => (int) $row['boxPerPack'],
|
||||||
|
'packPerSheet' => (int) $row['packPerSheet'],
|
||||||
|
'totalPerBox' => max(1, (int) $row['totalPerBox']),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$initialSelectedItems = [];
|
||||||
|
$maxOldCount = max(count($oldBagCodes), count($oldQtySheets), count($oldQtyBoxes));
|
||||||
|
for ($i = 0; $i < $maxOldCount; $i++) {
|
||||||
|
$code = trim((string) ($oldBagCodes[$i] ?? ''));
|
||||||
|
if ($code === '' || !isset($bagMeta[$code])) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
$fallbackQtyBox = (int) ($oldQtyBoxes[$i] ?? 0);
|
||||||
|
$rawQtySheet = (int) ($oldQtySheets[$i] ?? 0);
|
||||||
|
$fallbackTotalPerBox = (int) ($bagMeta[$code]['totalPerBox'] ?? 1);
|
||||||
|
if ($fallbackQtyBox <= 0 && $rawQtySheet > 0) {
|
||||||
|
$fallbackQtyBox = intdiv($rawQtySheet, max(1, $fallbackTotalPerBox));
|
||||||
|
}
|
||||||
|
$initialSelectedItems[] = [
|
||||||
|
'code' => $code,
|
||||||
|
'qtyBox' => max(0, $fallbackQtyBox),
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
|
$statusMap = ['normal' => '정상', 'cancelled' => '취소', 'deleted' => '삭제'];
|
||||||
|
|
||||||
|
$hubReturn = (bool) ($hubReturn ?? false);
|
||||||
|
$changeMode = $editMode ? (string) ($changeMode ?? 'meta') : 'meta';
|
||||||
|
if (! in_array($changeMode, ['price', 'meta', 'delete'], true)) {
|
||||||
|
$changeMode = 'meta';
|
||||||
|
}
|
||||||
|
$orderLotNo = (string) ($orderLotNo ?? '');
|
||||||
|
$orderReturnMonth = (string) ($orderReturnMonth ?? '');
|
||||||
|
$deleteMode = $editMode && $changeMode === 'delete';
|
||||||
|
$defaultDeleteBoIdx = (int) ($editDefaults['bo_source_idx'] ?? 0);
|
||||||
|
$firstNormalBoIdx = null;
|
||||||
|
foreach (($recentOrders ?? []) as $_h) {
|
||||||
|
if ((string) ($_h->bo_status ?? '') === 'normal') {
|
||||||
|
$firstNormalBoIdx = (int) $_h->bo_idx;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$defaultDeleteOk = false;
|
||||||
|
foreach (($recentOrders ?? []) as $_h) {
|
||||||
|
if ((int) $_h->bo_idx === $defaultDeleteBoIdx && (string) ($_h->bo_status ?? '') === 'normal') {
|
||||||
|
$defaultDeleteOk = true;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$selectedDeleteBoIdx = $defaultDeleteOk ? $defaultDeleteBoIdx : (int) ($firstNormalBoIdx ?? 0);
|
||||||
|
?>
|
||||||
|
|
||||||
|
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel flex flex-wrap items-center justify-between gap-2">
|
||||||
|
<span class="text-sm font-bold text-gray-700"><?= $editMode ? '발주 변경' : '발주 등록' ?></span>
|
||||||
|
<?php if ($hubReturn && $orderReturnMonth !== ''): ?>
|
||||||
|
<a href="<?= base_url('bag/order/change?month=' . rawurlencode($orderReturnMonth) . '&hub_mode=' . rawurlencode($changeMode)) ?>" class="text-sm text-blue-600 hover:underline">발주 변경 목록</a>
|
||||||
|
<?php endif; ?>
|
||||||
</section>
|
</section>
|
||||||
<div class="border border-gray-300 p-4 mt-2 bg-white max-w-4xl">
|
|
||||||
<form action="<?= base_url('bag/order/store') ?>" method="POST" class="space-y-4">
|
<?php if ($deleteMode): ?>
|
||||||
|
<form action="<?= base_url('bag/order/delete') ?>" method="post" class="mt-2 space-y-2">
|
||||||
<?= csrf_field() ?>
|
<?= csrf_field() ?>
|
||||||
|
<div class="border border-gray-300 bg-white p-2 text-sm">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<span class="font-bold text-gray-700">발주월</span>
|
||||||
<label class="block text-sm font-bold text-gray-700 w-28">발주일 <span class="text-red-500">*</span></label>
|
<span class="ml-2"><?= esc($defaultOrderMonth) ?></span>
|
||||||
<input class="border border-gray-300 rounded px-3 py-1.5 text-sm w-44" name="bo_order_date" type="date" value="<?= esc(old('bo_order_date', date('Y-m-d'))) ?>" required/>
|
<span class="text-gray-600 ml-2">왼쪽 목록에서 삭제할 발주를 선택한 뒤 「삭제 실행」을 누르세요.</span>
|
||||||
</div>
|
</div>
|
||||||
|
<div class="grid grid-cols-1 xl:grid-cols-12 gap-2">
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
<section class="xl:col-span-5 border border-gray-300 bg-white">
|
||||||
<label class="block text-sm font-bold text-gray-700 w-28">수수료율</label>
|
<div class="border-b border-gray-300 bg-gray-50 px-2 py-1 text-sm font-bold text-gray-700">발주 이력</div>
|
||||||
<input class="border border-gray-300 rounded px-3 py-1.5 text-sm w-32 text-right" name="bo_fee_rate" type="number" step="0.01" value="<?= esc(old('bo_fee_rate', '0')) ?>"/>
|
<div class="overflow-auto max-h-[410px]">
|
||||||
<span class="text-sm text-gray-500">%</span>
|
<table class="w-full data-table text-sm">
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
|
||||||
<label class="block text-sm font-bold text-gray-700 w-28">제작업체</label>
|
|
||||||
<select class="border border-gray-300 rounded px-3 py-1.5 text-sm w-60" name="bo_company_idx">
|
|
||||||
<option value="">선택</option>
|
|
||||||
<?php foreach ($companies as $cp): ?>
|
|
||||||
<option value="<?= esc($cp->cp_idx) ?>" <?= (int) old('bo_company_idx') === (int) $cp->cp_idx ? 'selected' : '' ?>>
|
|
||||||
<?= esc($cp->cp_name) ?>
|
|
||||||
</option>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="flex flex-wrap items-center gap-2">
|
|
||||||
<label class="block text-sm font-bold text-gray-700 w-28">입고처</label>
|
|
||||||
<select class="border border-gray-300 rounded px-3 py-1.5 text-sm w-60" name="bo_agency_idx">
|
|
||||||
<option value="">선택</option>
|
|
||||||
<?php foreach ($agencies as $ag): ?>
|
|
||||||
<option value="<?= esc($ag->sa_idx) ?>" <?= (int) old('bo_agency_idx') === (int) $ag->sa_idx ? 'selected' : '' ?>>
|
|
||||||
[<?= esc($ag->sa_kind ?? '') ?>] <?= esc($ag->sa_code ?? '') ?> — <?= esc($ag->sa_name) ?>
|
|
||||||
</option>
|
|
||||||
<?php endforeach; ?>
|
|
||||||
</select>
|
|
||||||
</div>
|
|
||||||
|
|
||||||
<div class="mt-4">
|
|
||||||
<label class="block text-sm font-bold text-gray-700 mb-2">발주 품목</label>
|
|
||||||
<div class="border border-gray-300 overflow-auto">
|
|
||||||
<table class="w-full data-table">
|
|
||||||
<thead>
|
<thead>
|
||||||
<tr>
|
<tr>
|
||||||
<th class="w-16">순번</th>
|
<th class="w-10">선택</th>
|
||||||
<th>봉투</th>
|
<th class="w-28">발주일</th>
|
||||||
<th class="w-32">박스수</th>
|
<th>제작업체</th>
|
||||||
|
<th>입고처</th>
|
||||||
|
<th class="w-16">상태</th>
|
||||||
</tr>
|
</tr>
|
||||||
</thead>
|
</thead>
|
||||||
<tbody>
|
<tbody>
|
||||||
<?php for ($i = 0; $i < 3; $i++): ?>
|
<?php $deleteRadioFirst = true; ?>
|
||||||
<tr>
|
<?php foreach (($recentOrders ?? []) as $history): ?>
|
||||||
<td class="text-center"><?= $i + 1 ?></td>
|
<?php $rowNormal = (string) ($history->bo_status ?? '') === 'normal'; ?>
|
||||||
<td>
|
<tr class="<?= $rowNormal ? '' : 'opacity-60' ?>">
|
||||||
<select class="border border-gray-300 rounded px-2 py-1 text-sm w-full" name="item_bag_code[]">
|
<td class="text-center align-middle">
|
||||||
<option value="">선택</option>
|
<?php if ($rowNormal): ?>
|
||||||
<?php foreach ($bagCodes as $cd): ?>
|
<input type="radio" name="bo_idx" value="<?= (int) $history->bo_idx ?>" class="accent-red-600" <?= (int) $history->bo_idx === $selectedDeleteBoIdx ? 'checked' : '' ?> <?= $deleteRadioFirst ? 'required' : '' ?> />
|
||||||
<option value="<?= esc($cd->cd_code) ?>">
|
<?php $deleteRadioFirst = false; ?>
|
||||||
<?= esc($cd->cd_code) ?> — <?= esc($cd->cd_name) ?>
|
<?php else: ?>
|
||||||
</option>
|
<span class="text-gray-400" title="삭제할 수 없는 상태">—</span>
|
||||||
<?php endforeach; ?>
|
<?php endif; ?>
|
||||||
</select>
|
|
||||||
</td>
|
|
||||||
<td>
|
|
||||||
<input class="border border-gray-300 rounded px-2 py-1 text-sm w-full text-right" name="item_qty_box[]" type="number" min="0" value="0"/>
|
|
||||||
</td>
|
</td>
|
||||||
|
<td class="text-center"><?= esc((string) $history->bo_order_date) ?></td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($companyMap[(int) $history->bo_company_idx] ?? '-')) ?></td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($agencyMap[(int) $history->bo_agency_idx] ?? '-')) ?></td>
|
||||||
|
<td class="text-center"><?= esc((string) ($statusMap[(string) $history->bo_status] ?? $history->bo_status)) ?></td>
|
||||||
</tr>
|
</tr>
|
||||||
<?php endfor; ?>
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($recentOrders)): ?>
|
||||||
|
<tr><td colspan="5" class="text-center text-gray-400 py-4">발주 이력이 없습니다.</td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
</tbody>
|
</tbody>
|
||||||
</table>
|
</table>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
|
<section class="xl:col-span-7 border border-red-200 bg-red-50 p-4">
|
||||||
|
<p class="text-sm font-bold text-red-800 mb-2">발주 삭제</p>
|
||||||
|
<p class="text-sm text-gray-700 mb-4">목록에서 선택한 발주를 삭제 처리합니다. 계속하시겠습니까?</p>
|
||||||
|
<div class="flex flex-wrap gap-2 items-center">
|
||||||
|
<button type="submit" class="bg-red-600 text-white px-6 py-1.5 rounded-sm text-sm shadow hover:opacity-90" <?= $firstNormalBoIdx === null ? 'disabled' : '' ?>>삭제 실행</button>
|
||||||
|
<a href="<?= base_url('bag/order/change?month=' . rawurlencode($orderReturnMonth !== '' ? $orderReturnMonth : substr($defaultOrderDate, 0, 7))) ?>" class="bg-gray-200 text-gray-800 px-6 py-1.5 rounded-sm text-sm">취소</a>
|
||||||
</div>
|
</div>
|
||||||
|
</section>
|
||||||
<div class="flex gap-2 pt-2">
|
|
||||||
<button type="submit" class="bg-btn-search text-white px-6 py-1.5 rounded-sm text-sm shadow hover:opacity-90 transition">등록</button>
|
|
||||||
<a href="<?= base_url('bag/purchase-inbound') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
|
|
||||||
</div>
|
</div>
|
||||||
</form>
|
</form>
|
||||||
|
<?php else: ?>
|
||||||
|
|
||||||
|
<form action="<?= base_url('bag/order/store') ?>" method="POST" class="mt-2 space-y-2" id="bag-order-store-form">
|
||||||
|
<?= csrf_field() ?>
|
||||||
|
<?php if ($editMode): ?>
|
||||||
|
<input type="hidden" name="bo_source_idx" value="<?= esc((string) ($editDefaults['bo_source_idx'] ?? 0)) ?>" />
|
||||||
|
<fieldset class="border border-gray-200 rounded px-3 py-2 mb-1 text-sm bg-white">
|
||||||
|
<legend class="text-xs font-bold text-gray-600 px-1">변경 구분</legend>
|
||||||
|
<div class="flex flex-wrap gap-x-4 gap-y-1">
|
||||||
|
<label class="inline-flex items-center gap-1 cursor-pointer">
|
||||||
|
<input type="radio" name="bo_change_mode" value="price" <?= $changeMode === 'price' ? 'checked' : '' ?> />
|
||||||
|
<span>발주·도매·판매 단가</span>
|
||||||
|
</label>
|
||||||
|
<label class="inline-flex items-center gap-1 cursor-pointer">
|
||||||
|
<input type="radio" name="bo_change_mode" value="meta" <?= $changeMode === 'meta' ? 'checked' : '' ?> />
|
||||||
|
<span>업체·수수료·협회·발주</span>
|
||||||
|
</label>
|
||||||
</div>
|
</div>
|
||||||
|
<p class="text-xs text-gray-500 mt-1">
|
||||||
|
발주 삭제는 <a class="text-blue-600 hover:underline" href="<?= base_url('bag/order/revise/' . (int) ($editDefaults['bo_source_idx'] ?? 0) . '?change_mode=delete') ?>">발주 삭제 화면</a>으로 이동합니다.
|
||||||
|
</p>
|
||||||
|
</fieldset>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if ($hubReturn && $orderReturnMonth !== ''): ?>
|
||||||
|
<input type="hidden" name="order_return_hub" value="1" />
|
||||||
|
<input type="hidden" name="order_return_month" value="<?= esc($orderReturnMonth) ?>" />
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<div class="border border-gray-300 bg-white p-2">
|
||||||
|
<div class="flex flex-wrap items-center gap-4 text-sm">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<label for="bo_order_month_ui" class="font-bold text-gray-700">발주월</label>
|
||||||
|
<select id="bo_order_month_ui" name="bo_order_month_ui" class="border border-gray-300 rounded px-2 py-1 w-40">
|
||||||
|
<?php foreach ($monthOptionValues as $monthOption): ?>
|
||||||
|
<option value="<?= esc($monthOption['value']) ?>" <?= $monthOption['value'] === $defaultOrderMonth ? 'selected' : '' ?>>
|
||||||
|
<?= esc($monthOption['label']) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<span id="bo_order_month_ko" class="text-sm text-gray-700"></span>
|
||||||
|
</div>
|
||||||
|
<p class="text-blue-600 font-bold">※ 발주수량을 박스단위로 떨어지게 입력해 주세요.</p>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 xl:grid-cols-12 gap-2">
|
||||||
|
<section class="xl:col-span-5 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-[410px]">
|
||||||
|
<table class="w-full data-table text-sm">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="w-28">발주일</th>
|
||||||
|
<th>제작업체</th>
|
||||||
|
<th>입고처</th>
|
||||||
|
<th class="w-16">상태</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach (($recentOrders ?? []) as $history): ?>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">
|
||||||
|
<a href="<?= base_url('bag/order/revise/' . (int) $history->bo_idx) ?>" class="text-blue-600 hover:underline">
|
||||||
|
<?= esc((string) $history->bo_order_date) ?>
|
||||||
|
</a>
|
||||||
|
</td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($companyMap[(int) $history->bo_company_idx] ?? '-')) ?></td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($agencyMap[(int) $history->bo_agency_idx] ?? '-')) ?></td>
|
||||||
|
<td class="text-center"><?= esc((string) ($statusMap[(string) $history->bo_status] ?? $history->bo_status)) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($recentOrders)): ?>
|
||||||
|
<tr><td colspan="4" class="text-center text-gray-400 py-4">발주 이력이 없습니다.</td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="xl:col-span-7 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"><?= $editMode ? '발주 변경 수정' : '발주 Form' ?></div>
|
||||||
|
<div class="p-2 space-y-2">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-2">
|
||||||
|
<div class="flex items-center gap-2 text-sm">
|
||||||
|
<label for="bo_order_date" class="w-20 font-bold text-gray-700">발주일 <span class="text-red-500">*</span></label>
|
||||||
|
<input id="bo_order_date" name="bo_order_date" type="date" value="<?= esc($defaultOrderDate) ?>" required class="border border-gray-300 rounded px-2 py-1 w-full" />
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-sm">
|
||||||
|
<label for="bo_association_idx" class="w-20 font-bold text-gray-700">협회</label>
|
||||||
|
<select id="bo_association_idx" name="bo_association_idx" class="border border-gray-300 rounded px-2 py-1 w-full">
|
||||||
|
<option value="">선택</option>
|
||||||
|
<?php foreach (($associations ?? []) as $association): ?>
|
||||||
|
<option value="<?= esc((string) $association->cp_idx) ?>" <?= (int) old('bo_association_idx', $editDefaults['bo_association_idx'] ?? 0) === (int) $association->cp_idx ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) $association->cp_name) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-sm">
|
||||||
|
<label for="bo_company_idx" class="w-20 font-bold text-gray-700">제작업체</label>
|
||||||
|
<select id="bo_company_idx" name="bo_company_idx" class="border border-gray-300 rounded px-2 py-1 w-full">
|
||||||
|
<option value="">선택</option>
|
||||||
|
<?php foreach (($companies ?? []) as $company): ?>
|
||||||
|
<option value="<?= esc((string) $company->cp_idx) ?>" <?= (int) old('bo_company_idx', $editDefaults['bo_company_idx'] ?? 0) === (int) $company->cp_idx ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) $company->cp_name) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center gap-2 text-sm">
|
||||||
|
<label for="bo_agency_idx" class="w-20 font-bold text-gray-700">입고처</label>
|
||||||
|
<select id="bo_agency_idx" name="bo_agency_idx" class="border border-gray-300 rounded px-2 py-1 w-full">
|
||||||
|
<option value="">선택</option>
|
||||||
|
<?php foreach (($agencies ?? []) as $agency): ?>
|
||||||
|
<option value="<?= esc((string) $agency->sa_idx) ?>" <?= (int) old('bo_agency_idx', $editDefaults['bo_agency_idx'] ?? 0) === (int) $agency->sa_idx ? 'selected' : '' ?>>
|
||||||
|
[<?= esc((string) ($agency->sa_kind ?? '')) ?>] <?= esc((string) ($agency->sa_code ?? '')) ?> — <?= esc((string) $agency->sa_name) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="border border-gray-300 overflow-auto">
|
||||||
|
<table class="w-full data-table text-sm order-input-table" id="order-item-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="w-12">번호</th>
|
||||||
|
<th class="w-16">선택</th>
|
||||||
|
<th>품명</th>
|
||||||
|
<th class="w-24">수량</th>
|
||||||
|
<th class="w-24">단가</th>
|
||||||
|
<th class="w-24">낱장환산</th>
|
||||||
|
<?php if ($editMode): ?>
|
||||||
|
<th class="w-24">선정수량</th>
|
||||||
|
<th class="w-20">LOT</th>
|
||||||
|
<?php endif; ?>
|
||||||
|
<th class="w-28">금액</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody id="selected-order-items-body"></tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr>
|
||||||
|
<th colspan="3" class="text-center">계</th>
|
||||||
|
<th class="text-right pr-2" id="sum-box-qty">0</th>
|
||||||
|
<th></th>
|
||||||
|
<th class="text-right pr-2" id="sum-sheet-qty">0</th>
|
||||||
|
<?php if ($editMode): ?>
|
||||||
|
<th></th>
|
||||||
|
<th></th>
|
||||||
|
<?php endif; ?>
|
||||||
|
<th class="text-right pr-2" id="sum-amount">0</th>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="border border-gray-300 bg-gray-50 p-2 text-sm">
|
||||||
|
<div class="grid grid-cols-1 md:grid-cols-2 gap-x-6 gap-y-1">
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="text-gray-700">품목 금액 합계</span>
|
||||||
|
<strong id="sum-item-amount">0</strong>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="text-gray-700">조달수수료</span>
|
||||||
|
<span class="flex items-center gap-1">
|
||||||
|
<input id="bo_fee_rate_summary" name="bo_fee_rate" type="number" step="0.01" value="<?= esc(old('bo_fee_rate', $editDefaults['bo_fee_rate'] ?? '0')) ?>" class="border border-gray-300 rounded px-2 py-0.5 w-20 text-right" />
|
||||||
|
<strong>%</strong>
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between">
|
||||||
|
<span class="text-gray-700">조달수수료액</span>
|
||||||
|
<strong id="sum-fee-amount">0</strong>
|
||||||
|
</div>
|
||||||
|
<div class="flex items-center justify-between border-t border-red-300 pt-1">
|
||||||
|
<span class="font-bold text-gray-800">품목 + 수수료 합계</span>
|
||||||
|
<strong id="sum-grand-amount" class="text-red-700">0</strong>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex gap-2 pt-1">
|
||||||
|
<button type="submit" class="bg-btn-search text-white px-6 py-1.5 rounded-sm text-sm shadow hover:opacity-90 transition"><?= $editMode ? '변경 저장' : '발주' ?></button>
|
||||||
|
<a href="<?= base_url('bag/purchase-inbound') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<section 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">
|
||||||
|
<table class="w-full data-table text-sm order-reference-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="w-12">번호</th>
|
||||||
|
<th class="w-20">선택</th>
|
||||||
|
<th>봉투 종류</th>
|
||||||
|
<th class="w-24">발주단가</th>
|
||||||
|
<th class="w-24">Box당 팩</th>
|
||||||
|
<th class="w-24">팩당 낱장</th>
|
||||||
|
<th class="w-28">1박스 총 낱장</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach (($bagReferenceRows ?? []) as $idx => $row): ?>
|
||||||
|
<tr data-reference-row data-code="<?= esc((string) $row['code']) ?>" class="cursor-pointer">
|
||||||
|
<td class="text-center"><?= $idx + 1 ?></td>
|
||||||
|
<td class="text-center">
|
||||||
|
<button type="button" class="js-toggle-bag border border-gray-300 rounded px-2 py-0.5 text-xs hover:bg-gray-100" data-code="<?= esc((string) $row['code']) ?>">선택</button>
|
||||||
|
</td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) $row['name']) ?></td>
|
||||||
|
<td class="text-right pr-2"><?= number_format((float) $row['orderPrice'], 2) ?></td>
|
||||||
|
<td class="text-right pr-2"><?= number_format((int) $row['boxPerPack']) ?></td>
|
||||||
|
<td class="text-right pr-2"><?= number_format((int) $row['packPerSheet']) ?></td>
|
||||||
|
<td class="text-right pr-2"><?= number_format((int) $row['totalPerBox']) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($bagReferenceRows)): ?>
|
||||||
|
<tr><td colspan="6" class="text-center text-gray-400 py-4">표시할 봉투 기준 데이터가 없습니다.</td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
</form>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (! $deleteMode): ?>
|
||||||
|
<style>
|
||||||
|
.order-input-table tbody tr,
|
||||||
|
.order-reference-table tbody tr {
|
||||||
|
height: 34px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.order-input-table tbody td,
|
||||||
|
.order-reference-table tbody td {
|
||||||
|
padding-top: 4px;
|
||||||
|
padding-bottom: 4px;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(() => {
|
||||||
|
const bagMeta = <?= json_encode($bagMeta, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||||||
|
const initialSelectedItems = <?= json_encode($initialSelectedItems, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||||||
|
const selectedBody = document.getElementById('selected-order-items-body');
|
||||||
|
const referenceRows = Array.from(document.querySelectorAll('[data-reference-row]'));
|
||||||
|
const sumBoxQtyEl = document.getElementById('sum-box-qty');
|
||||||
|
const sumSheetQtyEl = document.getElementById('sum-sheet-qty');
|
||||||
|
const sumAmountEl = document.getElementById('sum-amount');
|
||||||
|
const sumItemAmountEl = document.getElementById('sum-item-amount');
|
||||||
|
const sumFeeAmountEl = document.getElementById('sum-fee-amount');
|
||||||
|
const sumGrandAmountEl = document.getElementById('sum-grand-amount');
|
||||||
|
const monthInput = document.getElementById('bo_order_month_ui');
|
||||||
|
const monthKoLabel = document.getElementById('bo_order_month_ko');
|
||||||
|
const orderDateInput = document.getElementById('bo_order_date');
|
||||||
|
const feeRateSummaryInput = document.getElementById('bo_fee_rate_summary');
|
||||||
|
const orderForm = document.querySelector('form[action*="bag/order/store"]');
|
||||||
|
const selectedItems = new Map();
|
||||||
|
let activeCode = null;
|
||||||
|
const editMode = <?= $editMode ? 'true' : 'false' ?>;
|
||||||
|
const changeMode = <?= json_encode($changeMode, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||||||
|
const orderLotNo = <?= json_encode($orderLotNo, JSON_UNESCAPED_UNICODE | JSON_UNESCAPED_SLASHES) ?>;
|
||||||
|
const colEmpty = editMode ? 9 : 7;
|
||||||
|
|
||||||
|
const formatNumber = (value) => new Intl.NumberFormat('ko-KR').format(Number.isFinite(value) ? value : 0);
|
||||||
|
const escapeHtml = (value) => String(value ?? '')
|
||||||
|
.replaceAll('&', '&')
|
||||||
|
.replaceAll('<', '<')
|
||||||
|
.replaceAll('>', '>')
|
||||||
|
.replaceAll('"', '"')
|
||||||
|
.replaceAll("'", ''');
|
||||||
|
|
||||||
|
const ensureMonthOption = (monthValue) => {
|
||||||
|
if (!monthInput || !monthValue) return;
|
||||||
|
const hasOption = Array.from(monthInput.options || []).some((option) => option.value === monthValue);
|
||||||
|
if (hasOption) return;
|
||||||
|
const [year, month] = monthValue.split('-');
|
||||||
|
const label = `${Number(year)}년 ${Number(month)}월`;
|
||||||
|
const option = new Option(label, monthValue, false, false);
|
||||||
|
monthInput.add(option);
|
||||||
|
};
|
||||||
|
|
||||||
|
const syncMonthFromDate = () => {
|
||||||
|
if (!orderDateInput || !monthInput || !orderDateInput.value) return;
|
||||||
|
const monthValue = orderDateInput.value.substring(0, 7);
|
||||||
|
ensureMonthOption(monthValue);
|
||||||
|
monthInput.value = monthValue;
|
||||||
|
updateMonthKoLabel();
|
||||||
|
};
|
||||||
|
|
||||||
|
const syncDateFromMonth = () => {
|
||||||
|
if (!orderDateInput || !monthInput || !monthInput.value) return;
|
||||||
|
const parts = monthInput.value.split('-');
|
||||||
|
if (parts.length !== 2) return;
|
||||||
|
const year = Number(parts[0]);
|
||||||
|
const month = Number(parts[1]);
|
||||||
|
if (!Number.isFinite(year) || !Number.isFinite(month)) return;
|
||||||
|
|
||||||
|
const currentDay = orderDateInput.value ? Number(orderDateInput.value.split('-')[2]) : 1;
|
||||||
|
const lastDay = new Date(year, month, 0).getDate();
|
||||||
|
const day = String(Math.min(Math.max(currentDay, 1), lastDay)).padStart(2, '0');
|
||||||
|
orderDateInput.value = `${String(year)}-${String(month).padStart(2, '0')}-${day}`;
|
||||||
|
updateMonthKoLabel();
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateMonthKoLabel = () => {
|
||||||
|
if (!monthKoLabel || !monthInput || !monthInput.value) {
|
||||||
|
if (monthKoLabel) monthKoLabel.textContent = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
const [year, month] = monthInput.value.split('-');
|
||||||
|
if (!year || !month) {
|
||||||
|
monthKoLabel.textContent = '';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
monthKoLabel.textContent = `${Number(year)}년 ${Number(month)}월`;
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateReferenceSelectionUi = () => {
|
||||||
|
referenceRows.forEach((row) => {
|
||||||
|
const code = row.dataset.code || '';
|
||||||
|
const button = row.querySelector('.js-toggle-bag');
|
||||||
|
const isSelected = selectedItems.has(code);
|
||||||
|
row.classList.toggle('bg-blue-50', isSelected);
|
||||||
|
if (button) {
|
||||||
|
button.textContent = isSelected ? '선택됨' : '선택';
|
||||||
|
button.classList.toggle('bg-blue-600', isSelected);
|
||||||
|
button.classList.toggle('text-white', isSelected);
|
||||||
|
button.classList.toggle('border-blue-600', isSelected);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const applyModeLock = () => {
|
||||||
|
if (!editMode) return;
|
||||||
|
const isPrice = changeMode === 'price';
|
||||||
|
selectedBody.querySelectorAll('.item-qty-box').forEach((el) => {
|
||||||
|
el.readOnly = isPrice;
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const updateTotals = () => {
|
||||||
|
let sumBoxQty = 0;
|
||||||
|
let sumSheetQty = 0;
|
||||||
|
let sumAmount = 0;
|
||||||
|
|
||||||
|
selectedBody.querySelectorAll('tr[data-item-row]').forEach((row) => {
|
||||||
|
const code = row.dataset.code || '';
|
||||||
|
const qtyInput = row.querySelector('.item-qty-box');
|
||||||
|
const qtyBox = Math.max(0, parseInt(qtyInput?.value || '0', 10));
|
||||||
|
const meta = bagMeta[code] || { orderPrice: 0, totalPerBox: 1 };
|
||||||
|
const priceInput = row.querySelector('.item-unit-price-input');
|
||||||
|
let unitPrice = Number(meta.orderPrice || 0);
|
||||||
|
if (priceInput) {
|
||||||
|
unitPrice = Math.max(0, parseFloat(priceInput.value || '0') || 0);
|
||||||
|
}
|
||||||
|
const totalPerBox = Math.max(1, Number(meta.totalPerBox || 1));
|
||||||
|
const qtySheet = qtyBox * totalPerBox;
|
||||||
|
const amount = qtySheet * unitPrice;
|
||||||
|
|
||||||
|
const unitPriceEl = row.querySelector('.item-unit-price');
|
||||||
|
const qtySheetEl = row.querySelector('.item-qty-sheet');
|
||||||
|
const selQtyEl = row.querySelector('.item-sel-qty');
|
||||||
|
const sheetHelpEl = row.querySelector('.item-sheet-help');
|
||||||
|
const amountEl = row.querySelector('.item-amount');
|
||||||
|
if (unitPriceEl) unitPriceEl.textContent = formatNumber(unitPrice);
|
||||||
|
if (qtySheetEl) qtySheetEl.textContent = formatNumber(qtySheet);
|
||||||
|
if (selQtyEl) selQtyEl.textContent = formatNumber(qtySheet);
|
||||||
|
if (sheetHelpEl) sheetHelpEl.textContent = `낱장 ${formatNumber(qtySheet)}장`;
|
||||||
|
if (amountEl) amountEl.textContent = formatNumber(amount);
|
||||||
|
|
||||||
|
selectedItems.set(code, { qtyBox });
|
||||||
|
sumBoxQty += qtyBox;
|
||||||
|
sumSheetQty += qtySheet;
|
||||||
|
sumAmount += amount;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (sumBoxQtyEl) sumBoxQtyEl.textContent = formatNumber(sumBoxQty);
|
||||||
|
if (sumSheetQtyEl) sumSheetQtyEl.textContent = formatNumber(sumSheetQty);
|
||||||
|
if (sumAmountEl) sumAmountEl.textContent = formatNumber(sumAmount);
|
||||||
|
if (sumItemAmountEl) sumItemAmountEl.textContent = formatNumber(sumAmount);
|
||||||
|
|
||||||
|
const feeRateSource = feeRateSummaryInput?.value ?? '0';
|
||||||
|
const feeRate = Math.max(0, parseFloat(feeRateSource) || 0);
|
||||||
|
const feeAmount = Math.round(sumAmount * (feeRate / 100));
|
||||||
|
const grandAmount = sumAmount + feeAmount;
|
||||||
|
|
||||||
|
if (feeRateSummaryInput && feeRateSummaryInput.value !== feeRate.toString()) {
|
||||||
|
feeRateSummaryInput.value = feeRate.toString();
|
||||||
|
}
|
||||||
|
if (sumFeeAmountEl) sumFeeAmountEl.textContent = formatNumber(feeAmount);
|
||||||
|
if (sumGrandAmountEl) sumGrandAmountEl.textContent = formatNumber(grandAmount);
|
||||||
|
};
|
||||||
|
|
||||||
|
const setActiveRow = (code) => {
|
||||||
|
activeCode = code || null;
|
||||||
|
selectedBody.querySelectorAll('tr[data-item-row]').forEach((row) => {
|
||||||
|
row.classList.toggle('bg-amber-50', row.dataset.code === activeCode);
|
||||||
|
});
|
||||||
|
};
|
||||||
|
|
||||||
|
const renderSelectedRows = () => {
|
||||||
|
const codes = Object.keys(bagMeta).filter((code) => selectedItems.has(code));
|
||||||
|
if (codes.length === 0) {
|
||||||
|
selectedBody.innerHTML = `<tr><td colspan="${colEmpty}" class="text-center text-gray-400 py-4">아래 "발주 등록 종류"에서 봉투를 선택해 주세요.</td></tr>`;
|
||||||
|
setActiveRow(null);
|
||||||
|
updateTotals();
|
||||||
|
updateReferenceSelectionUi();
|
||||||
|
applyModeLock();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
selectedBody.innerHTML = codes.map((code, idx) => {
|
||||||
|
const meta = bagMeta[code];
|
||||||
|
const qtyBox = Math.max(0, parseInt(String(selectedItems.get(code)?.qtyBox ?? 0), 10));
|
||||||
|
const name = meta?.name || code;
|
||||||
|
const up = Number(meta.orderPrice || 0);
|
||||||
|
const priceCell = editMode && changeMode === 'price'
|
||||||
|
? `<td class="text-right pr-1"><input type="number" name="item_unit_price[]" step="0.01" min="0" class="item-unit-price-input border border-gray-300 rounded px-1 py-0.5 w-full text-sm text-right" value="${up}" /></td>`
|
||||||
|
: `<td class="text-right pr-2 item-unit-price">0</td>`;
|
||||||
|
const extraCols = editMode
|
||||||
|
? `<td class="text-right pr-2 item-sel-qty">0</td><td class="text-center text-[11px] item-lot-cell leading-tight text-gray-700">생성<br /><span class="font-mono">${escapeHtml(orderLotNo || '—')}</span></td>`
|
||||||
|
: '';
|
||||||
|
|
||||||
|
return `
|
||||||
|
<tr data-item-row data-code="${escapeHtml(code)}" class="cursor-pointer">
|
||||||
|
<td class="text-center">${idx + 1}</td>
|
||||||
|
<td class="text-center">
|
||||||
|
<button type="button" class="js-remove-selected text-xs text-red-600 hover:underline" data-code="${escapeHtml(code)}">해제</button>
|
||||||
|
</td>
|
||||||
|
<td class="text-left pl-2">
|
||||||
|
${escapeHtml(name)}
|
||||||
|
<input type="hidden" name="item_bag_code[]" value="${escapeHtml(code)}" />
|
||||||
|
</td>
|
||||||
|
<td>
|
||||||
|
<input name="item_qty_box[]" type="number" min="0" step="1" value="${qtyBox}" class="item-qty-box border border-gray-300 rounded px-2 py-1 text-sm w-full text-right leading-tight" />
|
||||||
|
<p class="text-[11px] text-gray-500 mt-1 item-sheet-help">낱장 0장</p>
|
||||||
|
</td>
|
||||||
|
${priceCell}
|
||||||
|
<td class="text-right pr-2 item-qty-sheet">0</td>
|
||||||
|
${extraCols}
|
||||||
|
<td class="text-right pr-2 item-amount">0</td>
|
||||||
|
</tr>
|
||||||
|
`;
|
||||||
|
}).join('');
|
||||||
|
|
||||||
|
if (!activeCode || !selectedItems.has(activeCode)) {
|
||||||
|
activeCode = codes[0];
|
||||||
|
}
|
||||||
|
setActiveRow(activeCode);
|
||||||
|
updateTotals();
|
||||||
|
updateReferenceSelectionUi();
|
||||||
|
applyModeLock();
|
||||||
|
};
|
||||||
|
|
||||||
|
const toggleSelection = (code) => {
|
||||||
|
if (!code || !bagMeta[code]) return;
|
||||||
|
if (selectedItems.has(code)) {
|
||||||
|
selectedItems.delete(code);
|
||||||
|
if (activeCode === code) activeCode = null;
|
||||||
|
} else {
|
||||||
|
selectedItems.set(code, { qtyBox: 0 });
|
||||||
|
activeCode = code;
|
||||||
|
}
|
||||||
|
renderSelectedRows();
|
||||||
|
};
|
||||||
|
|
||||||
|
initialSelectedItems.forEach((item) => {
|
||||||
|
if (!item || !item.code || !bagMeta[item.code]) return;
|
||||||
|
selectedItems.set(item.code, { qtyBox: Math.max(0, parseInt(String(item.qtyBox ?? 0), 10)) });
|
||||||
|
activeCode = item.code;
|
||||||
|
});
|
||||||
|
|
||||||
|
selectedBody.addEventListener('click', (event) => {
|
||||||
|
const removeButton = event.target.closest('.js-remove-selected');
|
||||||
|
if (removeButton) {
|
||||||
|
toggleSelection(removeButton.dataset.code || '');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
const row = event.target.closest('tr[data-item-row]');
|
||||||
|
if (!row) return;
|
||||||
|
const code = row.dataset.code || '';
|
||||||
|
setActiveRow(code);
|
||||||
|
const qtyInput = row.querySelector('.item-qty-box');
|
||||||
|
if (qtyInput) qtyInput.focus();
|
||||||
|
});
|
||||||
|
|
||||||
|
selectedBody.addEventListener('input', (event) => {
|
||||||
|
const qtyInput = event.target.closest('.item-qty-box');
|
||||||
|
const priceField = event.target.closest('.item-unit-price-input');
|
||||||
|
if (qtyInput) {
|
||||||
|
const row = qtyInput.closest('tr[data-item-row]');
|
||||||
|
if (!row) return;
|
||||||
|
const code = row.dataset.code || '';
|
||||||
|
selectedItems.set(code, { qtyBox: Math.max(0, parseInt(qtyInput.value || '0', 10)) });
|
||||||
|
updateTotals();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (priceField) {
|
||||||
|
updateTotals();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
referenceRows.forEach((row) => {
|
||||||
|
row.addEventListener('click', (event) => {
|
||||||
|
const button = event.target.closest('.js-toggle-bag');
|
||||||
|
if (button) {
|
||||||
|
toggleSelection(button.dataset.code || '');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if (event.target.closest('td')) {
|
||||||
|
toggleSelection(row.dataset.code || '');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
});
|
||||||
|
|
||||||
|
if (monthInput) monthInput.addEventListener('change', () => { syncDateFromMonth(); updateTotals(); });
|
||||||
|
if (orderDateInput) orderDateInput.addEventListener('change', syncMonthFromDate);
|
||||||
|
if (feeRateSummaryInput) {
|
||||||
|
feeRateSummaryInput.addEventListener('input', () => {
|
||||||
|
updateTotals();
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
if (orderForm) {
|
||||||
|
orderForm.addEventListener('submit', (event) => {
|
||||||
|
const hasValidItem = Array.from(selectedBody.querySelectorAll('tr[data-item-row]')).some((row) => {
|
||||||
|
const qtyInput = row.querySelector('.item-qty-box');
|
||||||
|
return Math.max(0, parseInt(qtyInput?.value || '0', 10)) > 0;
|
||||||
|
});
|
||||||
|
|
||||||
|
if (!hasValidItem) {
|
||||||
|
event.preventDefault();
|
||||||
|
alert('봉투를 선택하고 수량을 1 이상 입력해 주세요.');
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
|
syncMonthFromDate();
|
||||||
|
updateMonthKoLabel();
|
||||||
|
renderSelectedRows();
|
||||||
|
|
||||||
|
if (editMode) {
|
||||||
|
document.querySelectorAll('input[name="bo_change_mode"]').forEach((r) => {
|
||||||
|
r.addEventListener('change', () => {
|
||||||
|
const u = new URL(window.location.href);
|
||||||
|
u.searchParams.set('change_mode', r.value);
|
||||||
|
window.location.href = u.toString();
|
||||||
|
});
|
||||||
|
});
|
||||||
|
}
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
|
<?php endif; ?>
|
||||||
|
|||||||
106
app/Views/bag/order_change.php
Normal file
106
app/Views/bag/order_change.php
Normal file
@@ -0,0 +1,106 @@
|
|||||||
|
<?php
|
||||||
|
$month = $month ?? date('Y-m');
|
||||||
|
$hubMode = in_array(($hubMode ?? 'meta'), ['price', 'meta', 'delete'], true) ? (string) ($hubMode ?? 'meta') : 'meta';
|
||||||
|
$monthOptionValues = [];
|
||||||
|
$y = (int) substr($month, 0, 4);
|
||||||
|
for ($year = $y - 2; $year <= $y + 2; $year++) {
|
||||||
|
for ($m = 1; $m <= 12; $m++) {
|
||||||
|
$monthValue = sprintf('%04d-%02d', $year, $m);
|
||||||
|
$monthOptionValues[] = ['value' => $monthValue, 'label' => $year . '년 ' . $m . '월'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$statusMap = ['normal' => '정상', 'cancelled' => '취소', 'deleted' => '삭제'];
|
||||||
|
?>
|
||||||
|
|
||||||
|
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel flex flex-wrap items-center justify-between gap-2">
|
||||||
|
<span class="text-sm font-bold text-gray-700">발주 변경</span>
|
||||||
|
<a href="<?= base_url('bag/purchase-inbound') ?>" class="text-sm text-gray-600 hover:underline">발주 입고 관리로</a>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="mt-2 space-y-3">
|
||||||
|
<?php if (session()->getFlashdata('success')): ?>
|
||||||
|
<div class="border border-green-300 bg-green-50 text-green-800 px-3 py-2 text-sm"><?= esc((string) session()->getFlashdata('success')) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (session()->getFlashdata('error')): ?>
|
||||||
|
<div class="border border-red-300 bg-red-50 text-red-800 px-3 py-2 text-sm"><?= esc((string) session()->getFlashdata('error')) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<form method="get" action="<?= base_url('bag/order/change') ?>" class="border border-gray-300 bg-white p-3 flex flex-wrap items-end gap-4">
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<label for="hub_month" class="text-sm font-bold text-gray-700">발주월</label>
|
||||||
|
<select id="hub_month" name="month" class="border border-gray-300 rounded px-2 py-1 w-44 text-sm">
|
||||||
|
<?php foreach ($monthOptionValues as $opt): ?>
|
||||||
|
<option value="<?= esc($opt['value']) ?>" <?= $opt['value'] === $month ? 'selected' : '' ?>><?= esc($opt['label']) ?></option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<fieldset class="border border-gray-200 rounded px-3 py-2">
|
||||||
|
<legend class="text-xs font-bold text-gray-600 px-1">변경 구분</legend>
|
||||||
|
<div class="flex flex-wrap gap-x-4 gap-y-1 text-sm">
|
||||||
|
<label class="inline-flex items-center gap-1 cursor-pointer">
|
||||||
|
<input type="radio" name="hub_mode" value="price" <?= $hubMode === 'price' ? 'checked' : '' ?> />
|
||||||
|
<span>발주·도매·판매 단가</span>
|
||||||
|
</label>
|
||||||
|
<label class="inline-flex items-center gap-1 cursor-pointer">
|
||||||
|
<input type="radio" name="hub_mode" value="meta" <?= $hubMode === 'meta' ? 'checked' : '' ?> />
|
||||||
|
<span>업체·수수료·협회·발주</span>
|
||||||
|
</label>
|
||||||
|
<label class="inline-flex items-center gap-1 cursor-pointer">
|
||||||
|
<input type="radio" name="hub_mode" value="delete" <?= $hubMode === 'delete' ? 'checked' : '' ?> />
|
||||||
|
<span>발주 삭제</span>
|
||||||
|
</label>
|
||||||
|
</div>
|
||||||
|
</fieldset>
|
||||||
|
<button type="submit" class="bg-btn-search text-white px-4 py-1.5 rounded-sm text-sm shadow hover:opacity-90">조회</button>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<div class="grid grid-cols-1 lg:grid-cols-12 gap-2">
|
||||||
|
<section class="lg:col-span-5 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-[min(420px,60vh)]">
|
||||||
|
<table class="w-full data-table text-sm">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="w-28">발주일</th>
|
||||||
|
<th>제작업체</th>
|
||||||
|
<th class="w-20">상태</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach (($monthOrders ?? []) as $row): ?>
|
||||||
|
<?php
|
||||||
|
$canEdit = ((string) ($row->bo_status ?? '')) === 'normal';
|
||||||
|
$href = base_url('bag/order/revise/' . (int) $row->bo_idx . '?change_mode=' . rawurlencode($hubMode));
|
||||||
|
?>
|
||||||
|
<tr class="<?= $canEdit ? '' : 'opacity-70' ?>">
|
||||||
|
<td class="text-center">
|
||||||
|
<?php if ($canEdit): ?>
|
||||||
|
<a href="<?= esc($href) ?>" class="text-blue-600 hover:underline font-medium"><?= esc((string) ($row->bo_order_date ?? '')) ?></a>
|
||||||
|
<?php else: ?>
|
||||||
|
<span><?= esc((string) ($row->bo_order_date ?? '')) ?></span>
|
||||||
|
<?php endif; ?>
|
||||||
|
</td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($companyMap[(int) ($row->bo_company_idx ?? 0)] ?? '-')) ?></td>
|
||||||
|
<td class="text-center text-xs"><?= esc((string) ($statusMap[(string) ($row->bo_status ?? '')] ?? $row->bo_status)) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($monthOrders)): ?>
|
||||||
|
<tr><td colspan="3" class="text-center text-gray-400 py-6">해당 월 발주가 없습니다.</td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="lg:col-span-7 border border-dashed border-gray-300 bg-gray-50 p-4 text-sm text-gray-600">
|
||||||
|
<p class="font-bold text-gray-800 mb-2">안내</p>
|
||||||
|
<ul class="list-disc pl-5 space-y-1">
|
||||||
|
<li><strong class="text-gray-900">발주 삭제</strong>를 선택하고 <strong class="text-gray-900">조회</strong>하면 발주 삭제 화면으로 이동합니다 (해당 월에 정상 발주가 있을 때).</li>
|
||||||
|
<li>그 외 변경 구분에서는 왼쪽 목록에서 <strong class="text-gray-900">발주일</strong>을 클릭하면 선택한 <strong class="text-gray-900">변경 구분</strong>으로 발주 변경 화면이 열립니다.</li>
|
||||||
|
<li><strong class="text-gray-900">발주·도매·판매 단가</strong>: 품목별 단가를 수정해 저장합니다 (발주 변경 시에만).</li>
|
||||||
|
<li><strong class="text-gray-900">업체·수수료·협회·발주</strong>: 발주일·입고처·수량 등을 수정해 저장합니다.</li>
|
||||||
|
<li><strong class="text-gray-900">발주 삭제</strong> 화면에서 목록을 선택해 삭제 처리합니다 (복구 불가에 가깝게 동작하므로 확인 후 진행하세요).</li>
|
||||||
|
</ul>
|
||||||
|
</section>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
@@ -58,7 +58,11 @@
|
|||||||
<section class="mt-4">
|
<section class="mt-4">
|
||||||
<div class="flex items-center justify-between mb-2 border-b pb-1">
|
<div class="flex items-center justify-between mb-2 border-b pb-1">
|
||||||
<h3 class="text-base font-bold text-gray-700">입고 현황</h3>
|
<h3 class="text-base font-bold text-gray-700">입고 현황</h3>
|
||||||
<a href="<?= base_url('bag/receiving/create') ?>" class="bg-btn-search text-white px-3 py-1.5 rounded-sm text-sm">입고 처리</a>
|
<div class="flex items-center gap-2">
|
||||||
|
<a href="<?= base_url('bag/receiving/scanner') ?>" class="bg-btn-search text-white px-3 py-1.5 rounded-sm text-sm">입고 처리</a>
|
||||||
|
<a href="<?= base_url('bag/receiving/batch') ?>" class="border border-gray-300 text-gray-700 px-3 py-1.5 rounded-sm text-sm hover:bg-gray-50">일괄 입고</a>
|
||||||
|
<a href="<?= base_url('bag/receiving/status') ?>" class="border border-gray-300 text-gray-700 px-3 py-1.5 rounded-sm text-sm hover:bg-gray-50">입고 현황 리포트</a>
|
||||||
|
</div>
|
||||||
</div>
|
</div>
|
||||||
<table class="data-table">
|
<table class="data-table">
|
||||||
<thead><tr>
|
<thead><tr>
|
||||||
|
|||||||
119
app/Views/bag/receiving_batch.php
Normal file
119
app/Views/bag/receiving_batch.php
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel flex flex-wrap items-center justify-between gap-2">
|
||||||
|
<span class="text-sm font-bold text-gray-700">일괄 입고</span>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<a href="<?= base_url('bag/receiving/scanner') ?>" class="border border-gray-300 text-gray-700 px-3 py-1 rounded-sm text-sm hover:bg-gray-50">스캐너 입고</a>
|
||||||
|
<a href="<?= base_url('bag/receiving/status') ?>" class="border border-gray-300 text-gray-700 px-3 py-1 rounded-sm text-sm hover:bg-gray-50">입고 현황</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<?php if (session()->getFlashdata('success')): ?>
|
||||||
|
<div class="mt-2 border border-green-300 bg-green-50 text-green-800 px-3 py-2 text-sm"><?= esc((string) session()->getFlashdata('success')) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (session()->getFlashdata('error')): ?>
|
||||||
|
<div class="mt-2 border border-red-300 bg-red-50 text-red-800 px-3 py-2 text-sm"><?= esc((string) session()->getFlashdata('error')) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<section class="p-2 bg-white border border-gray-300 mt-2">
|
||||||
|
<form method="get" action="<?= base_url('bag/receiving/batch') ?>" class="flex flex-wrap items-center gap-2">
|
||||||
|
<label class="text-sm text-gray-600">제작 업체</label>
|
||||||
|
<select name="company_idx" class="border border-gray-300 rounded px-2 py-1 text-sm w-56">
|
||||||
|
<option value="0">전 체</option>
|
||||||
|
<?php foreach (($companies ?? []) as $company): ?>
|
||||||
|
<option value="<?= (int) $company->cp_idx ?>" <?= (int) ($companyIdx ?? 0) === (int) $company->cp_idx ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) ($company->cp_name ?? '')) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
<button type="submit" class="bg-btn-search text-white px-4 py-1 rounded-sm text-sm">조회</button>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<form action="<?= base_url('bag/receiving/batch/store') ?>" method="post" class="mt-2 space-y-2">
|
||||||
|
<?= csrf_field() ?>
|
||||||
|
<input type="hidden" name="company_idx" value="<?= (int) ($companyIdx ?? 0) ?>" />
|
||||||
|
|
||||||
|
<section class="p-2 bg-white border border-gray-300">
|
||||||
|
<div class="grid grid-cols-1 xl:grid-cols-12 gap-2 items-end">
|
||||||
|
<div class="xl:col-span-3 flex items-center gap-2">
|
||||||
|
<label class="text-sm text-gray-600 shrink-0 w-28">인수자 (대행소)</label>
|
||||||
|
<select name="br_receiver_ref" class="border border-gray-300 rounded px-2 py-1 text-sm w-full" required>
|
||||||
|
<?php foreach (($receiverOptions ?? []) as $opt): ?>
|
||||||
|
<option value="<?= esc((string) ($opt['ref'] ?? '')) ?>" <?= (string) ($receiverRef ?? '') === (string) ($opt['ref'] ?? '') ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) ($opt['label'] ?? '')) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="xl:col-span-3 flex items-center gap-2">
|
||||||
|
<label class="text-sm text-gray-600 shrink-0 w-28">인계자 (제작업체)</label>
|
||||||
|
<select name="br_sender_idx" class="border border-gray-300 rounded px-2 py-1 text-sm w-full">
|
||||||
|
<?php foreach (($senders ?? []) as $sender): ?>
|
||||||
|
<option value="<?= (int) ($sender->mg_idx ?? 0) ?>" <?= (int) ($senderIdx ?? 0) === (int) ($sender->mg_idx ?? 0) ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) ($sender->mg_name ?? '')) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="xl:col-span-2 flex items-center gap-2">
|
||||||
|
<label class="text-sm text-gray-600 w-16">입고일</label>
|
||||||
|
<input type="date" name="br_receive_date" value="<?= esc((string) old('br_receive_date', date('Y-m-d'))) ?>" class="border border-gray-300 rounded px-2 py-1 text-sm w-full" required />
|
||||||
|
</div>
|
||||||
|
<div class="xl:col-span-2">
|
||||||
|
<button type="submit" class="w-full border border-blue-600 text-blue-700 px-2 py-1 rounded-sm text-sm hover:bg-blue-50">입고 처리</button>
|
||||||
|
</div>
|
||||||
|
<div class="xl:col-span-2 text-xs text-gray-500">체크한 LOT-봉투 행의 미입고량을 전부 입고 처리합니다.</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="border border-gray-300 overflow-auto bg-white">
|
||||||
|
<table class="w-full data-table text-sm">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th class="w-12"><input type="checkbox" id="check-all" /></th>
|
||||||
|
<th>발주일자</th>
|
||||||
|
<th>봉투종류</th>
|
||||||
|
<th>발주량(매)</th>
|
||||||
|
<th>미입고량(매)</th>
|
||||||
|
<th>제작업체</th>
|
||||||
|
<th>LOT NO</th>
|
||||||
|
<th>발주NO</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach (($rows ?? []) as $row): ?>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center">
|
||||||
|
<input type="checkbox" name="selected_rows[]" value="<?= esc((string) ($row['row_key'] ?? '')) ?>" />
|
||||||
|
</td>
|
||||||
|
<td class="text-center"><?= esc((string) ($row['order_date'] ?? '')) ?></td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($row['bag_name'] ?? '')) ?></td>
|
||||||
|
<td class="text-right"><?= number_format((int) ($row['order_qty_sheet'] ?? 0)) ?></td>
|
||||||
|
<td class="text-right text-blue-700 font-semibold"><?= number_format((int) ($row['pending_qty_sheet'] ?? 0)) ?></td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($row['company_name'] ?? '')) ?></td>
|
||||||
|
<td class="text-center font-mono"><?= esc((string) ($row['lot_no'] ?? '')) ?></td>
|
||||||
|
<td class="text-center"><?= esc((string) ($row['order_no'] ?? '')) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($rows ?? [])): ?>
|
||||||
|
<tr><td colspan="8" class="text-center text-gray-400 py-4">일괄 입고 가능한 미입고 행이 없습니다.</td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<a href="<?= base_url('bag/purchase-inbound') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm">취소</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(() => {
|
||||||
|
const all = document.getElementById('check-all');
|
||||||
|
if (!all) return;
|
||||||
|
all.addEventListener('change', () => {
|
||||||
|
document.querySelectorAll('input[name="selected_rows[]"]').forEach((el) => {
|
||||||
|
el.checked = all.checked;
|
||||||
|
});
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
153
app/Views/bag/receiving_scanner.php
Normal file
153
app/Views/bag/receiving_scanner.php
Normal file
@@ -0,0 +1,153 @@
|
|||||||
|
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel flex flex-wrap items-center justify-between gap-2">
|
||||||
|
<span class="text-sm font-bold text-gray-700">발주 입고(스캐너 대체 수동입력)</span>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<a href="<?= base_url('bag/receiving/batch') ?>" class="border border-gray-300 text-gray-700 px-3 py-1 rounded-sm text-sm hover:bg-gray-50">일괄 입고</a>
|
||||||
|
<a href="<?= base_url('bag/receiving/status') ?>" class="border border-gray-300 text-gray-700 px-3 py-1 rounded-sm text-sm hover:bg-gray-50">입고 현황</a>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<?php if (session()->getFlashdata('success')): ?>
|
||||||
|
<div class="mt-2 border border-green-300 bg-green-50 text-green-800 px-3 py-2 text-sm"><?= esc((string) session()->getFlashdata('success')) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
<?php if (session()->getFlashdata('error')): ?>
|
||||||
|
<div class="mt-2 border border-red-300 bg-red-50 text-red-800 px-3 py-2 text-sm"><?= esc((string) session()->getFlashdata('error')) ?></div>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<section class="p-2 bg-white border border-gray-300 mt-2">
|
||||||
|
<form method="get" action="<?= base_url('bag/receiving/scanner') ?>" class="flex flex-wrap items-end gap-2">
|
||||||
|
<div class="flex flex-col min-w-[14rem] max-w-[22rem]">
|
||||||
|
<label class="text-xs text-gray-500 mb-1">제작업체</label>
|
||||||
|
<select name="company_idx" class="border border-gray-300 rounded px-2 py-1.5 text-sm bg-white">
|
||||||
|
<option value="0">제작업체 선택</option>
|
||||||
|
<?php foreach (($companies ?? []) as $company): ?>
|
||||||
|
<option value="<?= (int) ($company->cp_idx ?? 0) ?>" <?= (int) ($companyIdx ?? 0) === (int) ($company->cp_idx ?? 0) ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) ($company->cp_name ?? '')) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<button type="submit" class="bg-btn-search text-white px-4 py-1.5 rounded-sm text-sm shrink-0">조회</button>
|
||||||
|
</form>
|
||||||
|
<?php if ((int) ($companyIdx ?? 0) <= 0): ?>
|
||||||
|
<p class="text-xs text-gray-600 mt-2">제작업체를 선택하면 해당 업체 발주 중 미입고 내역을 조회합니다.</p>
|
||||||
|
<?php elseif (empty($rows ?? [])): ?>
|
||||||
|
<p class="text-xs text-amber-700 mt-2">미입고 잔량이 있는 발주가 없습니다. 발주 등록 후 다시 확인해 주세요.</p>
|
||||||
|
<?php endif; ?>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<form action="<?= base_url('bag/receiving/scanner/store') ?>" method="post" class="mt-2 space-y-2">
|
||||||
|
<?= csrf_field() ?>
|
||||||
|
<input type="hidden" name="company_idx" value="<?= (int) ($companyIdx ?? 0) ?>" />
|
||||||
|
|
||||||
|
<section class="p-2 bg-white border border-gray-300">
|
||||||
|
<div class="grid grid-cols-1 xl:grid-cols-12 gap-2 items-end">
|
||||||
|
<div class="xl:col-span-3 flex items-center gap-2">
|
||||||
|
<label class="text-sm text-gray-600 shrink-0 w-28">인수자 (대행소)</label>
|
||||||
|
<select name="br_receiver_ref" class="border border-gray-300 rounded px-2 py-1 text-sm w-full" required>
|
||||||
|
<?php foreach (($receiverOptions ?? []) as $opt): ?>
|
||||||
|
<option value="<?= esc((string) ($opt['ref'] ?? '')) ?>" <?= (string) ($receiverRef ?? '') === (string) ($opt['ref'] ?? '') ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) ($opt['label'] ?? '')) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="xl:col-span-3 flex items-center gap-2">
|
||||||
|
<label class="text-sm text-gray-600 shrink-0 w-28">인계자 (제작업체)</label>
|
||||||
|
<select name="br_sender_idx" class="border border-gray-300 rounded px-2 py-1 text-sm w-full">
|
||||||
|
<?php foreach (($senders ?? []) as $sender): ?>
|
||||||
|
<option value="<?= (int) ($sender->mg_idx ?? 0) ?>" <?= (int) ($senderIdx ?? 0) === (int) ($sender->mg_idx ?? 0) ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) ($sender->mg_name ?? '')) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
</div>
|
||||||
|
<div class="xl:col-span-2 flex items-center gap-2">
|
||||||
|
<label class="text-sm text-gray-600 w-16">입고일</label>
|
||||||
|
<input type="date" name="br_receive_date" value="<?= esc((string) old('br_receive_date', date('Y-m-d'))) ?>" class="border border-gray-300 rounded px-2 py-1 text-sm w-full" required />
|
||||||
|
</div>
|
||||||
|
<div class="xl:col-span-2">
|
||||||
|
<button type="submit" class="w-full border border-blue-600 text-blue-700 px-2 py-1 rounded-sm text-sm hover:bg-blue-50">입고 처리</button>
|
||||||
|
</div>
|
||||||
|
<div class="xl:col-span-2 text-xs text-gray-500">상단에서 제작업체를 조회한 뒤, 아래에서 입고량(매)을 입력해 저장합니다.</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="border border-gray-300 overflow-auto bg-white">
|
||||||
|
<table class="w-full data-table text-sm">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>발주일자</th>
|
||||||
|
<th>봉투종류</th>
|
||||||
|
<th>발주량(매)</th>
|
||||||
|
<th>미입고량(매)</th>
|
||||||
|
<th>입고량(매)</th>
|
||||||
|
<th>제작업체</th>
|
||||||
|
<th>LOT NO</th>
|
||||||
|
<th>발주NO</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php foreach (($rows ?? []) as $row): ?>
|
||||||
|
<?php $k = (string) ($row['row_key'] ?? ''); ?>
|
||||||
|
<tr data-row-key="<?= esc($k) ?>" data-lot-no="<?= esc((string) ($row['lot_no'] ?? '')) ?>" data-bag-code="<?= esc((string) ($row['bag_code'] ?? '')) ?>" data-total-per-box="<?= (int) ($row['total_per_box'] ?? 1) ?>" data-pack-per-sheet="<?= (int) ($row['pack_per_sheet'] ?? 1) ?>" data-pending-original="<?= (int) ($row['pending_qty_sheet'] ?? 0) ?>">
|
||||||
|
<td class="text-center"><?= esc((string) ($row['order_date'] ?? '')) ?></td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($row['bag_name'] ?? '')) ?></td>
|
||||||
|
<td class="text-right"><?= number_format((int) ($row['order_qty_sheet'] ?? 0)) ?></td>
|
||||||
|
<td class="text-right pending-cell"><?= number_format((int) ($row['pending_qty_sheet'] ?? 0)) ?></td>
|
||||||
|
<td class="text-right">
|
||||||
|
<input type="number" min="0" max="<?= (int) ($row['pending_qty_sheet'] ?? 0) ?>" name="receive_qty_sheet[<?= esc($k) ?>]" value="<?= esc((string) old('receive_qty_sheet.' . $k, '0')) ?>" class="w-24 border border-gray-300 rounded px-1 py-0.5 text-sm text-right receive-input" />
|
||||||
|
</td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($row['company_name'] ?? '')) ?></td>
|
||||||
|
<td class="text-center font-mono"><?= esc((string) ($row['lot_no'] ?? '')) ?></td>
|
||||||
|
<td class="text-center"><?= esc((string) ($row['order_no'] ?? '')) ?></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
<?php if (empty($rows ?? [])): ?>
|
||||||
|
<tr><td colspan="8" class="text-center text-gray-400 py-4"><?php
|
||||||
|
if ((int) ($companyIdx ?? 0) <= 0) {
|
||||||
|
echo '제작업체를 선택하고 조회해 주세요.';
|
||||||
|
} else {
|
||||||
|
echo '해당 제작업체의 미입고 발주 내역이 없습니다.';
|
||||||
|
}
|
||||||
|
?></td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<a href="<?= base_url('bag/purchase-inbound') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm">취소</a>
|
||||||
|
</div>
|
||||||
|
</form>
|
||||||
|
|
||||||
|
<script>
|
||||||
|
(() => {
|
||||||
|
const parseIntSafe = (v) => {
|
||||||
|
const n = Number(String(v ?? '').replace(/,/g, ''));
|
||||||
|
return Number.isFinite(n) ? Math.max(0, Math.floor(n)) : 0;
|
||||||
|
};
|
||||||
|
|
||||||
|
const refreshPending = (row) => {
|
||||||
|
const pendingCell = row.querySelector('.pending-cell');
|
||||||
|
const input = row.querySelector('.receive-input');
|
||||||
|
if (!pendingCell || !input) return;
|
||||||
|
const original = parseIntSafe(row.getAttribute('data-pending-original'));
|
||||||
|
const current = parseIntSafe(input.value);
|
||||||
|
const remain = Math.max(0, original - current);
|
||||||
|
pendingCell.textContent = Number(remain || 0).toLocaleString('ko-KR');
|
||||||
|
};
|
||||||
|
|
||||||
|
document.querySelectorAll('.receive-input').forEach((input) => {
|
||||||
|
input.addEventListener('input', (e) => {
|
||||||
|
const row = e.target.closest('tr');
|
||||||
|
if (!row) return;
|
||||||
|
const original = parseIntSafe(row.getAttribute('data-pending-original'));
|
||||||
|
const current = Math.min(parseIntSafe(input.value), original);
|
||||||
|
input.value = String(current);
|
||||||
|
refreshPending(row);
|
||||||
|
});
|
||||||
|
const row = input.closest('tr');
|
||||||
|
if (row) refreshPending(row);
|
||||||
|
});
|
||||||
|
})();
|
||||||
|
</script>
|
||||||
138
app/Views/bag/receiving_status.php
Normal file
138
app/Views/bag/receiving_status.php
Normal file
@@ -0,0 +1,138 @@
|
|||||||
|
<?= view('components/print_header', ['printTitle' => '봉투 입고 현황', 'printShowApproval' => false]) ?>
|
||||||
|
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel no-print">
|
||||||
|
<div class="flex flex-wrap items-center justify-between gap-y-2">
|
||||||
|
<span class="text-sm font-bold text-gray-700">입고 현황</span>
|
||||||
|
<div class="flex items-center gap-2">
|
||||||
|
<a href="<?= base_url('bag/receiving/status/export') . '?' . http_build_query(array_filter(['start_date' => $startDate ?? '', 'end_date' => $endDate ?? '', 'company_idx' => $companyIdx ?? 0, 'bag_code' => $bagCode ?? '', 'receive_type' => $receiveType ?? ''])) ?>" class="border border-btn-excel-border text-btn-excel-text px-3 py-1 rounded-sm text-sm hover:bg-green-50">엑셀저장</a>
|
||||||
|
<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('bag/receiving/scanner') ?>" class="border border-gray-300 text-gray-700 px-3 py-1 rounded-sm text-sm hover:bg-gray-50">입고 처리</a>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<section class="p-2 bg-white border-b border-gray-200 no-print">
|
||||||
|
<form method="get" action="<?= base_url('bag/receiving/status') ?>" class="flex flex-wrap items-center gap-2">
|
||||||
|
<label class="text-sm text-gray-600">입고 기간</label>
|
||||||
|
<input type="date" name="start_date" value="<?= esc((string) ($startDate ?? '')) ?>" class="border border-gray-300 rounded px-2 py-1 text-sm" />
|
||||||
|
<span class="text-sm text-gray-500">~</span>
|
||||||
|
<input type="date" name="end_date" value="<?= esc((string) ($endDate ?? '')) ?>" class="border border-gray-300 rounded px-2 py-1 text-sm" />
|
||||||
|
|
||||||
|
<label class="text-sm text-gray-600 ml-2">제작 업체</label>
|
||||||
|
<select name="company_idx" class="border border-gray-300 rounded px-2 py-1 text-sm w-52">
|
||||||
|
<option value="0">전 체</option>
|
||||||
|
<?php foreach (($companies ?? []) as $company): ?>
|
||||||
|
<option value="<?= (int) $company->cp_idx ?>" <?= (int) ($companyIdx ?? 0) === (int) $company->cp_idx ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) ($company->cp_name ?? '')) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<label class="text-sm text-gray-600">품명</label>
|
||||||
|
<select name="bag_code" class="border border-gray-300 rounded px-2 py-1 text-sm w-44">
|
||||||
|
<option value="">전 체</option>
|
||||||
|
<?php foreach (($bagCodeOptions ?? []) as $bag): ?>
|
||||||
|
<option value="<?= esc((string) ($bag->cd_code ?? '')) ?>" <?= (string) ($bagCode ?? '') === (string) ($bag->cd_code ?? '') ? 'selected' : '' ?>>
|
||||||
|
<?= esc((string) ($bag->cd_name ?? '')) ?>
|
||||||
|
</option>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<label class="text-sm text-gray-600">입고 구분</label>
|
||||||
|
<select name="receive_type" class="border border-gray-300 rounded px-2 py-1 text-sm w-36">
|
||||||
|
<option value="all" <?= ($receiveType ?? 'all') === 'all' ? 'selected' : '' ?>>전 체</option>
|
||||||
|
<option value="completed" <?= ($receiveType ?? 'all') === 'completed' ? 'selected' : '' ?>>완료</option>
|
||||||
|
<option value="pending" <?= ($receiveType ?? 'all') === 'pending' ? 'selected' : '' ?>>미완료</option>
|
||||||
|
</select>
|
||||||
|
|
||||||
|
<button type="submit" class="bg-btn-search text-white px-4 py-1 rounded-sm text-sm">조회</button>
|
||||||
|
<a href="<?= base_url('bag/receiving/status') ?>" class="text-sm text-gray-500 hover:underline">초기화</a>
|
||||||
|
</form>
|
||||||
|
</section>
|
||||||
|
|
||||||
|
<div class="border border-gray-300 overflow-auto mt-2 receiving-status-print-wrap">
|
||||||
|
<table class="w-full data-table text-sm receiving-status-print-table">
|
||||||
|
<thead>
|
||||||
|
<tr>
|
||||||
|
<th>입고일자</th>
|
||||||
|
<th>품명</th>
|
||||||
|
<th>입고수량</th>
|
||||||
|
<th>발주일자</th>
|
||||||
|
<th>발주수량</th>
|
||||||
|
<th>발주번호</th>
|
||||||
|
<th>제작업체</th>
|
||||||
|
<th>입고여부</th>
|
||||||
|
<th>입고처</th>
|
||||||
|
<th>비고</th>
|
||||||
|
</tr>
|
||||||
|
</thead>
|
||||||
|
<tbody>
|
||||||
|
<?php
|
||||||
|
$prevDate = null;
|
||||||
|
$runningSum = 0;
|
||||||
|
?>
|
||||||
|
<?php foreach (($rows ?? []) as $i => $row): ?>
|
||||||
|
<?php
|
||||||
|
$d = (string) ($row['display_date'] ?? '');
|
||||||
|
if ($prevDate !== null && $d !== $prevDate):
|
||||||
|
?>
|
||||||
|
<tr class="bg-gray-50 font-semibold">
|
||||||
|
<td colspan="2" class="text-center">소 계</td>
|
||||||
|
<td class="text-right"><?= number_format($runningSum) ?></td>
|
||||||
|
<td colspan="7"></td>
|
||||||
|
</tr>
|
||||||
|
<?php
|
||||||
|
$runningSum = 0;
|
||||||
|
endif;
|
||||||
|
$runningSum += (int) ($row['received_qty_sheet'] ?? 0);
|
||||||
|
$prevDate = $d;
|
||||||
|
?>
|
||||||
|
<tr>
|
||||||
|
<td class="text-center"><?= esc($d) ?></td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($row['bag_name'] ?? '')) ?></td>
|
||||||
|
<td class="text-right"><?= number_format((int) ($row['received_qty_sheet'] ?? 0)) ?></td>
|
||||||
|
<td class="text-center"><?= esc((string) ($row['order_date'] ?? '')) ?></td>
|
||||||
|
<td class="text-right"><?= number_format((int) ($row['order_qty_sheet'] ?? 0)) ?></td>
|
||||||
|
<td class="text-center"><?= esc((string) ($row['order_no'] ?? '')) ?></td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($row['company_name'] ?? '')) ?></td>
|
||||||
|
<td class="text-center <?= ($row['receive_status_label'] ?? '') === '완료' ? 'text-red-600 font-bold' : 'text-blue-600 font-bold' ?>"><?= esc((string) ($row['receive_status_label'] ?? '')) ?></td>
|
||||||
|
<td class="text-left pl-2"><?= esc((string) ($row['agency_name'] ?? '')) ?></td>
|
||||||
|
<td></td>
|
||||||
|
</tr>
|
||||||
|
<?php endforeach; ?>
|
||||||
|
|
||||||
|
<?php if (! empty($rows ?? [])): ?>
|
||||||
|
<tr class="bg-gray-50 font-semibold">
|
||||||
|
<td colspan="2" class="text-center">소 계</td>
|
||||||
|
<td class="text-right"><?= number_format($runningSum) ?></td>
|
||||||
|
<td colspan="7"></td>
|
||||||
|
</tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
|
||||||
|
<?php if (empty($rows ?? [])): ?>
|
||||||
|
<tr><td colspan="10" class="text-center text-gray-400 py-4">조회 결과가 없습니다.</td></tr>
|
||||||
|
<?php endif; ?>
|
||||||
|
</tbody>
|
||||||
|
<tfoot>
|
||||||
|
<tr class="bg-gray-100 font-bold">
|
||||||
|
<td colspan="2" class="text-center">합 계</td>
|
||||||
|
<td class="text-right"><?= number_format((int) ($grandTotalReceive ?? 0)) ?></td>
|
||||||
|
<td colspan="7"></td>
|
||||||
|
</tr>
|
||||||
|
</tfoot>
|
||||||
|
</table>
|
||||||
|
</div>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
@media print {
|
||||||
|
.receiving-status-print-wrap {
|
||||||
|
overflow: visible !important;
|
||||||
|
border: none !important;
|
||||||
|
}
|
||||||
|
.receiving-status-print-table th,
|
||||||
|
.receiving-status-print-table td {
|
||||||
|
white-space: nowrap !important;
|
||||||
|
font-size: 10px !important;
|
||||||
|
padding: 2px 3px !important;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
</style>
|
||||||
Reference in New Issue
Block a user