$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 = []; $dbDiag = null; 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()); } } if ($this->request->getGet('db_diag') === '1') { $dbDiag = [ 'lg_idx' => $lgIdx, 'cfg_host' => null, 'cfg_port' => null, 'cfg_user' => null, 'db_name' => null, 'mysql_host' => null, 'mysql_port' => null, 'mysql_version' => null, 'packaging_unit' => null, 'code_kind' => null, 'code_detail' => null, 'error' => null, ]; try { $db = db_connect(); $cfg = config('Database')->default ?? []; $dbDiag['cfg_host'] = $cfg['hostname'] ?? null; $dbDiag['cfg_port'] = isset($cfg['port']) ? (string) $cfg['port'] : null; $dbDiag['cfg_user'] = $cfg['username'] ?? null; $dbDiag['db_name'] = $db->database; $meta = $db->query('SELECT @@hostname AS mysql_host, @@port AS mysql_port, @@version AS mysql_version, DATABASE() AS db_name')->getRowArray(); if (is_array($meta)) { $dbDiag['mysql_host'] = $meta['mysql_host'] ?? null; $dbDiag['mysql_port'] = isset($meta['mysql_port']) ? (string) $meta['mysql_port'] : null; $dbDiag['mysql_version'] = $meta['mysql_version'] ?? null; if (! empty($meta['db_name'])) { $dbDiag['db_name'] = (string) $meta['db_name']; } } $dbDiag['packaging_unit'] = (int) $db->table('packaging_unit')->where('pu_lg_idx', (int) $lgIdx)->countAllResults(); $dbDiag['code_kind'] = (int) $db->table('code_kind')->countAllResults(); $dbDiag['code_detail'] = (int) $db->table('code_detail')->countAllResults(); } catch (\Throwable $e) { $dbDiag['error'] = $e->getMessage(); log_message('error', '[packagingUnits][db_diag] {type}: {message}', [ 'type' => $e::class, 'message' => $e->getMessage(), ]); } } return $this->render('포장 단위', 'bag/packaging_units', [ 'packagingUnits' => $packagingUnits, 'dbDiag' => $dbDiag, ]); } /** * 기본코드 종류·세부코드 조회 전용 (사이트 메뉴 기본코드관리) */ public function codeKinds(): string { $kindModel = model(CodeKindModel::class); $detailModel = model(CodeDetailModel::class); $kinds = []; $countMap = []; $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'); return $this->render('기본코드관리', 'bag/code_kinds', [ 'codeKinds' => $kinds, 'countMap' => $countMap, 'canManageKinds' => Roles::canManageCodeKindMaster($level), ]); } /** * 기본코드 세부 목록 (사이트 레이아웃). 등록·수정·삭제 폼은 /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_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); 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)->whereIn('cp_type', ['제작업체', 'manufacturer'])->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)->where('cd_ck_idx', $kind->ck_idx)->where('cd_state', 1)->orderBy('cd_sort')->findAll() : []; return $this->render('발주 등록', 'bag/create_bag_order', compact('companies', 'agencies', 'bagCodes')); } public function orderStore() { $admin = new \App\Controllers\Admin\BagOrder(); $admin->initController($this->request, $this->response, service('logger')); $result = $admin->store(); if ($result instanceof \CodeIgniter\HTTP\RedirectResponse) { return redirect()->to(site_url('bag/purchase-inbound'))->with('success', session()->getFlashdata('success'))->with('errors', session()->getFlashdata('errors')); } return redirect()->to(site_url('bag/purchase-inbound'))->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 { helper('admin'); $lgIdx = $this->lgIdx(); $orders = $lgIdx ? model(BagOrderModel::class)->where('bo_lg_idx', $lgIdx)->where('bo_status', 'normal')->orderBy('bo_order_date', 'DESC')->findAll() : []; return $this->render('입고 처리', 'bag/create_bag_receiving', compact('orders')); } public function receivingStore() { $admin = new \App\Controllers\Admin\BagReceiving(); $admin->initController($this->request, $this->response, service('logger')); $result = $admin->store(); if ($result instanceof \CodeIgniter\HTTP\RedirectResponse) { return redirect()->to(site_url('bag/purchase-inbound'))->with('success', session()->getFlashdata('success'))->with('errors', session()->getFlashdata('errors')); } return redirect()->to(site_url('bag/purchase-inbound'))->with('success', '입고 처리되었습니다.'); } // --- 판매 등록 --- 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', '주문 접수되었습니다.'); } }