feat: 전화접수 관리·주문 개선 + 매뉴얼 화면 바로가기
- 전화접수 관리: 배달일 기준 조회, 컬럼 보강(구분/포장 O·X/결제/수령/입금/총금액/취소), 헤더 정렬, 배달일 수정 저장, 포장 명세·포장량 수정, 입금자 영수증 출력 - 전화 주문 접수: 행추가 → 일괄표(카테고리 그룹·포장 헤더) - 매뉴얼 소제목에 '화면 열기' 바로가기(실제 GET 라우트만 연결) - shop_order_item.soi_packed_qty 컬럼 추가(SQL) Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
This commit is contained in:
@@ -3614,11 +3614,36 @@ SQL);
|
||||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound('매뉴얼 문서를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
// 이 매뉴얼 페이지가 설명하는 화면 → 바로가기 링크(screenHelp 역방향).
|
||||
// screenHelp 에는 "현재경로 매칭"용 비(非)라우트 prefix(bag/sale, bag/order 등)도 섞여 있어
|
||||
// 그대로 쓰면 404가 난다. 같은 소제목(hint)의 후보 중 "실제 GET 라우트"인 첫 경로만 채택.
|
||||
$routeCollection = service('routes');
|
||||
$routeCollection->loadRoutes();
|
||||
$validGet = $routeCollection->getRoutes('GET'); // [경로 => 핸들러] (정적 경로는 키가 곧 경로)
|
||||
|
||||
$screenHelp = config(\Config\Manual::class)->screenHelp ?? [];
|
||||
$jumpByHint = [];
|
||||
foreach ($screenHelp as $path => $val) {
|
||||
[$pSlug, $hint] = array_pad(explode('#', (string) $val, 2), 2, null);
|
||||
if ($pSlug !== $slug || $hint === null || trim($hint) === '') {
|
||||
continue;
|
||||
}
|
||||
if (isset($jumpByHint[$hint]) || ! isset($validGet[(string) $path])) {
|
||||
continue; // 이미 채택했거나, 실제 라우트가 아니면 건너뜀
|
||||
}
|
||||
$jumpByHint[$hint] = (string) $path;
|
||||
}
|
||||
$jumps = [];
|
||||
foreach ($jumpByHint as $hint => $path) {
|
||||
$jumps[] = ['hint' => $hint, 'url' => base_url($path)];
|
||||
}
|
||||
|
||||
return $this->render('사용자 매뉴얼 · ' . $page['title'], 'bag/manual', [
|
||||
'pages' => $renderer->pages(),
|
||||
'current' => $slug,
|
||||
'title' => $page['title'],
|
||||
'body' => $body,
|
||||
'jumps' => $jumps,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -7022,7 +7047,7 @@ SQL;
|
||||
return redirect()->to(site_url('bag/sales'))->with('error', '지자체를 선택해 주세요.');
|
||||
}
|
||||
|
||||
// 일자별·기간별 조회 (접수일 so_order_date 기준)
|
||||
// 일자별·기간별 조회 (배달일 so_delivery_date 기준)
|
||||
$startDate = trim((string) ($this->request->getGet('start_date') ?? ''));
|
||||
$endDate = trim((string) ($this->request->getGet('end_date') ?? ''));
|
||||
$isYmd = static fn (string $d): bool => preg_match('/^\d{4}-\d{2}-\d{2}$/', $d) === 1;
|
||||
@@ -7037,10 +7062,10 @@ SQL;
|
||||
$builder->where('so_channel', 'phone');
|
||||
}
|
||||
if ($isYmd($startDate)) {
|
||||
$builder->where('so_order_date >=', $startDate);
|
||||
$builder->where('so_delivery_date >=', $startDate);
|
||||
}
|
||||
if ($isYmd($endDate)) {
|
||||
$builder->where('so_order_date <=', $endDate . ' 23:59:59');
|
||||
$builder->where('so_delivery_date <=', $endDate . ' 23:59:59');
|
||||
}
|
||||
$orders = $builder->orderBy('so_idx', 'DESC')->limit(200)->findAll();
|
||||
|
||||
@@ -7100,6 +7125,7 @@ SQL;
|
||||
'soi_bag_name' => (string) ($item->soi_bag_name ?? ''),
|
||||
'soi_unit_price' => (int) ($item->soi_unit_price ?? 0),
|
||||
'soi_qty' => (int) ($item->soi_qty ?? 0),
|
||||
'soi_packed_qty' => (int) ($item->soi_packed_qty ?? 0),
|
||||
'soi_amount' => (int) ($item->soi_amount ?? 0),
|
||||
'soi_box_count' => (int) ($item->soi_box_count ?? 0),
|
||||
'soi_pack_count' => (int) ($item->soi_pack_count ?? 0),
|
||||
@@ -7124,7 +7150,10 @@ SQL;
|
||||
'ds_addr' => $shop['addr'],
|
||||
'so_order_date' => (string) ($order->so_order_date ?? ''),
|
||||
'so_delivery_date' => (string) ($order->so_delivery_date ?? ''),
|
||||
'so_channel' => (string) ($order->so_channel ?? ''),
|
||||
'so_payment_type' => (string) ($order->so_payment_type ?? ''),
|
||||
'so_received' => (int) ($order->so_received ?? 0),
|
||||
'so_paid' => (int) ($order->so_paid ?? 0),
|
||||
'so_total_qty' => (int) ($order->so_total_qty ?? 0),
|
||||
'so_total_amount' => (int) ($order->so_total_amount ?? 0),
|
||||
'so_status' => (string) ($order->so_status ?? 'normal'),
|
||||
@@ -7139,6 +7168,47 @@ SQL;
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 입금자 영수증 출력용 — 단일 접수건의 인쇄용 영수증(독립 HTML, 자동 인쇄).
|
||||
*/
|
||||
public function phoneOrderReceipt(int $id): string|RedirectResponse
|
||||
{
|
||||
helper('admin');
|
||||
$lgIdx = $this->lgIdx();
|
||||
if (! $lgIdx) {
|
||||
return redirect()->to(site_url('bag/order/phone/manage'))->with('error', '지자체를 선택해 주세요.');
|
||||
}
|
||||
|
||||
$order = model(ShopOrderModel::class)->where('so_idx', $id)->where('so_lg_idx', $lgIdx)->first();
|
||||
if (! $order) {
|
||||
throw \CodeIgniter\Exceptions\PageNotFoundException::forPageNotFound();
|
||||
}
|
||||
|
||||
$items = model(ShopOrderItemModel::class)
|
||||
->where('soi_so_idx', $id)
|
||||
->orderBy('soi_idx', 'ASC')
|
||||
->findAll();
|
||||
|
||||
$shop = null;
|
||||
$dsIdx = (int) ($order->so_ds_idx ?? 0);
|
||||
if ($dsIdx > 0) {
|
||||
$shop = \Config\Database::connect()->table('designated_shop')
|
||||
->select('ds_shop_no, ds_name, ds_rep_name, ds_tel, ds_addr, ds_addr_detail')
|
||||
->where('ds_idx', $dsIdx)
|
||||
->get()->getRowArray();
|
||||
}
|
||||
|
||||
$lgRow = model(\App\Models\LocalGovernmentModel::class)->find($lgIdx);
|
||||
$lgName = $lgRow ? (string) $lgRow->lg_name : '';
|
||||
|
||||
return view('bag/order_phone_receipt', [
|
||||
'order' => $order,
|
||||
'items' => $items,
|
||||
'shop' => $shop,
|
||||
'lgName' => $lgName,
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 전화 주문 상세 품목 수량 수정 저장.
|
||||
*/
|
||||
@@ -7174,6 +7244,10 @@ SQL;
|
||||
if (! is_array($qtyInput)) {
|
||||
$qtyInput = [];
|
||||
}
|
||||
$packedInput = $this->request->getPost('item_packed') ?? [];
|
||||
if (! is_array($packedInput)) {
|
||||
$packedInput = [];
|
||||
}
|
||||
|
||||
$codeSet = [];
|
||||
foreach ($items as $item) {
|
||||
@@ -7230,8 +7304,10 @@ SQL;
|
||||
$sheetCount = $qty % $packSheets;
|
||||
}
|
||||
|
||||
$packedQty = isset($packedInput[$itemId]) ? max(0, (int) $packedInput[$itemId]) : (int) ($item->soi_packed_qty ?? 0);
|
||||
$itemModel->update($itemId, [
|
||||
'soi_qty' => $qty,
|
||||
'soi_packed_qty' => $packedQty,
|
||||
'soi_amount' => $amount,
|
||||
'soi_box_count' => $boxCount,
|
||||
'soi_pack_count' => $packCount,
|
||||
|
||||
Reference in New Issue
Block a user