, defaultSenderIdx: int} */ private function receivingManagerPickers(int $lgIdx): array { $senders = model(ManagerModel::class, false) ->where('mg_lg_idx', $lgIdx) ->where('mg_state', 1) ->where('mg_dept_code', 'company') ->orderBy('mg_name', 'ASC') ->findAll(); $sessionName = trim((string) (session()->get('mb_name') ?? '')); $defaultSenderIdx = 0; foreach ($senders as $s) { if ((string) ($s->mg_name ?? '') === $sessionName) { $defaultSenderIdx = (int) ($s->mg_idx ?? 0); break; } } if ($defaultSenderIdx <= 0 && $senders !== []) { $defaultSenderIdx = (int) ($senders[0]->mg_idx ?? 0); } return [ 'senders' => $senders, 'defaultSenderIdx' => $defaultSenderIdx, ]; } /** * 인수자 드롭다운: 맨 위에 현재 로그인 회원, 이어서 대행소(agency) 담당자. * value 는 br_receiver_ref 로 전달: m_{mb_idx} | g_{mg_idx} * * @return array{receiverOptions: list, defaultReceiverRef: string} */ private function receivingReceiverSelect(int $lgIdx): array { $sessionMbIdx = (int) (session()->get('mb_idx') ?? 0); $sessionName = trim((string) (session()->get('mb_name') ?? '')); $normalizeName = static fn (string $name): string => preg_replace('/\s+/u', '', trim($name)) ?? ''; $normSession = $normalizeName($sessionName); $options = []; if ($sessionMbIdx > 0) { $label = $sessionName !== '' ? $sessionName : '로그인 사용자'; $options[] = ['ref' => 'm_' . $sessionMbIdx, 'label' => $label]; } $agencyManagers = model(ManagerModel::class, false) ->where('mg_lg_idx', $lgIdx) ->where('mg_state', 1) ->where('mg_dept_code', 'agency') ->orderBy('mg_name', 'ASC') ->findAll(); foreach ($agencyManagers as $rcv) { $mgIdx = (int) ($rcv->mg_idx ?? 0); $receiverName = trim((string) ($rcv->mg_name ?? '')); if ($mgIdx <= 0) { continue; } if ($normSession !== '' && $normalizeName($receiverName) === $normSession) { continue; } $options[] = ['ref' => 'g_' . $mgIdx, 'label' => $receiverName]; } $defaultRef = $options !== [] ? (string) ($options[0]['ref'] ?? '') : ''; return [ 'receiverOptions' => $options, 'defaultReceiverRef' => $defaultRef, ]; } /** * @param list $options */ private function sanitizeReceiverRef(array $options, string $ref): string { foreach ($options as $opt) { if (($opt['ref'] ?? '') === $ref) { return $ref; } } return ''; } private function parseReceiverRefToStoredIdx(int $lgIdx, string $ref): int { $ref = trim($ref); if (preg_match('/^m_(\d+)$/', $ref, $mm)) { $mbIdx = (int) $mm[1]; if ($mbIdx <= 0 || $mbIdx !== (int) (session()->get('mb_idx') ?? 0)) { return 0; } return $mbIdx; } if (preg_match('/^g_(\d+)$/', $ref, $mg)) { return $this->assertAgencyReceiverIdx($lgIdx, (int) $mg[1]); } return 0; } private function assertAgencyReceiverIdx(int $lgIdx, int $mgIdx): int { if ($mgIdx <= 0) { return 0; } $row = model(ManagerModel::class, false)->where([ 'mg_idx' => $mgIdx, 'mg_lg_idx' => $lgIdx, 'mg_state' => 1, 'mg_dept_code' => 'agency', ])->first(); return $row ? $mgIdx : 0; } private function resolveCompanySenderName(int $lgIdx, int $mgIdx): string { if ($mgIdx <= 0) { return ''; } $row = model(ManagerModel::class, false)->where([ 'mg_idx' => $mgIdx, 'mg_lg_idx' => $lgIdx, 'mg_state' => 1, 'mg_dept_code' => 'company', ])->first(); return $row ? trim((string) ($row->mg_name ?? '')) : ''; } private function render(string $title, string $viewFile, array $data = []): string { return view('bag/layout/main', [ 'title' => $title, 'content' => view($viewFile, $data), ]); } // ────────────────────────────────────────────── // 기본정보관리 (단가·포장 단위 진입 허브) // ────────────────────────────────────────────── public function basicInfo(): string { return $this->render('기본정보관리', 'bag/basic_info', []); } /** 봉투 단가 조회 (사이트) — 기간·봉투구분·봉투코드 필터, 적용기간 겹침, 페이징·인쇄 */ public function prices(): string|RedirectResponse { helper('admin'); if ($this->request->is('post')) { $post = $this->request->getPost(); $pick = static function (array $src, string $key): ?string { if (! array_key_exists($key, $src)) { return null; } $v = $src[$key]; if ($v === null || is_array($v)) { return null; } $s = trim((string) $v); return $s === '' ? null : $s; }; session()->setFlashdata('bag_prices_filter', [ 'start_y' => $pick($post, 'start_y'), 'start_m' => $pick($post, 'start_m'), 'start_d' => $pick($post, 'start_d'), 'end_y' => $pick($post, 'end_y'), 'end_m' => $pick($post, 'end_m'), 'end_d' => $pick($post, 'end_d'), 'bag_kind_e' => $pick($post, 'bag_kind_e'), 'bag_code' => $pick($post, 'bag_code'), ]); return redirect()->to(site_url('bag/prices')); } $lgIdx = $this->lgIdx(); $bagPrices = []; $get = $this->request->getGet(); $flash = session()->getFlashdata('bag_prices_filter'); $readSrc = static function (array $src, string $key): ?string { if (! array_key_exists($key, $src)) { return null; } $v = $src[$key]; if ($v === null || is_array($v)) { return null; } $s = trim((string) $v); return $s === '' ? null : $s; }; $filterKeys = [ 'start_y', 'start_m', 'start_d', 'end_y', 'end_m', 'end_d', 'bag_kind_e', 'bag_code', 'start_date', 'end_date', ]; $hasExplicitGetFilter = false; foreach ($filterKeys as $fk) { $v = $get[$fk] ?? null; if ($v !== null && ! is_array($v) && trim((string) $v) !== '') { $hasExplicitGetFilter = true; break; } } $src = []; if ($hasExplicitGetFilter) { $src = $get; } elseif (is_array($flash)) { $src = $flash; } $sy = $readSrc($src, 'start_y'); $sm = $readSrc($src, 'start_m'); $sd = $readSrc($src, 'start_d'); $ey = $readSrc($src, 'end_y'); $em = $readSrc($src, 'end_m'); $ed = $readSrc($src, 'end_d'); $startDate = null; if ($sy !== null && $sy !== '' && $sm !== null && $sm !== '' && $sd !== null && $sd !== '') { $startDate = parse_ymd_from_triple($sy, $sm, $sd); } if ($startDate === null) { $g = $readSrc($src, 'start_date'); $startDate = ($g !== null && $g !== '') ? $g : null; } $endDate = null; if ($ey !== null && $ey !== '' && $em !== null && $em !== '' && $ed !== null && $ed !== '') { $endDate = parse_ymd_from_triple($ey, $em, $ed); } if ($endDate === null) { $g = $readSrc($src, 'end_date'); $endDate = ($g !== null && $g !== '') ? $g : null; } $startParts = ['y' => '', 'm' => '', 'd' => '']; $endParts = ['y' => '', 'm' => '', 'd' => '']; if ($startDate !== null && preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $startDate, $m)) { $startParts = ['y' => $m[1], 'm' => (int) $m[2], 'd' => (int) $m[3]]; } elseif ($sy !== null && $sm !== null && $sd !== null && $sy !== '' && $sm !== '' && $sd !== '') { $iy = (int) $sy; $im = (int) $sm; $id = (int) $sd; if ($iy >= 1000 && $iy <= 9999 && $im >= 1 && $im <= 12 && $id >= 1 && $id <= 31) { $startParts = ['y' => (string) $iy, 'm' => $im, 'd' => $id]; } } if ($endDate !== null && preg_match('/^(\d{4})-(\d{2})-(\d{2})$/', $endDate, $m)) { $endParts = ['y' => $m[1], 'm' => (int) $m[2], 'd' => (int) $m[3]]; } elseif ($ey !== null && $em !== null && $ed !== null && $ey !== '' && $em !== '' && $ed !== '') { $iy = (int) $ey; $im = (int) $em; $id = (int) $ed; if ($iy >= 1000 && $iy <= 9999 && $im >= 1 && $im <= 12 && $id >= 1 && $id <= 31) { $endParts = ['y' => (string) $iy, 'm' => $im, 'd' => $id]; } } $dateYearMin = (int) date('Y') - 12; $dateYearMax = (int) date('Y') + 2; $bagKindE = $readSrc($src, 'bag_kind_e'); $bagCode = $readSrc($src, 'bag_code'); $pager = null; $bagCodes = []; $bagKindOpts = []; $printLines = []; $printLgName = ''; if ($lgIdx !== null) { try { $priceModel = model(BagPriceModel::class); $builder = $priceModel->where('bp_lg_idx', $lgIdx); if (($startDate !== null && $startDate !== '') || ($endDate !== null && $endDate !== '')) { $qStart = ($startDate !== null && $startDate !== '') ? $startDate : $endDate; $qEnd = ($endDate !== null && $endDate !== '') ? $endDate : $startDate; if (strcmp((string) $qStart, (string) $qEnd) > 0) { [$qStart, $qEnd] = [$qEnd, $qStart]; } $builder->where('bp_start_date <=', $qEnd); $builder->groupStart() ->where('bp_end_date IS NULL') ->orWhere('bp_end_date >=', $qStart) ->groupEnd(); } if ($bagKindE !== null && $bagKindE !== '') { $ek = model(CodeKindModel::class)->where('ck_code', 'E')->first(); if ($ek) { $eDetail = model(CodeDetailModel::class) ->where('cd_ck_idx', (int) $ek->ck_idx) ->where('cd_code', $bagKindE) ->where('cd_state', 1) ->first(); if ($eDetail !== null) { $builder->like('bp_bag_code', (string) $bagKindE, 'after'); } } } if ($bagCode !== null && $bagCode !== '') { $ok = model(CodeKindModel::class)->where('ck_code', 'O')->first(); if ($ok) { $oDetail = model(CodeDetailModel::class)->findResolvedByKindAndCode((int) $ok->ck_idx, (string) $bagCode, $lgIdx); if ($oDetail !== null) { $builder->where('bp_bag_code', $bagCode); } } } $bagPrices = $builder->orderBy('bp_bag_code', 'ASC')->orderBy('bp_start_date', 'DESC')->paginate(20); $queryForPager = []; $tripleS = $sy !== null && $sy !== '' && $sm !== null && $sm !== '' && $sd !== null && $sd !== ''; $tripleE = $ey !== null && $ey !== '' && $em !== null && $em !== '' && $ed !== null && $ed !== ''; if ($tripleS) { $queryForPager['start_y'] = $sy; $queryForPager['start_m'] = $sm; $queryForPager['start_d'] = $sd; } else { $legacyS = $readSrc($src, 'start_date'); if ($legacyS !== null) { $queryForPager['start_date'] = $legacyS; } } if ($tripleE) { $queryForPager['end_y'] = $ey; $queryForPager['end_m'] = $em; $queryForPager['end_d'] = $ed; } else { $legacyE = $readSrc($src, 'end_date'); if ($legacyE !== null) { $queryForPager['end_date'] = $legacyE; } } if ($bagKindE !== null && $bagKindE !== '') { $queryForPager['bag_kind_e'] = $bagKindE; } if ($bagCode !== null && $bagCode !== '') { $queryForPager['bag_code'] = $bagCode; } $queryForPager = array_filter( $queryForPager, static fn ($v) => $v !== null && $v !== '' ); $pagerPath = site_url('bag/prices'); if ($queryForPager !== []) { $pagerPath .= '?' . http_build_query($queryForPager); } $priceModel->pager->setPath($pagerPath); $pager = $priceModel->pager; $kindO = model(CodeKindModel::class)->where('ck_code', 'O')->first(); $bagCodes = $kindO ? model(CodeDetailModel::class)->getByKind((int) $kindO->ck_idx, true, $lgIdx) : []; $kindE = model(CodeKindModel::class)->where('ck_code', 'E')->first(); $bagKindOpts = $kindE ? model(CodeDetailModel::class)->getByKind((int) $kindE->ck_idx, true, null) : []; $lgRow = model(LocalGovernmentModel::class)->find($lgIdx); $printLgName = $lgRow !== null ? $lgRow->lg_name : ''; } catch (DatabaseException $e) { log_message('error', '[prices] bag_price 조회 실패: ' . $e->getMessage()); } } if (($startDate !== null && $startDate !== '') || ($endDate !== null && $endDate !== '')) { $qs = ($startDate !== null && $startDate !== '') ? $startDate : $endDate; $qe = ($endDate !== null && $endDate !== '') ? $endDate : $startDate; if (strcmp((string) $qs, (string) $qe) > 0) { [$qs, $qe] = [$qe, $qs]; } $printLines[] = '조회기간(적용기간 겹침): ' . format_ymd_korean($qs) . ' ~ ' . format_ymd_korean($qe); } if ($bagKindE !== null && $bagKindE !== '') { foreach ($bagKindOpts as $cd) { if ((string) $cd->cd_code === (string) $bagKindE) { $printLines[] = '봉투구분: ' . $cd->cd_name . ' (' . $bagKindE . ')'; break; } } } if ($bagCode !== null && $bagCode !== '') { $printLines[] = '봉투코드: ' . $bagCode; } $viewData = [ 'lgIdx' => $lgIdx, 'bagPrices' => $bagPrices, 'pager' => $pager, 'startDate' => $startDate, 'endDate' => $endDate, 'startParts' => $startParts, 'endParts' => $endParts, 'dateYearMin' => $dateYearMin, 'dateYearMax' => $dateYearMax, 'bag_kind_e' => $bagKindE, 'bag_code' => $bagCode, 'bag_codes' => $bagCodes, 'bag_kind_options' => $bagKindOpts, 'printExtraLines' => $printLines, ]; if ($printLgName !== '') { $viewData['printLgName'] = $printLgName; } return $this->render('봉투 단가', 'bag/prices', $viewData); } /** 포장 단위 조회 (사이트) */ public function packagingUnits(): string { $lgIdx = $this->lgIdx(); $packagingUnits = []; if ($lgIdx) { try { $packagingUnits = model(PackagingUnitModel::class)->where('pu_lg_idx', $lgIdx)->orderBy('pu_bag_code', 'ASC')->findAll(); } catch (DatabaseException $e) { log_message('error', '[packagingUnits] packaging_unit 조회 실패: ' . $e->getMessage()); } } return $this->render('포장 단위', 'bag/packaging_units', ['packagingUnits' => $packagingUnits]); } /** * 기본코드 종류·세부코드 조회 전용 (사이트 메뉴 기본코드관리) */ public function codeKinds(): string { $kindModel = model(CodeKindModel::class); $detailModel = model(CodeDetailModel::class); $kinds = []; $countMap = []; $selectedKind = null; $detailList = []; $rowCanEdit = []; $lgIdx = $this->lgIdx(); try { $kinds = $kindModel->orderBy('ck_code', 'ASC')->findAll(); foreach ($kinds as $row) { $countMap[$row->ck_idx] = (int) $detailModel->where('cd_ck_idx', $row->ck_idx) ->filterByTenantScope($lgIdx) ->countAllResults(); } } catch (\Throwable $e) { log_message('error', '[codeKinds] 실패: {type} {message} @ {file}:{line} / lg={lg}, user={user}, level={level}', [ 'type' => $e::class, 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), 'lg' => $lgIdx !== null ? (string) $lgIdx : 'null', 'user' => (string) (session()->get('mb_id') ?? ''), 'level' => (string) (session()->get('mb_level') ?? ''), ]); session()->setFlashdata('error', '기본코드 조회 중 오류가 발생했습니다. 관리자에게 로그 확인을 요청해 주세요.'); } $level = (int) session()->get('mb_level'); $canManageDetails = Roles::canManageCodeMaster($level); if ($kinds !== []) { $selectedCkIdx = (int) ($this->request->getGet('ck_idx') ?? 0); foreach ($kinds as $row) { if ((int) $row->ck_idx === $selectedCkIdx) { $selectedKind = $row; break; } } if ($selectedKind === null) { $selectedKind = $kinds[0]; } } if ($selectedKind !== null) { $detailList = $detailModel->where('cd_ck_idx', (int) $selectedKind->ck_idx) ->filterByTenantScope($lgIdx) ->orderBy('cd_sort', 'ASC') ->orderBy('cd_code', 'ASC') ->orderBy('cd_idx', 'ASC') ->findAll(); helper('admin'); $adminLg = admin_effective_lg_idx(); foreach ($detailList as $row) { $rowCanEdit[$row->cd_idx] = Roles::canEditCodeDetailRow($level, $row, $adminLg); } } return $this->render('기본코드관리', 'bag/code_kinds', [ 'codeKinds' => $kinds, 'countMap' => $countMap, 'canManageKinds' => Roles::canManageCodeKindMaster($level), 'canManageDetails' => $canManageDetails, 'selectedKind' => $selectedKind, 'detailList' => $detailList, 'rowCanEdit' => $rowCanEdit, ]); } /** * 기본코드 세부 목록 (사이트 레이아웃). 등록·수정·삭제 폼은 /admin/code-details/* 유지. */ public function codeDetails(int $ckIdx) { $kindModel = model(CodeKindModel::class); $detailModel = model(CodeDetailModel::class); $kind = null; try { $kind = $kindModel->find($ckIdx); } catch (\Throwable $e) { log_message('error', '[codeDetails] kind 조회 실패: {type} {message} @ {file}:{line} / ck={ck}, user={user}, level={level}', [ 'type' => $e::class, 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), 'ck' => (string) $ckIdx, 'user' => (string) (session()->get('mb_id') ?? ''), 'level' => (string) (session()->get('mb_level') ?? ''), ]); return redirect()->to(site_url('bag/code-kinds'))->with('error', '세부코드 조회 중 오류가 발생했습니다. 관리자에게 로그 확인을 요청해 주세요.'); } if ($kind === null) { return redirect()->to(site_url('bag/code-kinds'))->with('error', '코드 종류를 찾을 수 없습니다.'); } $lgIdx = $this->lgIdx(); try { $list = $detailModel->where('cd_ck_idx', $ckIdx) ->filterByTenantScope($lgIdx) ->orderBy('cd_sort', 'ASC') ->orderBy('cd_code', 'ASC') ->orderBy('cd_idx', 'ASC') ->paginate(20); $pager = $detailModel->pager; } catch (\Throwable $e) { log_message('error', '[codeDetails] list 조회 실패: {type} {message} @ {file}:{line} / ck={ck}, lg={lg}, user={user}, level={level}', [ 'type' => $e::class, 'message' => $e->getMessage(), 'file' => $e->getFile(), 'line' => $e->getLine(), 'ck' => (string) $ckIdx, 'lg' => $lgIdx !== null ? (string) $lgIdx : 'null', 'user' => (string) (session()->get('mb_id') ?? ''), 'level' => (string) (session()->get('mb_level') ?? ''), ]); return redirect()->to(site_url('bag/code-kinds'))->with('error', '세부코드 조회 중 오류가 발생했습니다. 관리자에게 로그 확인을 요청해 주세요.'); } helper('admin'); $level = (int) session()->get('mb_level'); $adminLg = admin_effective_lg_idx(); $canManage = Roles::canManageCodeMaster($level); $rowCanEdit = []; foreach ($list as $row) { $rowCanEdit[$row->cd_idx] = Roles::canEditCodeDetailRow($level, $row, $adminLg); } $title = ($canManage ? '세부코드 관리' : '세부코드 조회') . ' — ' . $kind->ck_name . ' (' . $kind->ck_code . ')'; return $this->render($title, 'bag/code_details', [ 'kind' => $kind, 'list' => $list, 'pager' => $pager, 'canManage' => $canManage, 'rowCanEdit' => $rowCanEdit, ]); } // ────────────────────────────────────────────── // 발주 입고 관리 // ────────────────────────────────────────────── public function purchaseInbound(): string { $lgIdx = $this->lgIdx(); $data = ['orders' => [], 'receivings' => [], 'startDate' => null, 'endDate' => null]; if ($lgIdx) { $startDate = $this->request->getGet('start_date'); $endDate = $this->request->getGet('end_date'); $data['startDate'] = $startDate; $data['endDate'] = $endDate; // 발주 목록 $orderBuilder = model(BagOrderModel::class)->where('bo_lg_idx', $lgIdx)->whereLatestHead($lgIdx); if ($startDate) $orderBuilder->where('bo_order_date >=', $startDate); if ($endDate) $orderBuilder->where('bo_order_date <=', $endDate); $data['orders'] = $orderBuilder->orderBy('bo_order_date', 'DESC')->paginate(20, 'orders'); $data['orderPager'] = model(BagOrderModel::class)->pager; // 발주별 품목 합계 $itemSummary = []; foreach ($data['orders'] as $order) { $items = model(BagOrderItemModel::class)->where('boi_bo_idx', $order->bo_idx)->findAll(); $totalQty = 0; $totalAmt = 0; foreach ($items as $it) { $totalQty += (int) $it->boi_qty_sheet; $totalAmt += (float) $it->boi_amount; } $itemSummary[$order->bo_idx] = ['qty' => $totalQty, 'amount' => $totalAmt, 'count' => count($items)]; } $data['itemSummary'] = $itemSummary; // 입고 목록 $recvBuilder = model(BagReceivingModel::class)->where('br_lg_idx', $lgIdx); if ($startDate) $recvBuilder->where('br_receive_date >=', $startDate); if ($endDate) $recvBuilder->where('br_receive_date <=', $endDate); $data['receivings'] = $recvBuilder->orderBy('br_receive_date', 'DESC')->paginate(20, 'receivings'); $data['recvPager'] = model(BagReceivingModel::class)->pager; } return $this->render('발주 입고 관리', 'bag/purchase_inbound', $data); } // ────────────────────────────────────────────── // 불출 관리 // ────────────────────────────────────────────── public function issue(): string { $lgIdx = $this->lgIdx(); $data = ['list' => [], 'startDate' => null, 'endDate' => null]; if ($lgIdx) { $startDate = $this->request->getGet('start_date'); $endDate = $this->request->getGet('end_date'); $data['startDate'] = $startDate; $data['endDate'] = $endDate; $builder = model(BagIssueModel::class)->where('bi2_lg_idx', $lgIdx); if ($startDate) $builder->where('bi2_issue_date >=', $startDate); if ($endDate) $builder->where('bi2_issue_date <=', $endDate); $data['list'] = $builder->orderBy('bi2_issue_date', 'DESC')->paginate(20); $data['pager'] = model(BagIssueModel::class)->pager; } return $this->render('불출 관리', 'bag/issue', $data); } // ────────────────────────────────────────────── // 재고 관리 // ────────────────────────────────────────────── public function inventory(): string { $lgIdx = $this->lgIdx(); $data = ['list' => []]; if ($lgIdx) { $invModel = model(BagInventoryModel::class); $data['list'] = $invModel->where('bi_lg_idx', $lgIdx)->orderBy('bi_bag_code', 'ASC')->paginate(20); $data['pager'] = $invModel->pager; } return $this->render('재고 관리', 'bag/inventory', $data); } // ────────────────────────────────────────────── // 판매 관리 // ────────────────────────────────────────────── public function sales(): string { $lgIdx = $this->lgIdx(); $data = ['salesList' => [], 'orderList' => [], 'startDate' => null, 'endDate' => null]; if ($lgIdx) { $startDate = $this->request->getGet('start_date'); $endDate = $this->request->getGet('end_date'); $data['startDate'] = $startDate; $data['endDate'] = $endDate; // 판매/반품 $saleBuilder = model(BagSaleModel::class)->where('bs_lg_idx', $lgIdx); if ($startDate) $saleBuilder->where('bs_sale_date >=', $startDate); if ($endDate) $saleBuilder->where('bs_sale_date <=', $endDate); $data['salesList'] = $saleBuilder->orderBy('bs_sale_date', 'DESC')->paginate(20, 'sales'); $data['salesPager'] = model(BagSaleModel::class)->pager; // 주문 접수 $orderBuilder = model(ShopOrderModel::class)->where('so_lg_idx', $lgIdx); if ($startDate) $orderBuilder->where('so_delivery_date >=', $startDate); if ($endDate) $orderBuilder->where('so_delivery_date <=', $endDate); $data['orderList'] = $orderBuilder->orderBy('so_idx', 'DESC')->paginate(20, 'shoporders'); $data['orderPager'] = model(ShopOrderModel::class)->pager; } return $this->render('판매 관리', 'bag/sales', $data); } // ────────────────────────────────────────────── // 판매 현황 // ────────────────────────────────────────────── public function salesStats(): string { $lgIdx = $this->lgIdx(); $data = ['result' => [], 'startDate' => null, 'endDate' => null]; if ($lgIdx) { $startDate = $this->request->getGet('start_date'); $endDate = $this->request->getGet('end_date'); $data['startDate'] = $startDate; $data['endDate'] = $endDate; $builder = model(BagSaleModel::class)->where('bs_lg_idx', $lgIdx)->where('bs_type', 'sale'); if ($startDate) $builder->where('bs_sale_date >=', $startDate); if ($endDate) $builder->where('bs_sale_date <=', $endDate); $data['result'] = $builder->orderBy('bs_sale_date', 'DESC')->paginate(20); $data['pager'] = model(BagSaleModel::class)->pager; } return $this->render('판매 현황', 'bag/sales_stats', $data); } // ────────────────────────────────────────────── // 봉투 수불 관리 // ────────────────────────────────────────────── public function flow(): string { $lgIdx = $this->lgIdx(); $data = ['receiving' => [], 'sales' => [], 'issues' => [], 'inventory' => [], 'startDate' => null, 'endDate' => null]; if ($lgIdx) { $startDate = $this->request->getGet('start_date'); $endDate = $this->request->getGet('end_date'); $data['startDate'] = $startDate; $data['endDate'] = $endDate; $data['inventory'] = model(BagInventoryModel::class)->where('bi_lg_idx', $lgIdx)->findAll(); $recvBuilder = model(BagReceivingModel::class)->where('br_lg_idx', $lgIdx); if ($startDate) $recvBuilder->where('br_receive_date >=', $startDate); if ($endDate) $recvBuilder->where('br_receive_date <=', $endDate); $data['receiving'] = $recvBuilder->findAll(); $saleBuilder = model(BagSaleModel::class)->where('bs_lg_idx', $lgIdx); if ($startDate) $saleBuilder->where('bs_sale_date >=', $startDate); if ($endDate) $saleBuilder->where('bs_sale_date <=', $endDate); $data['sales'] = $saleBuilder->findAll(); $issueBuilder = model(BagIssueModel::class)->where('bi2_lg_idx', $lgIdx); if ($startDate) $issueBuilder->where('bi2_issue_date >=', $startDate); if ($endDate) $issueBuilder->where('bi2_issue_date <=', $endDate); $data['issues'] = $issueBuilder->findAll(); } return $this->render('봉투 수불 관리', 'bag/flow', $data); } // ────────────────────────────────────────────── // 통계 분석 관리 // ────────────────────────────────────────────── public function analytics(): string { return $this->render('통계 분석 관리', 'bag/analytics', []); } // ────────────────────────────────────────────── // 창 (프로그램 창 관리 - 추후) // ────────────────────────────────────────────── public function window(): string { return $this->render('창', 'bag/window', []); } // ────────────────────────────────────────────── // 도움말 // ────────────────────────────────────────────── public function help(): string { return $this->render('도움말', 'bag/help', []); } // ────────────────────────────────────────────── // 재고 조정 (실사) // ────────────────────────────────────────────── public function inventoryAdjust(): string { $lgIdx = $this->lgIdx(); $inventory = $lgIdx ? model(BagInventoryModel::class)->where('bi_lg_idx', $lgIdx)->orderBy('bi_bag_code')->findAll() : []; return $this->render('재고 조정', 'bag/inventory_adjust', compact('inventory')); } public function inventoryAdjustStore() { helper('admin'); $lgIdx = $this->lgIdx(); if (! $lgIdx) { return redirect()->to(site_url('bag/inventory'))->with('error', '지자체를 선택해 주세요.'); } $rules = [ 'bag_code' => 'required|max_length[50]', 'adjust_type' => 'required|in_list[set,add,sub]', 'qty' => 'required|is_natural', ]; if (! $this->validate($rules)) { return redirect()->back()->withInput()->with('errors', $this->validator->getErrors()); } $bagCode = $this->request->getPost('bag_code'); $type = $this->request->getPost('adjust_type'); $qty = (int) $this->request->getPost('qty'); $invModel = model(BagInventoryModel::class); $existing = $invModel->where('bi_lg_idx', $lgIdx)->where('bi_bag_code', $bagCode)->first(); if ($type === 'set') { if ($existing) { $invModel->update($existing->bi_idx, ['bi_qty' => $qty, 'bi_updated_at' => date('Y-m-d H:i:s')]); } } elseif ($type === 'add') { $bagName = $existing ? $existing->bi_bag_name : ''; $invModel->adjustQty($lgIdx, $bagCode, $bagName, $qty); } elseif ($type === 'sub') { $bagName = $existing ? $existing->bi_bag_name : ''; $invModel->adjustQty($lgIdx, $bagCode, $bagName, -$qty); } return redirect()->to(site_url('bag/inventory'))->with('success', '재고가 조정되었습니다.'); } // ══════════════════════════════════════════════ // CRUD — 사이트 레이아웃으로 등록/처리 폼 제공 // ══════════════════════════════════════════════ // --- 불출 등록 --- public function issueCreate(): string { $kind = model(CodeKindModel::class)->where('ck_code', 'O')->first(); $bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $this->lgIdx()) : []; return $this->render('불출 처리', 'bag/create_bag_issue', compact('bagCodes')); } public function issueStore() { $admin = new \App\Controllers\Admin\BagIssue(); $admin->initController($this->request, $this->response, service('logger')); $result = $admin->store(); if ($result instanceof \CodeIgniter\HTTP\RedirectResponse) { $to = (string) $result->getHeaderLine('Location'); $to = str_replace('/admin/bag-issues', '/bag/issue', $to); return redirect()->to($to)->with('success', session()->getFlashdata('success'))->with('errors', session()->getFlashdata('errors')); } return redirect()->to(site_url('bag/issue'))->with('success', '불출 처리되었습니다.'); } public function issueCancel(int $id) { $admin = new \App\Controllers\Admin\BagIssue(); $admin->initController($this->request, $this->response, service('logger')); $admin->cancel($id); return redirect()->to(site_url('bag/issue'))->with('success', session()->getFlashdata('success') ?? '취소되었습니다.'); } // --- 발주 등록 --- public function orderCreate(): string { helper('admin'); $lgIdx = $this->lgIdx(); $companies = $lgIdx ? model(CompanyModel::class)->where('cp_lg_idx', $lgIdx)->where('cp_type', '제작업체')->where('cp_state', 1)->findAll() : []; $associations = $lgIdx ? model(CompanyModel::class)->where('cp_lg_idx', $lgIdx)->where('cp_type', '협회')->where('cp_state', 1)->findAll() : []; $agencies = $lgIdx ? model(SalesAgencyModel::class)->where('sa_lg_idx', $lgIdx)->orderForDisplay()->findAll() : []; $kind = model(CodeKindModel::class)->where('ck_code', 'O')->first(); $bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx) : []; $priceMapRows = $lgIdx ? model(BagPriceModel::class)->latestActiveMapByBagCode($lgIdx) : []; $units = $lgIdx ? model(PackagingUnitModel::class)->where('pu_lg_idx', $lgIdx)->where('pu_state', 1)->findAll() : []; $recentOrders = $lgIdx ? model(BagOrderModel::class)->where('bo_lg_idx', $lgIdx)->whereLatestHead($lgIdx)->orderBy('bo_order_date', 'DESC')->orderBy('bo_idx', 'DESC')->findAll(12) : []; $companyMap = []; foreach ($companies as $company) { $companyMap[(int) $company->cp_idx] = (string) $company->cp_name; } $agencyMap = []; foreach ($agencies as $agency) { $agencyMap[(int) $agency->sa_idx] = '[' . ($agency->sa_kind ?? '') . '] ' . ($agency->sa_code ?? '') . ' — ' . ($agency->sa_name ?? ''); } $bagNameMap = []; foreach ($bagCodes as $codeDetail) { $bagNameMap[(string) $codeDetail->cd_code] = (string) $codeDetail->cd_name; } $priceMap = []; foreach ($priceMapRows as $bagCode => $price) { $priceMap[(string) $bagCode] = (float) ($price->bp_order_price ?? 0); } $unitMap = []; foreach ($units as $unit) { $unitMap[(string) $unit->pu_bag_code] = [ 'boxPerPack' => (int) $unit->pu_box_per_pack, 'packPerSheet' => (int) $unit->pu_pack_per_sheet, 'totalPerBox' => (int) $unit->pu_total_per_box, ]; } $bagReferenceRows = []; foreach ($bagCodes as $codeDetail) { $bagCode = (string) $codeDetail->cd_code; $unit = $unitMap[$bagCode] ?? ['boxPerPack' => 0, 'packPerSheet' => 0, 'totalPerBox' => 0]; $bagReferenceRows[] = [ 'code' => $bagCode, 'name' => (string) ($bagNameMap[$bagCode] ?? ''), 'orderPrice' => (float) ($priceMap[$bagCode] ?? 0), 'boxPerPack' => (int) $unit['boxPerPack'], 'packPerSheet' => (int) $unit['packPerSheet'], 'totalPerBox' => (int) $unit['totalPerBox'], ]; } return $this->render( '발주 등록', 'bag/create_bag_order', array_merge( compact( 'companies', 'associations', 'agencies', 'bagCodes', 'recentOrders', 'companyMap', 'agencyMap', 'bagReferenceRows' ), ['editMode' => false, 'editDefaults' => null] ) ); } /** * 발주 변경 허브: 발주월·변경 구분 선택 후 목록에서 발주를 선택 (GBMS 발주 변경 화면 흐름). */ public function orderChange(): string|RedirectResponse { helper('admin'); $lgIdx = $this->lgIdx(); $month = $this->request->getGet('month'); if ($month === null || $month === '' || ! is_string($month) || ! preg_match('/^\d{4}-\d{2}$/', $month)) { $month = date('Y-m'); } $hubMode = $this->request->getGet('hub_mode'); $hubMode = in_array($hubMode, ['price', 'meta', 'delete'], true) ? $hubMode : 'meta'; $companyMap = []; if ($lgIdx) { $companies = model(CompanyModel::class)->where('cp_lg_idx', $lgIdx)->where('cp_type', '제작업체')->where('cp_state', 1)->findAll(); foreach ($companies as $company) { $companyMap[(int) $company->cp_idx] = (string) $company->cp_name; } } $monthOrders = []; if ($lgIdx) { $start = $month . '-01'; $end = date('Y-m-t', strtotime($start . ' 00:00:00')); $monthOrders = model(BagOrderModel::class) ->where('bo_lg_idx', $lgIdx) ->whereLatestHead($lgIdx) ->where('bo_order_date >=', $start) ->where('bo_order_date <=', $end) ->whereIn('bo_status', ['normal', 'cancelled']) ->orderBy('bo_order_date', 'DESC') ->orderBy('bo_idx', 'DESC') ->findAll(); } if ($hubMode === 'delete') { foreach ($monthOrders as $row) { if ((string) ($row->bo_status ?? '') === 'normal') { return redirect()->to( site_url('bag/order/revise/' . (int) $row->bo_idx . '?change_mode=delete') ); } } if ($lgIdx) { session()->setFlashdata('error', '해당 월에 삭제할 수 있는 발주(정상)가 없습니다.'); } } return $this->render( '발주 변경', 'bag/order_change', compact('month', 'hubMode', 'monthOrders', 'companyMap') ); } public function orderRevise(int $id): string|RedirectResponse { helper('admin'); $lgIdx = $this->lgIdx(); $orderModel = model(BagOrderModel::class); $itemModel = model(\App\Models\BagOrderItemModel::class); $target = $orderModel->find($id); if (! $target || (int) $target->bo_lg_idx !== $lgIdx) { return redirect()->to(site_url('bag/order/change'))->with('error', '수정할 발주를 찾을 수 없습니다.'); } if ((string) ($target->bo_status ?? '') !== 'normal') { return redirect()->to(site_url('bag/order/change'))->with('error', '변경할 수 없는 발주입니다.'); } $changeMode = $this->request->getGet('change_mode'); $changeMode = in_array($changeMode, ['price', 'meta', 'delete'], true) ? $changeMode : 'meta'; $companies = $lgIdx ? model(CompanyModel::class)->where('cp_lg_idx', $lgIdx)->where('cp_type', '제작업체')->where('cp_state', 1)->findAll() : []; $associations = $lgIdx ? model(CompanyModel::class)->where('cp_lg_idx', $lgIdx)->where('cp_type', '협회')->where('cp_state', 1)->findAll() : []; $agencies = $lgIdx ? model(SalesAgencyModel::class)->where('sa_lg_idx', $lgIdx)->orderForDisplay()->findAll() : []; $kind = model(CodeKindModel::class)->where('ck_code', 'O')->first(); $bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx) : []; $priceMapRows = $lgIdx ? model(BagPriceModel::class)->latestActiveMapByBagCode($lgIdx) : []; $units = $lgIdx ? model(PackagingUnitModel::class)->where('pu_lg_idx', $lgIdx)->where('pu_state', 1)->findAll() : []; $companyMap = []; foreach ($companies as $company) { $companyMap[(int) $company->cp_idx] = (string) $company->cp_name; } $agencyMap = []; foreach ($agencies as $agency) { $agencyMap[(int) $agency->sa_idx] = '[' . ($agency->sa_kind ?? '') . '] ' . ($agency->sa_code ?? '') . ' — ' . ($agency->sa_name ?? ''); } $bagNameMap = []; foreach ($bagCodes as $codeDetail) { $bagNameMap[(string) $codeDetail->cd_code] = (string) $codeDetail->cd_name; } $priceMap = []; foreach ($priceMapRows as $bagCode => $price) { $priceMap[(string) $bagCode] = (float) ($price->bp_order_price ?? 0); } $unitMap = []; foreach ($units as $unit) { $unitMap[(string) $unit->pu_bag_code] = [ 'boxPerPack' => (int) $unit->pu_box_per_pack, 'packPerSheet' => (int) $unit->pu_pack_per_sheet, 'totalPerBox' => (int) $unit->pu_total_per_box, ]; } $bagReferenceRows = []; foreach ($bagCodes as $codeDetail) { $bagCode = (string) $codeDetail->cd_code; $unit = $unitMap[$bagCode] ?? ['boxPerPack' => 0, 'packPerSheet' => 0, 'totalPerBox' => 0]; $bagReferenceRows[] = [ 'code' => $bagCode, 'name' => (string) ($bagNameMap[$bagCode] ?? ''), 'orderPrice' => (float) ($priceMap[$bagCode] ?? 0), 'boxPerPack' => (int) $unit['boxPerPack'], 'packPerSheet' => (int) $unit['packPerSheet'], 'totalPerBox' => (int) $unit['totalPerBox'], ]; } $items = $itemModel->where('boi_bo_idx', (int) $target->bo_idx)->orderBy('boi_idx', 'ASC')->findAll(); $orderReturnMonth = substr((string) ($target->bo_order_date ?? date('Y-m-d')), 0, 7); $monthStart = $orderReturnMonth . '-01'; $monthEnd = date('Y-m-t', strtotime($monthStart . ' 00:00:00')); $recentOrders = $lgIdx ? $orderModel->where('bo_lg_idx', $lgIdx) ->whereLatestHead($lgIdx) ->where('bo_order_date >=', $monthStart) ->where('bo_order_date <=', $monthEnd) ->whereIn('bo_status', ['normal', 'cancelled']) ->orderBy('bo_order_date', 'DESC') ->orderBy('bo_idx', 'DESC') ->findAll() : []; $itemCodes = []; $itemQtyBoxes = []; $itemQtySheets = []; foreach ($items as $item) { $itemCodes[] = (string) ($item->boi_bag_code ?? ''); $itemQtyBoxes[] = (int) ($item->boi_qty_box ?? 0); $itemQtySheets[] = (int) ($item->boi_qty_sheet ?? 0); } $savedLinePrices = []; foreach ($items as $item) { $savedLinePrices[(string) ($item->boi_bag_code ?? '')] = (float) ($item->boi_unit_price ?? 0); } foreach ($bagReferenceRows as &$brow) { $c = (string) ($brow['code'] ?? ''); if ($c !== '' && isset($savedLinePrices[$c])) { $brow['orderPrice'] = $savedLinePrices[$c]; } } unset($brow); $orderLotNo = (string) ($target->bo_lot_no ?? ''); $editDefaults = [ 'bo_source_idx' => (int) $target->bo_idx, 'bo_order_date' => (string) ($target->bo_order_date ?? date('Y-m-d')), 'bo_order_month_ui' => substr((string) ($target->bo_order_date ?? date('Y-m-d')), 0, 7), 'bo_fee_rate' => (string) ($target->bo_fee_rate ?? '0'), 'bo_association_idx' => (string) ($target->bo_association_idx ?? ''), 'bo_company_idx' => (string) ($target->bo_company_idx ?? ''), 'bo_agency_idx' => (string) ($target->bo_agency_idx ?? ''), 'item_bag_code' => $itemCodes, 'item_qty_box' => $itemQtyBoxes, 'item_qty_sheet' => $itemQtySheets, ]; return $this->render( '발주 변경', 'bag/create_bag_order', compact( 'companies', 'associations', 'agencies', 'bagCodes', 'recentOrders', 'companyMap', 'agencyMap', 'bagReferenceRows', 'editDefaults', 'changeMode', 'orderReturnMonth', 'orderLotNo' ) + ['editMode' => true, 'hubReturn' => true] ); } public function orderStore() { $admin = new \App\Controllers\Admin\BagOrder(); $admin->initController($this->request, $this->response, service('logger')); $result = $admin->store(); if ($result instanceof RedirectResponse) { $success = session()->getFlashdata('success'); $error = session()->getFlashdata('error'); $errors = session()->getFlashdata('errors'); if (! empty($error) || ! empty($errors)) { $sourceIdx = (int) ($this->request->getPost('bo_source_idx') ?? 0); $reviseMode = (string) ($this->request->getPost('bo_change_mode') ?? 'meta'); $redirectUrl = $sourceIdx > 0 ? site_url('bag/order/revise/' . $sourceIdx . '?change_mode=' . rawurlencode($reviseMode)) : site_url('bag/order/create'); return redirect()->to($redirectUrl) ->withInput() ->with('error', $error) ->with('errors', $errors); } $returnHub = (int) ($this->request->getPost('order_return_hub') ?? 0) === 1; $returnMonth = (string) ($this->request->getPost('order_return_month') ?? ''); $sourceIdxPost = (int) ($this->request->getPost('bo_source_idx') ?? 0); if ($returnHub && $sourceIdxPost > 0 && preg_match('/^\d{4}-\d{2}$/', $returnMonth)) { return redirect()->to(site_url('bag/order/change?month=' . $returnMonth)) ->with('success', $success ?? '발주가 저장되었습니다.'); } return redirect()->to(site_url('bag/order/create')) ->with('success', $success); } $returnHub = (int) ($this->request->getPost('order_return_hub') ?? 0) === 1; $returnMonth = (string) ($this->request->getPost('order_return_month') ?? ''); if ($returnHub && (int) ($this->request->getPost('bo_source_idx') ?? 0) > 0 && preg_match('/^\d{4}-\d{2}$/', $returnMonth)) { return redirect()->to(site_url('bag/order/change?month=' . $returnMonth))->with('success', '발주가 저장되었습니다.'); } return redirect()->to(site_url('bag/order/create'))->with('success', '발주 등록되었습니다.'); } public function orderDeletePost() { $id = (int) ($this->request->getPost('bo_idx') ?? 0); if ($id <= 0) { return redirect()->to(site_url('bag/order/change'))->with('error', '삭제할 발주를 선택해 주세요.'); } return $this->orderDelete($id); } public function orderDelete(int $id) { helper('admin'); $lgIdx = $this->lgIdx(); if ($lgIdx === null || $lgIdx <= 0) { return redirect()->to(site_url('bag/order/change'))->with('error', '지자체를 선택해 주세요.'); } $orderModel = model(BagOrderModel::class); $order = $orderModel->find($id); if (! $order || (int) $order->bo_lg_idx !== $lgIdx) { return redirect()->to(site_url('bag/order/change'))->with('error', '발주를 찾을 수 없습니다.'); } if ((string) ($order->bo_status ?? '') !== 'normal') { return redirect()->to(site_url('bag/order/change'))->with('error', '삭제할 수 없는 발주입니다.'); } $month = substr((string) ($order->bo_order_date ?? date('Y-m-d')), 0, 7); $admin = new \App\Controllers\Admin\BagOrder(); $admin->initController($this->request, $this->response, service('logger')); $response = $admin->delete($id); if ($response instanceof RedirectResponse) { $msg = session()->getFlashdata('success') ?? '발주가 삭제 처리되었습니다.'; return redirect()->to(site_url('bag/order/change?month=' . $month))->with('success', $msg); } return redirect()->to(site_url('bag/order/change?month=' . $month))->with('success', '처리되었습니다.'); } public function orderCancel(int $id) { helper('admin'); $lgIdx = $this->lgIdx(); if (!$lgIdx) { return redirect()->to(site_url('bag/purchase-inbound'))->with('error', '지자체를 확인할 수 없습니다.'); } $orderModel = model(BagOrderModel::class); $order = $orderModel->find($id); if (!$order || (int) $order->bo_lg_idx !== $lgIdx) { return redirect()->to(site_url('bag/purchase-inbound'))->with('error', '발주를 찾을 수 없습니다.'); } $before = (array) $order; $orderModel->update($id, ['bo_status' => 'cancelled', 'bo_moddate' => date('Y-m-d H:i:s')]); helper('audit'); audit_log('update', 'bag_order', $id, $before, ['bo_status' => 'cancelled']); return redirect()->to(site_url('bag/purchase-inbound'))->with('success', '발주가 취소되었습니다.'); } // --- 입고 처리 --- public function receivingCreate(): string { return $this->receivingScanner(); } public function receivingStore() { return $this->receivingScannerStore(); } /** * 발주 입고(스캐너 대체 수동입력) * - 미입고가 남은 발주의 LOT·봉투(이름)로 조회 범위를 좁힌 뒤 입고 처리 * - 인수자: 대행소(agency) 담당자, 기본값 동명이면 로그인 사용자명과 일치하는 담당자 * - 인계자: 제작업체(company) 담당자 */ public function receivingScanner(): string|RedirectResponse { helper('admin'); $lgIdx = $this->lgIdx(); if (! $lgIdx) { return redirect()->to(site_url('bag/purchase-inbound'))->with('error', '지자체를 선택해 주세요.'); } $companyIdx = (int) old('company_idx', (int) ($this->request->getGet('company_idx') ?? 0)); $lotNo = ''; $bagCode = ''; $companies = model(CompanyModel::class) ->where('cp_lg_idx', $lgIdx) ->where('cp_type', '제작업체') ->where('cp_state', 1) ->orderBy('cp_name', 'ASC') ->findAll(); $defaultCompanyIdx = ! empty($companies) ? (int) ($companies[0]->cp_idx ?? 0) : 0; if ($companyIdx > 0) { $validCompany = false; foreach ($companies as $company) { if ((int) ($company->cp_idx ?? 0) === $companyIdx) { $validCompany = true; break; } } if (! $validCompany) { $companyIdx = $defaultCompanyIdx; } } elseif ($defaultCompanyIdx > 0) { // 초기 진입 시 드롭다운 최상단 제작업체를 기본 선택한다. $companyIdx = $defaultCompanyIdx; } $lotChoices = []; $bagFilterOptions = $this->receivingBagFilterOptions($lgIdx, $companyIdx, ''); $pick = $this->receivingManagerPickers($lgIdx); $recvSel = $this->receivingReceiverSelect($lgIdx); $receiverRef = (string) old('br_receiver_ref', $recvSel['defaultReceiverRef']); $receiverRef = $this->sanitizeReceiverRef($recvSel['receiverOptions'], $receiverRef); if ($receiverRef === '') { $receiverRef = $recvSel['defaultReceiverRef']; } $senderIdx = (int) old('br_sender_idx', $pick['defaultSenderIdx']); $rows = $companyIdx > 0 ? $this->buildReceivingCandidateRows($lgIdx, $companyIdx, '', true, '') : []; $rowsByKey = []; foreach ($rows as $row) { $rowsByKey[(string) $row['row_key']] = $row; } return $this->render( '발주 입고(스캐너)', 'bag/receiving_scanner', [ 'companyIdx' => $companyIdx, 'companies' => $companies, 'lotNo' => '', 'bagCode' => '', 'bagFilterOptions' => $bagFilterOptions, 'lotChoices' => $lotChoices, 'receiverOptions' => $recvSel['receiverOptions'], 'receiverRef' => $receiverRef, 'senders' => $pick['senders'], 'senderIdx' => $senderIdx, 'rows' => $rows, 'rowsByKey' => $rowsByKey, ] ); } public function receivingScannerStore(): RedirectResponse { helper('admin'); $lgIdx = $this->lgIdx(); if (! $lgIdx) { return redirect()->to(site_url('bag/purchase-inbound'))->with('error', '지자체를 선택해 주세요.'); } $receiveDate = (string) ($this->request->getPost('br_receive_date') ?? date('Y-m-d')); $companyIdx = (int) ($this->request->getPost('company_idx') ?? 0); $lotNo = ''; $filterBagCode = ''; $recvSel = $this->receivingReceiverSelect($lgIdx); $receiverRef = (string) ($this->request->getPost('br_receiver_ref') ?? ''); $receiverRef = $this->sanitizeReceiverRef($recvSel['receiverOptions'], $receiverRef); if ($receiverRef === '') { $receiverRef = $recvSel['defaultReceiverRef']; } $receiverIdx = $this->parseReceiverRefToStoredIdx($lgIdx, $receiverRef); $senderIdx = (int) ($this->request->getPost('br_sender_idx') ?? 0); $inputQty = $this->request->getPost('receive_qty_sheet'); $inputQty = is_array($inputQty) ? $inputQty : []; if (! preg_match('/^\d{4}-\d{2}-\d{2}$/', $receiveDate)) { return redirect()->back()->withInput()->with('error', '입고일 형식을 확인해 주세요.'); } if ($companyIdx <= 0) { return redirect()->back()->withInput()->with('error', '제작업체를 선택해 주세요.'); } if ($receiverIdx <= 0) { return redirect()->back()->withInput()->with('error', '인수자를 선택해 주세요.'); } $senderResolved = $this->resolveCompanySenderName($lgIdx, $senderIdx); $rows = $this->buildReceivingCandidateRows($lgIdx, $companyIdx, '', true, ''); $rowMap = []; foreach ($rows as $row) { $rowMap[(string) $row['row_key']] = $row; } $insertRows = []; foreach ($inputQty as $rowKey => $qtyRaw) { $rowKey = (string) $rowKey; $qty = (int) $qtyRaw; if ($qty <= 0 || ! isset($rowMap[$rowKey])) { continue; } $base = $rowMap[$rowKey]; $pending = (int) ($base['pending_qty_sheet'] ?? 0); if ($pending <= 0) { continue; } if ($qty > $pending) { $qty = $pending; } $totalPerBox = max(1, (int) ($base['total_per_box'] ?? 1)); $qtyBox = intdiv($qty, $totalPerBox); $sender = $senderResolved !== '' ? $senderResolved : (string) ($base['company_rep_name'] ?? ''); $insertRows[] = [ 'br_bo_idx' => (int) $base['bo_idx'], 'br_lg_idx' => $lgIdx, 'br_bag_code' => (string) $base['bag_code'], 'br_bag_name' => (string) $base['bag_name'], 'br_qty_box' => $qtyBox, 'br_qty_sheet' => $qty, 'br_receive_date' => $receiveDate, 'br_receiver_idx' => $receiverIdx, 'br_sender_name' => $sender, 'br_type' => 'scanner', 'br_regdate' => date('Y-m-d H:i:s'), ]; } if (empty($insertRows)) { return redirect()->back()->withInput()->with('error', '입고 처리할 수량을 입력해 주세요.'); } $recvModel = model(BagReceivingModel::class); $invModel = model(BagInventoryModel::class); $db = \Config\Database::connect(); $db->transStart(); foreach ($insertRows as $row) { $recvModel->insert($row); $invModel->adjustQty( $lgIdx, (string) $row['br_bag_code'], (string) $row['br_bag_name'], (int) $row['br_qty_sheet'] ); } $db->transComplete(); if (! $db->transStatus()) { return redirect()->back()->withInput()->with('error', '입고 처리 중 오류가 발생했습니다.'); } $query = ['company_idx' => $companyIdx]; return redirect()->to(site_url('bag/receiving/scanner') . '?' . http_build_query($query)) ->with('success', count($insertRows) . '건 입고 처리되었습니다.'); } /** * 일괄 입고: LOT-봉투 행 기준 미입고량 전체 입고. */ public function receivingBatch(): string|RedirectResponse { helper('admin'); $lgIdx = $this->lgIdx(); if (! $lgIdx) { return redirect()->to(site_url('bag/purchase-inbound'))->with('error', '지자체를 선택해 주세요.'); } $companyIdx = (int) ($this->request->getGet('company_idx') ?? 0); $bagCode = trim((string) ($this->request->getGet('bag_code') ?? '')); $companies = model(CompanyModel::class) ->where('cp_lg_idx', $lgIdx) ->where('cp_type', '제작업체') ->where('cp_state', 1) ->orderBy('cp_name', 'ASC') ->findAll(); $kind = model(CodeKindModel::class)->where('ck_code', 'O')->first(); $bagCodeOptions = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx) : []; $pick = $this->receivingManagerPickers($lgIdx); $recvSel = $this->receivingReceiverSelect($lgIdx); $receiverRef = (string) old('br_receiver_ref', $recvSel['defaultReceiverRef']); $receiverRef = $this->sanitizeReceiverRef($recvSel['receiverOptions'], $receiverRef); if ($receiverRef === '') { $receiverRef = $recvSel['defaultReceiverRef']; } // 조회 화면에서는 입고완료 행도 함께 보여 미입고량 0을 확인할 수 있게 한다. $rows = $this->buildReceivingCandidateRows($lgIdx, $companyIdx, $bagCode, false, ''); return $this->render( '일괄 입고', 'bag/receiving_batch', [ 'companyIdx' => $companyIdx, 'bagCode' => $bagCode, 'companies' => $companies, 'bagCodeOptions' => $bagCodeOptions, 'receiverOptions' => $recvSel['receiverOptions'], 'receiverRef' => $receiverRef, 'senders' => $pick['senders'], 'senderIdx' => (int) old('br_sender_idx', $pick['defaultSenderIdx']), 'rows' => $rows, ] ); } public function receivingBatchStore(): RedirectResponse { helper('admin'); $lgIdx = $this->lgIdx(); if (! $lgIdx) { return redirect()->to(site_url('bag/purchase-inbound'))->with('error', '지자체를 선택해 주세요.'); } $companyIdx = (int) ($this->request->getPost('company_idx') ?? 0); $bagCode = trim((string) ($this->request->getPost('bag_code') ?? '')); $selected = $this->request->getPost('selected_rows'); $selected = is_array($selected) ? array_map('strval', $selected) : []; $receiveDate = (string) ($this->request->getPost('br_receive_date') ?? date('Y-m-d')); $recvSel = $this->receivingReceiverSelect($lgIdx); $receiverRef = (string) ($this->request->getPost('br_receiver_ref') ?? ''); $receiverRef = $this->sanitizeReceiverRef($recvSel['receiverOptions'], $receiverRef); if ($receiverRef === '') { $receiverRef = $recvSel['defaultReceiverRef']; } $receiverIdx = $this->parseReceiverRefToStoredIdx($lgIdx, $receiverRef); $senderIdx = (int) ($this->request->getPost('br_sender_idx') ?? 0); if (empty($selected)) { return redirect()->back()->withInput()->with('error', '일괄 입고할 행을 선택해 주세요.'); } if (! preg_match('/^\d{4}-\d{2}-\d{2}$/', $receiveDate)) { return redirect()->back()->withInput()->with('error', '입고일 형식을 확인해 주세요.'); } if ($receiverIdx <= 0) { return redirect()->back()->withInput()->with('error', '인수자를 선택해 주세요.'); } $senderResolved = $this->resolveCompanySenderName($lgIdx, $senderIdx); $rows = $this->buildReceivingCandidateRows($lgIdx, 0, '', true, ''); $rowMap = []; foreach ($rows as $row) { $rowMap[(string) $row['row_key']] = $row; } $insertRows = []; foreach ($selected as $rowKey) { if (! isset($rowMap[$rowKey])) { continue; } $base = $rowMap[$rowKey]; $qty = (int) ($base['pending_qty_sheet'] ?? 0); if ($qty <= 0) { continue; } $totalPerBox = max(1, (int) ($base['total_per_box'] ?? 1)); $qtyBox = intdiv($qty, $totalPerBox); $sender = $senderResolved !== '' ? $senderResolved : (string) ($base['company_rep_name'] ?? ''); $insertRows[] = [ 'br_bo_idx' => (int) $base['bo_idx'], 'br_lg_idx' => $lgIdx, 'br_bag_code' => (string) $base['bag_code'], 'br_bag_name' => (string) $base['bag_name'], 'br_qty_box' => $qtyBox, 'br_qty_sheet' => $qty, 'br_receive_date' => $receiveDate, 'br_receiver_idx' => $receiverIdx, 'br_sender_name' => $sender, 'br_type' => 'batch', 'br_regdate' => date('Y-m-d H:i:s'), ]; } if (empty($insertRows)) { return redirect()->back()->withInput()->with('error', '선택한 행에 입고할 수량이 없습니다.'); } $recvModel = model(BagReceivingModel::class); $invModel = model(BagInventoryModel::class); $db = \Config\Database::connect(); $db->transStart(); foreach ($insertRows as $row) { $recvModel->insert($row); $invModel->adjustQty( $lgIdx, (string) $row['br_bag_code'], (string) $row['br_bag_name'], (int) $row['br_qty_sheet'] ); } $db->transComplete(); if (! $db->transStatus()) { return redirect()->back()->withInput()->with('error', '일괄 입고 처리 중 오류가 발생했습니다.'); } return redirect()->to(site_url('bag/receiving/batch?company_idx=' . $companyIdx . '&bag_code=' . rawurlencode($bagCode))) ->with('success', count($insertRows) . '건 일괄 입고 처리되었습니다.'); } public function receivingStatus(): string|RedirectResponse { helper('admin'); $lgIdx = $this->lgIdx(); if (! $lgIdx) { return redirect()->to(site_url('bag/purchase-inbound'))->with('error', '지자체를 선택해 주세요.'); } $startDate = (string) ($this->request->getGet('start_date') ?? date('Y-m-01')); $endDate = (string) ($this->request->getGet('end_date') ?? date('Y-m-d')); $companyIdx = (int) ($this->request->getGet('company_idx') ?? 0); $bagCode = trim((string) ($this->request->getGet('bag_code') ?? '')); $receiveType = (string) ($this->request->getGet('receive_type') ?? 'all'); if (! in_array($receiveType, ['all', 'completed', 'pending'], true)) { $receiveType = 'all'; } $companies = model(CompanyModel::class) ->where('cp_lg_idx', $lgIdx) ->where('cp_type', '제작업체') ->where('cp_state', 1) ->orderBy('cp_name', 'ASC') ->findAll(); $kind = model(CodeKindModel::class)->where('ck_code', 'O')->first(); $bagCodeOptions = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx) : []; $rows = $this->buildReceivingStatusRows($lgIdx, $startDate, $endDate, $companyIdx, $bagCode, $receiveType); $groupTotals = []; $grandTotalReceive = 0; foreach ($rows as $row) { $key = (string) ($row['display_date'] ?? ''); if (! isset($groupTotals[$key])) { $groupTotals[$key] = 0; } $groupTotals[$key] += (int) ($row['received_qty_sheet'] ?? 0); $grandTotalReceive += (int) ($row['received_qty_sheet'] ?? 0); } return $this->render( '입고 현황', 'bag/receiving_status', compact( 'startDate', 'endDate', 'companyIdx', 'bagCode', 'receiveType', 'companies', 'bagCodeOptions', 'rows', 'groupTotals', 'grandTotalReceive' ) ); } public function receivingStatusExport(): RedirectResponse { helper(['admin', 'export']); $lgIdx = $this->lgIdx(); if (! $lgIdx) { return redirect()->to(site_url('bag/purchase-inbound'))->with('error', '지자체를 선택해 주세요.'); } $startDate = (string) ($this->request->getGet('start_date') ?? date('Y-m-01')); $endDate = (string) ($this->request->getGet('end_date') ?? date('Y-m-d')); $companyIdx = (int) ($this->request->getGet('company_idx') ?? 0); $bagCode = trim((string) ($this->request->getGet('bag_code') ?? '')); $receiveType = (string) ($this->request->getGet('receive_type') ?? 'all'); if (! in_array($receiveType, ['all', 'completed', 'pending'], true)) { $receiveType = 'all'; } $rows = $this->buildReceivingStatusRows($lgIdx, $startDate, $endDate, $companyIdx, $bagCode, $receiveType); $exportRows = []; foreach ($rows as $row) { $exportRows[] = [ (string) ($row['display_date'] ?? ''), (string) ($row['bag_name'] ?? ''), (int) ($row['received_qty_sheet'] ?? 0), (string) ($row['order_date'] ?? ''), (int) ($row['order_qty_sheet'] ?? 0), (string) ($row['order_no'] ?? ''), (string) ($row['company_name'] ?? ''), (string) ($row['receive_status_label'] ?? ''), (string) ($row['agency_name'] ?? ''), '', ]; } export_xlsx( '입고현황_' . date('Ymd'), '입고현황', ['입고일자', '품명', '입고수량', '발주일자', '발주수량', '발주번호', '제작업체', '입고여부', '입고처', '비고'], $exportRows ); } /** * 미입고 잔량이 있는 발주 LOT 목록(스캐너 입고용 드롭다운). * * @return list */ private function buildReceivingPendingLotChoices(int $lgIdx, int $companyIdx = 0): array { $rows = $this->buildReceivingCandidateRows($lgIdx, $companyIdx, '', true, ''); $byLot = []; foreach ($rows as $r) { $lot = (string) ($r['lot_no'] ?? ''); if ($lot === '') { continue; } if (! isset($byLot[$lot])) { $byLot[$lot] = [ 'lot_no' => $lot, 'bo_idx' => (int) ($r['bo_idx'] ?? 0), 'order_date' => (string) ($r['order_date'] ?? ''), 'company_name' => (string) ($r['company_name'] ?? ''), 'pending_lines' => 0, ]; } $byLot[$lot]['pending_lines']++; } $list = array_values($byLot); usort($list, static function (array $a, array $b): int { $da = (string) ($a['order_date'] ?? ''); $db = (string) ($b['order_date'] ?? ''); if ($da === $db) { return strcmp((string) ($b['lot_no'] ?? ''), (string) ($a['lot_no'] ?? '')); } return strcmp($db, $da); }); return $list; } private function sanitizeLotNoForReceiving(int $lgIdx, int $companyIdx, string $lotNo): string { $lotNo = trim($lotNo); if ($lotNo === '') { return ''; } foreach ($this->buildReceivingPendingLotChoices($lgIdx, $companyIdx) as $choice) { if ((string) ($choice['lot_no'] ?? '') === $lotNo) { return $lotNo; } } return ''; } /** * 선택 조건(제작업체 + LOT)에 해당하는 미입고 품목(봉투) 목록 — 조회 조건 드롭다운용. * * @return list */ private function receivingBagFilterOptions(int $lgIdx, int $companyIdx, string $lotNo = ''): array { if ($companyIdx <= 0) { return []; } $allForFilter = $this->buildReceivingCandidateRows($lgIdx, $companyIdx, '', true, $lotNo); $byCode = []; foreach ($allForFilter as $r) { $c = (string) ($r['bag_code'] ?? ''); if ($c === '') { continue; } if (! isset($byCode[$c])) { $byCode[$c] = (string) ($r['bag_name'] ?? ''); } } $list = []; foreach ($byCode as $code => $name) { $list[] = ['bag_code' => $code, 'bag_name' => $name]; } usort($list, static fn (array $a, array $b): int => strcmp($a['bag_name'], $b['bag_name'])); return $list; } private function sanitizeBagCodeForReceiving(int $lgIdx, int $companyIdx, string $lotNo, string $bagCode): string { $bagCode = trim($bagCode); if ($bagCode === '' || $companyIdx <= 0) { return ''; } foreach ($this->receivingBagFilterOptions($lgIdx, $companyIdx, $lotNo) as $opt) { if ($opt['bag_code'] === $bagCode) { return $bagCode; } } return ''; } /** * 입고 대상 후보(LOT-봉투행) 생성. * * @param string $lotNo 빈 문자열이면 LOT 제한 없음. 지정 시 해당 LOT(최신 헤드) 발주만. */ private function buildReceivingCandidateRows(int $lgIdx, int $companyIdx = 0, string $bagCode = '', bool $onlyPending = true, string $lotNo = ''): array { $orderBuilder = model(BagOrderModel::class) ->where('bo_lg_idx', $lgIdx) ->whereLatestHead($lgIdx) ->where('bo_status', 'normal') ->orderBy('bo_order_date', 'DESC') ->orderBy('bo_idx', 'DESC'); if ($lotNo !== '') { $orderBuilder->where('bo_lot_no', $lotNo); } if ($companyIdx > 0) { $orderBuilder->where('bo_company_idx', $companyIdx); } $orders = $orderBuilder->findAll(); if (empty($orders)) { return []; } $orderIds = array_map(static fn($o) => (int) ($o->bo_idx ?? 0), $orders); $companyMap = []; foreach (model(CompanyModel::class)->where('cp_lg_idx', $lgIdx)->where('cp_type', '제작업체')->findAll() as $company) { $companyMap[(int) ($company->cp_idx ?? 0)] = [ 'name' => (string) ($company->cp_name ?? ''), 'rep' => (string) ($company->cp_rep_name ?? ''), ]; } $agencyMap = []; foreach (model(SalesAgencyModel::class)->where('sa_lg_idx', $lgIdx)->orderForDisplay()->findAll() as $agency) { $agencyMap[(int) ($agency->sa_idx ?? 0)] = (string) ($agency->sa_name ?? ''); } $unitMap = []; foreach (model(PackagingUnitModel::class)->where('pu_lg_idx', $lgIdx)->where('pu_state', 1)->findAll() as $unit) { $unitMap[(string) ($unit->pu_bag_code ?? '')] = [ 'pack_per_sheet' => (int) ($unit->pu_pack_per_sheet ?? 1), 'total_per_box' => (int) ($unit->pu_total_per_box ?? 1), ]; } $itemBuilder = model(BagOrderItemModel::class)->whereIn('boi_bo_idx', $orderIds); if ($bagCode !== '') { $itemBuilder->where('boi_bag_code', $bagCode); } $items = $itemBuilder->orderBy('boi_bo_idx', 'DESC')->orderBy('boi_idx', 'ASC')->findAll(); $receivedRows = model(BagReceivingModel::class) ->select('br_bo_idx, br_bag_code, SUM(br_qty_sheet) as recv_qty_sheet, MAX(br_receive_date) as last_receive_date') ->where('br_lg_idx', $lgIdx) ->whereIn('br_bo_idx', $orderIds) ->groupBy('br_bo_idx, br_bag_code') ->findAll(); $receivedMap = []; foreach ($receivedRows as $recv) { $receivedMap[(int) ($recv->br_bo_idx ?? 0) . '|' . (string) ($recv->br_bag_code ?? '')] = [ 'recv_qty_sheet' => (int) ($recv->recv_qty_sheet ?? 0), 'last_receive_date' => (string) ($recv->last_receive_date ?? ''), ]; } $orderMap = []; foreach ($orders as $order) { $orderMap[(int) ($order->bo_idx ?? 0)] = $order; } $rows = []; foreach ($items as $item) { $boIdx = (int) ($item->boi_bo_idx ?? 0); if (! isset($orderMap[$boIdx])) { continue; } $order = $orderMap[$boIdx]; $itemBagCode = (string) ($item->boi_bag_code ?? ''); $recv = $receivedMap[$boIdx . '|' . $itemBagCode] ?? ['recv_qty_sheet' => 0, 'last_receive_date' => '']; $orderQtySheet = (int) ($item->boi_qty_sheet ?? 0); $receivedQtySheet = min($orderQtySheet, (int) ($recv['recv_qty_sheet'] ?? 0)); $pendingQtySheet = max(0, $orderQtySheet - $receivedQtySheet); if ($onlyPending && $pendingQtySheet <= 0) { continue; } $unit = $unitMap[$itemBagCode] ?? ['pack_per_sheet' => 1, 'total_per_box' => 1]; $companyInfo = $companyMap[(int) ($order->bo_company_idx ?? 0)] ?? ['name' => '', 'rep' => '']; $rows[] = [ 'row_key' => $boIdx . '|' . $itemBagCode, 'bo_idx' => $boIdx, 'order_no' => sprintf('%06d', $boIdx), 'lot_no' => (string) ($order->bo_lot_no ?? ''), 'order_date' => (string) ($order->bo_order_date ?? ''), 'company_name' => (string) ($companyInfo['name'] ?? ''), 'company_rep_name' => (string) ($companyInfo['rep'] ?? ''), 'agency_name' => (string) ($agencyMap[(int) ($order->bo_agency_idx ?? 0)] ?? ''), 'bag_code' => $itemBagCode, 'bag_name' => (string) ($item->boi_bag_name ?? ''), 'order_qty_sheet' => $orderQtySheet, 'received_qty_sheet' => $receivedQtySheet, 'pending_qty_sheet' => $pendingQtySheet, 'pack_per_sheet' => max(1, (int) ($unit['pack_per_sheet'] ?? 1)), 'total_per_box' => max(1, (int) ($unit['total_per_box'] ?? 1)), 'last_receive_date' => (string) ($recv['last_receive_date'] ?? ''), ]; } return $rows; } private function buildReceivingStatusRows( int $lgIdx, string $startDate, string $endDate, int $companyIdx, string $bagCode, string $receiveType ): array { $rows = $this->buildReceivingCandidateRows($lgIdx, $companyIdx, $bagCode, false, ''); $filtered = []; foreach ($rows as $row) { $pendingQty = (int) ($row['pending_qty_sheet'] ?? 0); $isCompleted = $pendingQty <= 0; if ($receiveType === 'completed' && ! $isCompleted) { continue; } if ($receiveType === 'pending' && $isCompleted) { continue; } $displayDate = (string) ($row['last_receive_date'] ?? ''); if ($displayDate === '') { $displayDate = (string) ($row['order_date'] ?? ''); } if ($startDate !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $startDate) && $displayDate < $startDate) { continue; } if ($endDate !== '' && preg_match('/^\d{4}-\d{2}-\d{2}$/', $endDate) && $displayDate > $endDate) { continue; } $row['display_date'] = $displayDate; $row['receive_status_label'] = $isCompleted ? '완료' : '미완료'; $filtered[] = $row; } usort($filtered, static function (array $a, array $b): int { $da = (string) ($a['display_date'] ?? ''); $db = (string) ($b['display_date'] ?? ''); if ($da === $db) { return strcmp((string) ($a['bag_name'] ?? ''), (string) ($b['bag_name'] ?? '')); } return strcmp($da, $db); }); return $filtered; } // --- 판매 등록 --- public function saleCreate(): string { helper('admin'); $lgIdx = $this->lgIdx(); $shops = $lgIdx ? model(DesignatedShopModel::class)->where('ds_lg_idx', $lgIdx)->where('ds_state', 1)->findAll() : []; $kind = model(CodeKindModel::class)->where('ck_code', 'O')->first(); $bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx) : []; return $this->render('판매 등록', 'bag/create_bag_sale', compact('shops', 'bagCodes')); } public function saleStore() { $admin = new \App\Controllers\Admin\BagSale(); $admin->initController($this->request, $this->response, service('logger')); $result = $admin->store(); if ($result instanceof \CodeIgniter\HTTP\RedirectResponse) { return redirect()->to(site_url('bag/sales'))->with('success', session()->getFlashdata('success'))->with('errors', session()->getFlashdata('errors')); } return redirect()->to(site_url('bag/sales'))->with('success', '판매 등록되었습니다.'); } // --- 주문 접수 --- public function shopOrderCreate(): string { helper('admin'); $lgIdx = $this->lgIdx(); $shops = $lgIdx ? model(DesignatedShopModel::class)->where('ds_lg_idx', $lgIdx)->where('ds_state', 1)->findAll() : []; $kind = model(CodeKindModel::class)->where('ck_code', 'O')->first(); $bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx) : []; return $this->render('주문 접수', 'bag/create_shop_order', compact('shops', 'bagCodes')); } public function shopOrderStore() { $admin = new \App\Controllers\Admin\ShopOrder(); $admin->initController($this->request, $this->response, service('logger')); $result = $admin->store(); if ($result instanceof \CodeIgniter\HTTP\RedirectResponse) { return redirect()->to(site_url('bag/sales'))->with('success', session()->getFlashdata('success'))->with('errors', session()->getFlashdata('errors')); } return redirect()->to(site_url('bag/sales'))->with('success', '주문 접수되었습니다.'); } }