455 lines
21 KiB
PHP
455 lines
21 KiB
PHP
|
|
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel">
|
||
|
|
<span class="text-sm font-bold text-gray-700">전화 주문 접수</span>
|
||
|
|
</section>
|
||
|
|
|
||
|
|
<div class="border border-gray-300 p-4 mt-2 bg-white">
|
||
|
|
<?php if (session()->getFlashdata('success')): ?>
|
||
|
|
<div class="mb-3 border border-emerald-300 bg-emerald-50 text-emerald-800 px-3 py-2 rounded-sm text-sm">
|
||
|
|
<?= esc(session()->getFlashdata('success')) ?>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php if (session()->getFlashdata('error')): ?>
|
||
|
|
<div class="mb-3 border border-red-300 bg-red-50 text-red-700 px-3 py-2 rounded-sm text-sm">
|
||
|
|
<?= esc(session()->getFlashdata('error')) ?>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
<?php $flashErrors = session()->getFlashdata('errors'); ?>
|
||
|
|
<?php if (is_array($flashErrors) && $flashErrors !== []): ?>
|
||
|
|
<div class="mb-3 border border-red-300 bg-red-50 text-red-700 px-3 py-2 rounded-sm text-sm">
|
||
|
|
<ul class="list-disc list-inside">
|
||
|
|
<?php foreach ($flashErrors as $err): ?>
|
||
|
|
<li><?= esc((string) $err) ?></li>
|
||
|
|
<?php endforeach; ?>
|
||
|
|
</ul>
|
||
|
|
</div>
|
||
|
|
<?php endif; ?>
|
||
|
|
<form action="<?= base_url('bag/shop-order/store') ?>" method="POST" class="space-y-4" id="phone-order-form">
|
||
|
|
<?= csrf_field() ?>
|
||
|
|
<input type="hidden" name="return_to" value="bag/order/phone"/>
|
||
|
|
|
||
|
|
<div class="grid grid-cols-1 xl:grid-cols-3 gap-4">
|
||
|
|
<div class="xl:col-span-2 space-y-3">
|
||
|
|
<div class="flex flex-wrap items-center gap-2">
|
||
|
|
<label class="block text-sm font-bold text-gray-700 w-28">판매소 검색</label>
|
||
|
|
<div class="relative flex-1 min-w-[20rem]">
|
||
|
|
<input id="shop-search" class="border border-gray-300 rounded px-3 py-1.5 text-sm w-[34rem] max-w-full" type="text" autocomplete="off" placeholder="코드/사업자번호/대표자명/상호/전화/주소 중 하나 입력"/>
|
||
|
|
<div id="shop-search-suggest" class="hidden absolute left-0 top-full mt-1 w-[48rem] max-w-[90vw] max-h-72 overflow-auto border border-gray-300 bg-white shadow-lg z-30"></div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="flex flex-wrap items-center gap-2">
|
||
|
|
<label class="block text-sm font-bold text-gray-700 w-28">판매소 선택 <span class="text-red-500">*</span></label>
|
||
|
|
<select id="shop-select" class="border border-gray-300 rounded px-3 py-1.5 text-sm w-[34rem] max-w-full" name="so_ds_idx" required>
|
||
|
|
<option value="">선택</option>
|
||
|
|
<?php foreach ($shops as $shop): ?>
|
||
|
|
<option
|
||
|
|
value="<?= esc($shop->ds_idx) ?>"
|
||
|
|
data-shop-no="<?= esc((string) ($shop->ds_shop_no ?? '')) ?>"
|
||
|
|
data-biz-no="<?= esc((string) ($shop->ds_biz_no ?? '')) ?>"
|
||
|
|
data-name="<?= esc((string) ($shop->ds_name ?? '')) ?>"
|
||
|
|
data-rep-name="<?= esc((string) ($shop->ds_rep_name ?? '')) ?>"
|
||
|
|
data-tel="<?= esc((string) ($shop->ds_tel ?? '')) ?>"
|
||
|
|
data-rep-phone="<?= esc((string) ($shop->ds_rep_phone ?? '')) ?>"
|
||
|
|
data-address="<?= esc(trim((string) ($shop->ds_addr ?? '') . ' ' . (string) ($shop->ds_addr_detail ?? ''))) ?>"
|
||
|
|
data-va-bank="<?= esc((string) ($shop->ds_va_bank ?? '')) ?>"
|
||
|
|
data-va-account="<?= esc((string) ($shop->ds_va_account ?? '')) ?>"
|
||
|
|
>
|
||
|
|
<?= esc(($shop->ds_shop_no ? '[' . $shop->ds_shop_no . '] ' : '') . $shop->ds_name) ?>
|
||
|
|
</option>
|
||
|
|
<?php endforeach; ?>
|
||
|
|
</select>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="border border-gray-300 p-2 bg-gray-50">
|
||
|
|
<div class="text-sm font-bold text-gray-700 mb-2">접수 정보</div>
|
||
|
|
<table class="w-full text-sm">
|
||
|
|
<tr><th class="text-left w-28 py-1">접수번호</th><td class="py-1 text-gray-800 font-semibold"><?= esc((string) ($receiptNo ?? 1)) ?></td></tr>
|
||
|
|
<tr><th class="text-left py-1">접수일</th><td class="py-1 text-gray-700"><?= esc(date('Y-m-d')) ?></td></tr>
|
||
|
|
<tr><th class="text-left py-1">배달일</th><td class="py-1 text-gray-700"><?= esc(date('Y-m-d', strtotime('+1 day'))) ?> (자동)</td></tr>
|
||
|
|
<tr><th class="text-left py-1">담당자</th><td class="py-1 text-gray-700"><?= esc((string) (session()->get('mb_name') ?? '담당자')) ?></td></tr>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="grid grid-cols-1 xl:grid-cols-2 gap-4">
|
||
|
|
<div class="border border-gray-300 p-2 bg-gray-50">
|
||
|
|
<div class="text-sm font-bold text-gray-700 mb-2">지정판매소 정보</div>
|
||
|
|
<table class="w-full text-sm">
|
||
|
|
<tr><th class="text-left w-28 py-1">코드</th><td id="shop-info-code" class="py-1 text-gray-700">-</td></tr>
|
||
|
|
<tr><th class="text-left py-1">사업자번호</th><td id="shop-info-biz" class="py-1 text-gray-700">-</td></tr>
|
||
|
|
<tr><th class="text-left py-1">대표자명</th><td id="shop-info-rep" class="py-1 text-gray-700">-</td></tr>
|
||
|
|
<tr><th class="text-left py-1">상호명</th><td id="shop-info-name" class="py-1 text-gray-700">-</td></tr>
|
||
|
|
<tr><th class="text-left py-1">전화번호</th><td id="shop-info-tel" class="py-1 text-gray-700">-</td></tr>
|
||
|
|
<tr><th class="text-left py-1">주소</th><td id="shop-info-addr" class="py-1 text-gray-700">-</td></tr>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<div class="border border-gray-300 p-2 bg-gray-50">
|
||
|
|
<div class="text-sm font-bold text-gray-700 mb-2">결제/가상계좌</div>
|
||
|
|
<div class="flex flex-wrap items-center gap-2 mb-2">
|
||
|
|
<label class="block text-sm font-bold text-gray-700 w-24">결제구분 <span class="text-red-500">*</span></label>
|
||
|
|
<select id="payment-type" class="border border-gray-300 rounded px-3 py-1.5 text-sm w-40" name="so_payment_type" required>
|
||
|
|
<option value="">선택</option>
|
||
|
|
<option value="이체">이체</option>
|
||
|
|
<option value="가상계좌">가상계좌</option>
|
||
|
|
</select>
|
||
|
|
<span id="payment-guide" class="text-xs text-gray-500"></span>
|
||
|
|
</div>
|
||
|
|
<div class="text-sm">
|
||
|
|
<span class="font-semibold text-gray-700">가상계좌:</span>
|
||
|
|
<span id="shop-info-va" class="text-gray-700">-</span>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<input type="hidden" name="so_delivery_date" value="<?= esc(date('Y-m-d', strtotime('+1 day'))) ?>"/>
|
||
|
|
|
||
|
|
<div class="mt-4">
|
||
|
|
<div class="flex items-center justify-between mb-2">
|
||
|
|
<label class="block text-sm font-bold text-gray-700">전화 주문접수표</label>
|
||
|
|
<button type="button" id="add-order-row" class="border border-gray-300 bg-white px-3 py-1 rounded-sm text-xs text-gray-700 hover:bg-gray-50">행 추가</button>
|
||
|
|
</div>
|
||
|
|
<div class="border border-gray-300 overflow-auto">
|
||
|
|
<table class="w-full data-table text-sm">
|
||
|
|
<thead>
|
||
|
|
<tr>
|
||
|
|
<th class="w-14">구분</th>
|
||
|
|
<th class="w-56">품목</th>
|
||
|
|
<th class="w-40">1박스(낱장/판매가)</th>
|
||
|
|
<th class="w-40">1팩(낱장/판매가)</th>
|
||
|
|
<th class="w-24">단가</th>
|
||
|
|
<th class="w-28">주문수량</th>
|
||
|
|
<th class="w-28">금액</th>
|
||
|
|
<th class="w-44">포장(박스/팩/낱장)</th>
|
||
|
|
<th class="w-20">삭제</th>
|
||
|
|
</tr>
|
||
|
|
</thead>
|
||
|
|
<tbody id="order-rows">
|
||
|
|
<?php for ($i = 0; $i < 3; $i++): ?>
|
||
|
|
<tr class="order-row">
|
||
|
|
<td class="text-center item-kind-cell">-</td>
|
||
|
|
<td>
|
||
|
|
<select class="border border-gray-300 rounded px-2 py-1 text-sm w-full bag-code-select" name="item_bag_code[]">
|
||
|
|
<option value="">선택</option>
|
||
|
|
<?php foreach ($bagCodes as $cd): ?>
|
||
|
|
<?php
|
||
|
|
$code = (string) $cd->cd_code;
|
||
|
|
$name = (string) ($cd->cd_name ?? '');
|
||
|
|
$price = $priceMap[$code] ?? null;
|
||
|
|
$unit = $unitMap[$code] ?? null;
|
||
|
|
$unitPrice = (int) ($price->bp_consumer ?? 0);
|
||
|
|
$boxSheets = (int) ($unit->pu_total_per_box ?? 0);
|
||
|
|
$packSheets = (int) ($unit->pu_pack_per_sheet ?? 0);
|
||
|
|
$kindLabel = (mb_strpos($name, '스티커') !== false) ? '스티커' : '봉투';
|
||
|
|
?>
|
||
|
|
<option value="<?= esc($code) ?>" data-name="<?= esc($name, 'attr') ?>" data-kind-label="<?= esc($kindLabel, 'attr') ?>" data-unit-price="<?= esc((string) $unitPrice, 'attr') ?>" data-box-sheets="<?= esc((string) $boxSheets, 'attr') ?>" data-pack-sheets="<?= esc((string) $packSheets, 'attr') ?>">
|
||
|
|
<?= esc($code) ?> — <?= esc($name) ?>
|
||
|
|
</option>
|
||
|
|
<?php endforeach; ?>
|
||
|
|
</select>
|
||
|
|
</td>
|
||
|
|
<td class="text-right px-2 box-info-cell">0 / 0</td>
|
||
|
|
<td class="text-right px-2 pack-info-cell">0 / 0</td>
|
||
|
|
<td class="text-right px-2 unit-price-cell">0</td>
|
||
|
|
<td><input class="border border-gray-300 rounded px-2 py-1 text-sm w-full text-right item-qty-input" name="item_qty[]" type="number" min="0" value="0"/></td>
|
||
|
|
<td class="text-right px-2 item-amount-cell">0</td>
|
||
|
|
<td class="text-right px-2 pack-result-cell">박스=0, 팩=0, 낱장=0</td>
|
||
|
|
<td class="text-center px-2">
|
||
|
|
<button type="button" class="remove-order-row border border-red-300 text-red-600 px-2 py-0.5 rounded text-xs hover:bg-red-50">삭제</button>
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
<?php endfor; ?>
|
||
|
|
</tbody>
|
||
|
|
<tfoot>
|
||
|
|
<tr class="font-semibold bg-gray-50">
|
||
|
|
<td colspan="5" class="text-right px-2 py-1">합계</td>
|
||
|
|
<td class="text-right px-2 py-1" id="sum-qty">0</td>
|
||
|
|
<td class="text-right px-2 py-1" id="sum-amount">0</td>
|
||
|
|
<td class="text-right px-2 py-1" id="sum-pack">박스=0, 팩=0, 낱장=0</td>
|
||
|
|
<td></td>
|
||
|
|
</tr>
|
||
|
|
</tfoot>
|
||
|
|
</table>
|
||
|
|
</div>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<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/sales') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
|
||
|
|
</div>
|
||
|
|
</form>
|
||
|
|
</div>
|
||
|
|
|
||
|
|
<template id="order-row-template">
|
||
|
|
<tr class="order-row">
|
||
|
|
<td class="text-center item-kind-cell">-</td>
|
||
|
|
<td>
|
||
|
|
<select class="border border-gray-300 rounded px-2 py-1 text-sm w-full bag-code-select" name="item_bag_code[]">
|
||
|
|
<option value="">선택</option>
|
||
|
|
<?php foreach ($bagCodes as $cd): ?>
|
||
|
|
<?php
|
||
|
|
$code = (string) $cd->cd_code;
|
||
|
|
$name = (string) ($cd->cd_name ?? '');
|
||
|
|
$price = $priceMap[$code] ?? null;
|
||
|
|
$unit = $unitMap[$code] ?? null;
|
||
|
|
$unitPrice = (int) ($price->bp_consumer ?? 0);
|
||
|
|
$boxSheets = (int) ($unit->pu_total_per_box ?? 0);
|
||
|
|
$packSheets = (int) ($unit->pu_pack_per_sheet ?? 0);
|
||
|
|
$kindLabel = (mb_strpos($name, '스티커') !== false) ? '스티커' : '봉투';
|
||
|
|
?>
|
||
|
|
<option value="<?= esc($code) ?>" data-name="<?= esc($name, 'attr') ?>" data-kind-label="<?= esc($kindLabel, 'attr') ?>" data-unit-price="<?= esc((string) $unitPrice, 'attr') ?>" data-box-sheets="<?= esc((string) $boxSheets, 'attr') ?>" data-pack-sheets="<?= esc((string) $packSheets, 'attr') ?>">
|
||
|
|
<?= esc($code) ?> — <?= esc($name) ?>
|
||
|
|
</option>
|
||
|
|
<?php endforeach; ?>
|
||
|
|
</select>
|
||
|
|
</td>
|
||
|
|
<td class="text-right px-2 box-info-cell">0 / 0</td>
|
||
|
|
<td class="text-right px-2 pack-info-cell">0 / 0</td>
|
||
|
|
<td class="text-right px-2 unit-price-cell">0</td>
|
||
|
|
<td><input class="border border-gray-300 rounded px-2 py-1 text-sm w-full text-right item-qty-input" name="item_qty[]" type="number" min="0" value="0"/></td>
|
||
|
|
<td class="text-right px-2 item-amount-cell">0</td>
|
||
|
|
<td class="text-right px-2 pack-result-cell">박스=0, 팩=0, 낱장=0</td>
|
||
|
|
<td class="text-center px-2">
|
||
|
|
<button type="button" class="remove-order-row border border-red-300 text-red-600 px-2 py-0.5 rounded text-xs hover:bg-red-50">삭제</button>
|
||
|
|
</td>
|
||
|
|
</tr>
|
||
|
|
</template>
|
||
|
|
|
||
|
|
<script>
|
||
|
|
(() => {
|
||
|
|
const shopSearch = document.getElementById('shop-search');
|
||
|
|
const shopSelect = document.getElementById('shop-select');
|
||
|
|
const shopSuggest = document.getElementById('shop-search-suggest');
|
||
|
|
const paymentType = document.getElementById('payment-type');
|
||
|
|
const paymentGuide = document.getElementById('payment-guide');
|
||
|
|
const addRowButton = document.getElementById('add-order-row');
|
||
|
|
const orderRows = document.getElementById('order-rows');
|
||
|
|
const rowTemplate = document.getElementById('order-row-template');
|
||
|
|
const form = document.getElementById('phone-order-form');
|
||
|
|
|
||
|
|
const nf = (n) => new Intl.NumberFormat('ko-KR').format(n || 0);
|
||
|
|
|
||
|
|
function updateShopInfo() {
|
||
|
|
const opt = shopSelect.options[shopSelect.selectedIndex];
|
||
|
|
const bank = opt?.dataset?.vaBank || '';
|
||
|
|
const account = opt?.dataset?.vaAccount || '';
|
||
|
|
const va = bank || account ? [bank, account].filter(Boolean).join(' ') : '-';
|
||
|
|
|
||
|
|
document.getElementById('shop-info-code').textContent = opt?.dataset?.shopNo || '-';
|
||
|
|
document.getElementById('shop-info-biz').textContent = opt?.dataset?.bizNo || '-';
|
||
|
|
document.getElementById('shop-info-rep').textContent = opt?.dataset?.repName || '-';
|
||
|
|
document.getElementById('shop-info-name').textContent = opt?.dataset?.name || '-';
|
||
|
|
document.getElementById('shop-info-tel').textContent = opt?.dataset?.tel || opt?.dataset?.repPhone || '-';
|
||
|
|
document.getElementById('shop-info-addr').textContent = opt?.dataset?.address || '-';
|
||
|
|
document.getElementById('shop-info-va').textContent = va;
|
||
|
|
paymentGuide.textContent = paymentType.value === '가상계좌' ? ('안내 계좌: ' + va) : '';
|
||
|
|
}
|
||
|
|
|
||
|
|
function shopMergedText(opt) {
|
||
|
|
return [
|
||
|
|
opt.dataset.shopNo || '',
|
||
|
|
opt.dataset.bizNo || '',
|
||
|
|
opt.dataset.repName || '',
|
||
|
|
opt.dataset.name || '',
|
||
|
|
opt.dataset.tel || '',
|
||
|
|
opt.dataset.address || '',
|
||
|
|
].filter(Boolean).join(' ');
|
||
|
|
}
|
||
|
|
|
||
|
|
function matchShopByKeyword(keyword) {
|
||
|
|
const q = (keyword || '').trim().toLowerCase();
|
||
|
|
if (!q) return;
|
||
|
|
for (let i = 0; i < shopSelect.options.length; i++) {
|
||
|
|
const opt = shopSelect.options[i];
|
||
|
|
if (!opt.value) continue;
|
||
|
|
const merged = (shopMergedText(opt) + ' ' + (opt.text || '')).toLowerCase();
|
||
|
|
if (merged.includes(q)) {
|
||
|
|
shopSelect.selectedIndex = i;
|
||
|
|
updateShopInfo();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
function hideSuggest() {
|
||
|
|
if (!shopSuggest) return;
|
||
|
|
shopSuggest.classList.add('hidden');
|
||
|
|
shopSuggest.innerHTML = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
function renderSuggest(query) {
|
||
|
|
if (!shopSuggest || !shopSelect) return;
|
||
|
|
const q = (query || '').trim().toLowerCase();
|
||
|
|
const matched = [];
|
||
|
|
for (let i = 0; i < shopSelect.options.length; i++) {
|
||
|
|
const opt = shopSelect.options[i];
|
||
|
|
if (!opt.value) continue;
|
||
|
|
const merged = shopMergedText(opt);
|
||
|
|
if (!q || merged.toLowerCase().includes(q)) {
|
||
|
|
matched.push({ index: i, label: merged });
|
||
|
|
}
|
||
|
|
if (matched.length >= 50) break;
|
||
|
|
}
|
||
|
|
if (matched.length === 0) {
|
||
|
|
hideSuggest();
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
shopSuggest.innerHTML = matched.map((m) => `
|
||
|
|
<button type="button" class="shop-suggest-item w-full text-left px-2 py-1.5 hover:bg-blue-50 text-xs border-b border-gray-100 whitespace-normal break-all" data-index="${m.index}">${m.label}</button>
|
||
|
|
`).join('');
|
||
|
|
shopSuggest.classList.remove('hidden');
|
||
|
|
}
|
||
|
|
|
||
|
|
function calcRow(row) {
|
||
|
|
const select = row.querySelector('.bag-code-select');
|
||
|
|
const qtyInput = row.querySelector('.item-qty-input');
|
||
|
|
const selected = select.options[select.selectedIndex];
|
||
|
|
|
||
|
|
const qty = parseInt(qtyInput.value || '0', 10) || 0;
|
||
|
|
const unitPrice = parseInt(selected?.dataset?.unitPrice || '0', 10) || 0;
|
||
|
|
const boxSheets = parseInt(selected?.dataset?.boxSheets || '0', 10) || 0;
|
||
|
|
const packSheets = parseInt(selected?.dataset?.packSheets || '0', 10) || 0;
|
||
|
|
const kindLabel = selected?.dataset?.kindLabel || '-';
|
||
|
|
|
||
|
|
let box = 0;
|
||
|
|
let pack = 0;
|
||
|
|
let sheet = qty;
|
||
|
|
if (boxSheets > 0) {
|
||
|
|
box = Math.floor(qty / boxSheets);
|
||
|
|
const remain = qty % boxSheets;
|
||
|
|
if (packSheets > 0) {
|
||
|
|
pack = Math.floor(remain / packSheets);
|
||
|
|
sheet = remain % packSheets;
|
||
|
|
} else {
|
||
|
|
sheet = remain;
|
||
|
|
}
|
||
|
|
} else if (packSheets > 0) {
|
||
|
|
pack = Math.floor(qty / packSheets);
|
||
|
|
sheet = qty % packSheets;
|
||
|
|
}
|
||
|
|
|
||
|
|
const amount = unitPrice * qty;
|
||
|
|
const boxPrice = boxSheets * unitPrice;
|
||
|
|
const packPrice = packSheets * unitPrice;
|
||
|
|
|
||
|
|
row.querySelector('.item-kind-cell').textContent = kindLabel;
|
||
|
|
row.querySelector('.box-info-cell').textContent = nf(boxSheets) + ' / ' + nf(boxPrice);
|
||
|
|
row.querySelector('.pack-info-cell').textContent = nf(packSheets) + ' / ' + nf(packPrice);
|
||
|
|
row.querySelector('.unit-price-cell').textContent = nf(unitPrice);
|
||
|
|
row.querySelector('.item-amount-cell').textContent = nf(amount);
|
||
|
|
row.querySelector('.pack-result-cell').textContent = '박스=' + nf(box) + ', 팩=' + nf(pack) + ', 낱장=' + nf(sheet);
|
||
|
|
|
||
|
|
return { qty, amount, box, pack, sheet };
|
||
|
|
}
|
||
|
|
|
||
|
|
function recalcAllRows() {
|
||
|
|
let sumQty = 0, sumAmount = 0, sumBox = 0, sumPack = 0, sumSheet = 0;
|
||
|
|
document.querySelectorAll('.order-row').forEach((row) => {
|
||
|
|
const r = calcRow(row);
|
||
|
|
sumQty += r.qty;
|
||
|
|
sumAmount += r.amount;
|
||
|
|
sumBox += r.box;
|
||
|
|
sumPack += r.pack;
|
||
|
|
sumSheet += r.sheet;
|
||
|
|
});
|
||
|
|
document.getElementById('sum-qty').textContent = nf(sumQty);
|
||
|
|
document.getElementById('sum-amount').textContent = nf(sumAmount);
|
||
|
|
document.getElementById('sum-pack').textContent = '박스=' + nf(sumBox) + ', 팩=' + nf(sumPack) + ', 낱장=' + nf(sumSheet);
|
||
|
|
}
|
||
|
|
|
||
|
|
function clearSearchInputOnly() {
|
||
|
|
if (shopSearch) shopSearch.value = '';
|
||
|
|
}
|
||
|
|
|
||
|
|
// 판매소 검색 input을 다시 누르면(또는 포커스를 다시 받으면) 검색 input 텍스트만 비운다.
|
||
|
|
// 기존에 선택된 판매소 정보(셀렉트, 지정판매소 정보, 가상계좌 등)는 그대로 유지한다.
|
||
|
|
shopSearch?.addEventListener('focus', () => {
|
||
|
|
if (shopSelect && shopSelect.value) clearSearchInputOnly();
|
||
|
|
renderSuggest('');
|
||
|
|
});
|
||
|
|
shopSearch?.addEventListener('mousedown', () => {
|
||
|
|
if (shopSelect && shopSelect.value) clearSearchInputOnly();
|
||
|
|
});
|
||
|
|
shopSearch?.addEventListener('click', () => renderSuggest(shopSearch.value || ''));
|
||
|
|
shopSearch?.addEventListener('input', (e) => renderSuggest(e.target.value || ''));
|
||
|
|
|
||
|
|
shopSuggest?.addEventListener('mousedown', (e) => {
|
||
|
|
const btn = e.target.closest('.shop-suggest-item');
|
||
|
|
if (!btn) return;
|
||
|
|
e.preventDefault();
|
||
|
|
const idx = Number(btn.dataset.index || -1);
|
||
|
|
if (!Number.isInteger(idx) || idx < 0 || idx >= shopSelect.options.length) return;
|
||
|
|
shopSelect.selectedIndex = idx;
|
||
|
|
const opt = shopSelect.options[idx];
|
||
|
|
shopSearch.value = shopMergedText(opt);
|
||
|
|
updateShopInfo();
|
||
|
|
hideSuggest();
|
||
|
|
});
|
||
|
|
|
||
|
|
document.addEventListener('click', (e) => {
|
||
|
|
if (!shopSuggest || !shopSearch) return;
|
||
|
|
if (e.target === shopSearch || shopSuggest.contains(e.target)) return;
|
||
|
|
hideSuggest();
|
||
|
|
});
|
||
|
|
|
||
|
|
shopSearch?.addEventListener('change', (e) => matchShopByKeyword(e.target.value));
|
||
|
|
shopSearch?.addEventListener('blur', () => {
|
||
|
|
// 자동완성 클릭이 우선되도록 약간 지연.
|
||
|
|
setTimeout(() => {
|
||
|
|
matchShopByKeyword(shopSearch.value || '');
|
||
|
|
}, 150);
|
||
|
|
});
|
||
|
|
shopSelect?.addEventListener('change', updateShopInfo);
|
||
|
|
paymentType?.addEventListener('change', updateShopInfo);
|
||
|
|
|
||
|
|
orderRows?.addEventListener('change', function (e) {
|
||
|
|
if (e.target.closest('.bag-code-select') || e.target.closest('.item-qty-input')) {
|
||
|
|
recalcAllRows();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
orderRows?.addEventListener('input', function (e) {
|
||
|
|
if (e.target.closest('.item-qty-input')) {
|
||
|
|
recalcAllRows();
|
||
|
|
}
|
||
|
|
});
|
||
|
|
orderRows?.addEventListener('click', function (e) {
|
||
|
|
const removeButton = e.target.closest('.remove-order-row');
|
||
|
|
if (!removeButton) return;
|
||
|
|
const row = removeButton.closest('.order-row');
|
||
|
|
if (!row) return;
|
||
|
|
if (orderRows.querySelectorAll('.order-row').length <= 1) {
|
||
|
|
alert('최소 1개 행은 유지해야 합니다.');
|
||
|
|
return;
|
||
|
|
}
|
||
|
|
row.remove();
|
||
|
|
recalcAllRows();
|
||
|
|
});
|
||
|
|
|
||
|
|
addRowButton?.addEventListener('click', function () {
|
||
|
|
if (!rowTemplate || !orderRows) return;
|
||
|
|
const fragment = rowTemplate.content.cloneNode(true);
|
||
|
|
orderRows.appendChild(fragment);
|
||
|
|
recalcAllRows();
|
||
|
|
});
|
||
|
|
|
||
|
|
form?.addEventListener('submit', function (e) {
|
||
|
|
let hasItem = false;
|
||
|
|
document.querySelectorAll('.order-row').forEach((row) => {
|
||
|
|
const code = row.querySelector('.bag-code-select').value;
|
||
|
|
const qty = parseInt(row.querySelector('.item-qty-input').value || '0', 10) || 0;
|
||
|
|
if (code && qty > 0) hasItem = true;
|
||
|
|
});
|
||
|
|
if (!hasItem) {
|
||
|
|
e.preventDefault();
|
||
|
|
alert('주문 품목과 수량을 1개 이상 입력해 주세요.');
|
||
|
|
}
|
||
|
|
});
|
||
|
|
|
||
|
|
updateShopInfo();
|
||
|
|
recalcAllRows();
|
||
|
|
})();
|
||
|
|
</script>
|
||
|
|
|
||
|
|
<?= view('bag/_dev_all_sales_panel') ?>
|