to(site_url('admin'))->with('error', '지자체를 선택해 주세요.'); $startDate = $this->request->getGet('start_date') ?? date('Y-m-01'); $endDate = $this->request->getGet('end_date') ?? date('Y-m-d'); $mode = $this->request->getGet('mode') ?? 'daily'; // daily or period $saleModel = model(BagSaleModel::class); $db = \Config\Database::connect(); if ($mode === 'daily') { $result = $db->query(" SELECT bs_sale_date, bs_ds_name, bs_bag_code, bs_bag_name, bs_type, SUM(ABS(bs_qty)) as total_qty, SUM(bs_amount) as total_amount FROM bag_sale WHERE bs_lg_idx = ? AND bs_sale_date BETWEEN ? AND ? AND bs_type IN('sale','return') GROUP BY bs_sale_date, bs_ds_name, bs_bag_code, bs_bag_name, bs_type ORDER BY bs_sale_date DESC, bs_ds_name, bs_bag_code ", [$lgIdx, $startDate, $endDate])->getResult(); } else { $result = $db->query(" SELECT bs_ds_name, bs_bag_code, bs_bag_name, SUM(CASE WHEN bs_type='sale' THEN ABS(bs_qty) ELSE 0 END) as sale_qty, SUM(CASE WHEN bs_type='sale' THEN bs_amount ELSE 0 END) as sale_amount, SUM(CASE WHEN bs_type='return' THEN ABS(bs_qty) ELSE 0 END) as return_qty, SUM(CASE WHEN bs_type='return' THEN bs_amount ELSE 0 END) as return_amount FROM bag_sale WHERE bs_lg_idx = ? AND bs_sale_date BETWEEN ? AND ? GROUP BY bs_ds_name, bs_bag_code, bs_bag_name ORDER BY bs_ds_name, bs_bag_code ", [$lgIdx, $startDate, $endDate])->getResult(); } return view('admin/layout', [ 'title' => '판매 대장', 'content' => view('admin/sales_report/sales_ledger', compact('result', 'startDate', 'endDate', 'mode')), ]); } /** * P5-02: 일계표 */ public function dailySummary() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if (!$lgIdx) return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.'); $date = $this->request->getGet('date') ?? date('Y-m-d'); $db = \Config\Database::connect(); // 당일 판매 $daily = $db->query(" SELECT bs_bag_code, bs_bag_name, SUM(CASE WHEN bs_type='sale' THEN ABS(bs_qty) ELSE 0 END) as sale_qty, SUM(CASE WHEN bs_type='sale' THEN bs_amount ELSE 0 END) as sale_amount FROM bag_sale WHERE bs_lg_idx = ? AND bs_sale_date = ? GROUP BY bs_bag_code, bs_bag_name ORDER BY bs_bag_code ", [$lgIdx, $date])->getResult(); // 당월 누계 $monthStart = date('Y-m-01', strtotime($date)); $monthly = $db->query(" SELECT bs_bag_code, bs_bag_name, SUM(CASE WHEN bs_type='sale' THEN ABS(bs_qty) ELSE 0 END) as sale_qty, SUM(CASE WHEN bs_type='sale' THEN bs_amount ELSE 0 END) as sale_amount FROM bag_sale WHERE bs_lg_idx = ? AND bs_sale_date BETWEEN ? AND ? GROUP BY bs_bag_code, bs_bag_name ORDER BY bs_bag_code ", [$lgIdx, $monthStart, $date])->getResult(); return view('admin/layout', [ 'title' => '일계표', 'content' => view('admin/sales_report/daily_summary', compact('daily', 'monthly', 'date')), ]); } /** * P5-03: 기간별 판매현황 */ public function periodSales() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if (!$lgIdx) return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.'); $startDate = $this->request->getGet('start_date') ?? date('Y-m-01'); $endDate = $this->request->getGet('end_date') ?? date('Y-m-d'); $db = \Config\Database::connect(); $result = $db->query(" SELECT bs_bag_code, bs_bag_name, SUM(CASE WHEN bs_type='sale' THEN ABS(bs_qty) ELSE 0 END) as sale_qty, SUM(CASE WHEN bs_type='sale' THEN bs_amount ELSE 0 END) as sale_amount, SUM(CASE WHEN bs_type='return' THEN ABS(bs_qty) ELSE 0 END) as return_qty, SUM(CASE WHEN bs_type='return' THEN bs_amount ELSE 0 END) as return_amount FROM bag_sale WHERE bs_lg_idx = ? AND bs_sale_date BETWEEN ? AND ? GROUP BY bs_bag_code, bs_bag_name ORDER BY bs_bag_code ", [$lgIdx, $startDate, $endDate])->getResult(); return view('admin/layout', [ 'title' => '기간별 판매현황', 'content' => view('admin/sales_report/period_sales', compact('result', 'startDate', 'endDate')), ]); } /** * P5-04: 년 판매 현황 (월별) */ public function yearlySales() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if (!$lgIdx) return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.'); $year = $this->request->getGet('year') ?? date('Y'); $db = \Config\Database::connect(); $result = $db->query(" SELECT bs_bag_code, bs_bag_name, SUM(CASE WHEN MONTH(bs_sale_date)=1 THEN ABS(bs_qty) ELSE 0 END) as m01, SUM(CASE WHEN MONTH(bs_sale_date)=2 THEN ABS(bs_qty) ELSE 0 END) as m02, SUM(CASE WHEN MONTH(bs_sale_date)=3 THEN ABS(bs_qty) ELSE 0 END) as m03, SUM(CASE WHEN MONTH(bs_sale_date)=4 THEN ABS(bs_qty) ELSE 0 END) as m04, SUM(CASE WHEN MONTH(bs_sale_date)=5 THEN ABS(bs_qty) ELSE 0 END) as m05, SUM(CASE WHEN MONTH(bs_sale_date)=6 THEN ABS(bs_qty) ELSE 0 END) as m06, SUM(CASE WHEN MONTH(bs_sale_date)=7 THEN ABS(bs_qty) ELSE 0 END) as m07, SUM(CASE WHEN MONTH(bs_sale_date)=8 THEN ABS(bs_qty) ELSE 0 END) as m08, SUM(CASE WHEN MONTH(bs_sale_date)=9 THEN ABS(bs_qty) ELSE 0 END) as m09, SUM(CASE WHEN MONTH(bs_sale_date)=10 THEN ABS(bs_qty) ELSE 0 END) as m10, SUM(CASE WHEN MONTH(bs_sale_date)=11 THEN ABS(bs_qty) ELSE 0 END) as m11, SUM(CASE WHEN MONTH(bs_sale_date)=12 THEN ABS(bs_qty) ELSE 0 END) as m12, SUM(ABS(bs_qty)) as total FROM bag_sale WHERE bs_lg_idx = ? AND YEAR(bs_sale_date) = ? AND bs_type = 'sale' GROUP BY bs_bag_code, bs_bag_name ORDER BY bs_bag_code ", [$lgIdx, $year])->getResult(); return view('admin/layout', [ 'title' => '년 판매 현황', 'content' => view('admin/sales_report/yearly_sales', compact('result', 'year')), ]); } /** * P5-05: 지정판매소별 판매현황 */ public function shopSales() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if (!$lgIdx) return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.'); $startDate = $this->request->getGet('start_date') ?? date('Y-m-01'); $endDate = $this->request->getGet('end_date') ?? date('Y-m-d'); $db = \Config\Database::connect(); $result = $db->query(" SELECT bs_ds_name, SUM(CASE WHEN bs_type='sale' THEN ABS(bs_qty) ELSE 0 END) as sale_qty, SUM(CASE WHEN bs_type='sale' THEN bs_amount ELSE 0 END) as sale_amount, SUM(CASE WHEN bs_type='return' THEN ABS(bs_qty) ELSE 0 END) as return_qty, SUM(CASE WHEN bs_type='return' THEN ABS(bs_amount) ELSE 0 END) as return_amount FROM bag_sale WHERE bs_lg_idx = ? AND bs_sale_date BETWEEN ? AND ? GROUP BY bs_ds_name ORDER BY bs_ds_name ", [$lgIdx, $startDate, $endDate])->getResult(); return view('admin/layout', [ 'title' => '지정판매소별 판매현황', 'content' => view('admin/sales_report/shop_sales', compact('result', 'startDate', 'endDate')), ]); } /** * P5-06: 홈택스 세금계산서 엑셀 내보내기 */ public function hometaxExport() { helper(['admin', 'export']); $lgIdx = admin_effective_lg_idx(); if (!$lgIdx) return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.'); $startDate = $this->request->getGet('start_date') ?? date('Y-m-01'); $endDate = $this->request->getGet('end_date') ?? date('Y-m-d'); $db = \Config\Database::connect(); $rows = $db->query(" SELECT bs.bs_sale_date, ds.ds_biz_no as buyer_biz_no, ds.ds_name as buyer_name, bs.bs_bag_name, ABS(bs.bs_qty) as qty, bs.bs_unit_price, bs.bs_amount FROM bag_sale bs LEFT JOIN designated_shop ds ON bs.bs_ds_idx = ds.ds_idx WHERE bs.bs_lg_idx = ? AND bs.bs_sale_date BETWEEN ? AND ? AND bs.bs_type = 'sale' ORDER BY bs.bs_sale_date, ds.ds_name ", [$lgIdx, $startDate, $endDate])->getResult(); // 지자체 정보 (공급자) $lg = model(\App\Models\LocalGovernmentModel::class)->find($lgIdx); $supplierBizNo = $lg->lg_biz_no ?? ''; $supplierName = $lg->lg_name ?? ''; $csvRows = []; foreach ($rows as $row) { $amount = (int) $row->bs_amount; $tax = (int) round($amount * 0.1); $csvRows[] = [ str_replace('-', '', $row->bs_sale_date), // 작성일자 (YYYYMMDD) $supplierBizNo, // 공급자사업자번호 $supplierName, // 공급자상호 $row->buyer_biz_no ?? '', // 공급받는자사업자번호 $row->buyer_name ?? '', // 공급받는자상호 $row->bs_bag_name, // 품목 (int) $row->qty, // 수량 (int) $row->bs_unit_price, // 단가 $amount, // 공급가액 $tax, // 세액 ]; } export_csv( '홈택스_세금계산서_' . date('Ymd') . '.csv', ['작성일자', '공급자사업자번호', '공급자상호', '공급받는자사업자번호', '공급받는자상호', '품목', '수량', '단가', '공급가액', '세액'], $csvRows ); } /** * P5-08: 반품/파기 현황 */ public function returns() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if (!$lgIdx) return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.'); $startDate = $this->request->getGet('start_date') ?? date('Y-m-01'); $endDate = $this->request->getGet('end_date') ?? date('Y-m-d'); $db = \Config\Database::connect(); $result = $db->query(" SELECT bs_sale_date, bs_ds_name, bs_bag_code, bs_bag_name, bs_type, ABS(bs_qty) as qty, ABS(bs_amount) as amount FROM bag_sale WHERE bs_lg_idx = ? AND bs_sale_date BETWEEN ? AND ? AND bs_type IN('return','cancel') ORDER BY bs_sale_date DESC, bs_ds_name ", [$lgIdx, $startDate, $endDate])->getResult(); return view('admin/layout', [ 'title' => '반품/파기 현황', 'content' => view('admin/sales_report/returns', compact('result', 'startDate', 'endDate')), ]); } /** * P5-10: LOT 수불 조회 */ public function lotFlow() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if (!$lgIdx) return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.'); $lotNo = $this->request->getGet('lot_no') ?? ''; $order = null; $items = []; $receivings = []; if ($lotNo !== '') { $db = \Config\Database::connect(); $order = $db->query("SELECT * FROM bag_order WHERE bo_lg_idx = ? AND bo_lot_no = ?", [$lgIdx, $lotNo])->getRow(); if ($order) { $items = $db->query("SELECT * FROM bag_order_item WHERE boi_bo_idx = ? ORDER BY boi_bag_code", [(int) $order->bo_idx])->getResult(); $receivings = $db->query("SELECT * FROM bag_receiving WHERE br_bo_idx = ? ORDER BY br_receive_date", [(int) $order->bo_idx])->getResult(); } } return view('admin/layout', [ 'title' => 'LOT 수불 조회', 'content' => view('admin/sales_report/lot_flow', compact('lotNo', 'order', 'items', 'receivings')), ]); } /** * P5-11: 기타 입출고 목록 */ public function miscFlow() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if (!$lgIdx) return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.'); $startDate = $this->request->getGet('start_date') ?? date('Y-m-01'); $endDate = $this->request->getGet('end_date') ?? date('Y-m-d'); $db = \Config\Database::connect(); // bag_misc_flow 테이블이 존재하는지 확인 $tableExists = $db->query("SHOW TABLES LIKE 'bag_misc_flow'")->getNumRows() > 0; $result = []; if ($tableExists) { $result = $db->query(" SELECT * FROM bag_misc_flow WHERE bmf_lg_idx = ? AND bmf_date BETWEEN ? AND ? ORDER BY bmf_date DESC, bmf_idx DESC ", [$lgIdx, $startDate, $endDate])->getResult(); } // 봉투 코드 목록 $kindO = model(\App\Models\CodeKindModel::class)->where('ck_code', 'O')->first(); $bagCodes = $kindO ? model(\App\Models\CodeDetailModel::class)->getByKind((int) $kindO->ck_idx, true) : []; return view('admin/layout', [ 'title' => '기타 입출고', 'content' => view('admin/sales_report/misc_flow', compact('result', 'startDate', 'endDate', 'bagCodes', 'tableExists')), ]); } /** * P5-11: 기타 입출고 등록 처리 */ public function miscFlowStore() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if (!$lgIdx) return redirect()->to(site_url('admin/reports/misc-flow'))->with('error', '지자체를 선택해 주세요.'); $rules = [ 'bmf_type' => 'required|in_list[in,out]', 'bmf_bag_code' => 'required|max_length[50]', 'bmf_qty' => 'required|is_natural_no_zero', 'bmf_date' => 'required|valid_date[Y-m-d]', 'bmf_reason' => 'required|max_length[200]', ]; if (! $this->validate($rules)) { return redirect()->back()->withInput()->with('errors', $this->validator->getErrors()); } $bagCode = $this->request->getPost('bmf_bag_code'); $qty = (int) $this->request->getPost('bmf_qty'); $type = $this->request->getPost('bmf_type'); // 봉투명 조회 $kindO = model(\App\Models\CodeKindModel::class)->where('ck_code', 'O')->first(); $detail = $kindO ? model(\App\Models\CodeDetailModel::class)->where('cd_ck_idx', $kindO->ck_idx)->where('cd_code', $bagCode)->first() : null; $bagName = $detail ? $detail->cd_name : ''; $db = \Config\Database::connect(); $db->transStart(); $db->query(" INSERT INTO bag_misc_flow (bmf_lg_idx, bmf_type, bmf_bag_code, bmf_bag_name, bmf_qty, bmf_date, bmf_reason, bmf_regdate) VALUES (?, ?, ?, ?, ?, ?, ?, ?) ", [$lgIdx, $type, $bagCode, $bagName, $qty, $this->request->getPost('bmf_date'), $this->request->getPost('bmf_reason'), date('Y-m-d H:i:s')]); // 재고 조정 $delta = ($type === 'in') ? $qty : -$qty; model(BagInventoryModel::class)->adjustQty($lgIdx, $bagCode, $bagName, $delta); $db->transComplete(); return redirect()->to(site_url('admin/reports/misc-flow'))->with('success', '기타 입출고가 등록되었습니다.'); } /** * P5-07: 봉투 수불 현황 */ public function supplyDemand() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if (!$lgIdx) return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.'); $startDate = $this->request->getGet('start_date') ?? date('Y-m-01'); $endDate = $this->request->getGet('end_date') ?? date('Y-m-d'); $db = \Config\Database::connect(); // 입고 합계 $receiving = $db->query(" SELECT br_bag_code, br_bag_name, SUM(br_qty_sheet) as recv_qty FROM bag_receiving WHERE br_lg_idx = ? AND br_receive_date BETWEEN ? AND ? GROUP BY br_bag_code, br_bag_name ", [$lgIdx, $startDate, $endDate])->getResult(); // 판매 합계 $sales = $db->query(" SELECT bs_bag_code, bs_bag_name, SUM(CASE WHEN bs_type='sale' THEN ABS(bs_qty) ELSE 0 END) as sale_qty, SUM(CASE WHEN bs_type='return' THEN ABS(bs_qty) ELSE 0 END) as return_qty FROM bag_sale WHERE bs_lg_idx = ? AND bs_sale_date BETWEEN ? AND ? GROUP BY bs_bag_code, bs_bag_name ", [$lgIdx, $startDate, $endDate])->getResult(); // 불출 합계 $issues = $db->query(" SELECT bi2_bag_code, bi2_bag_name, SUM(bi2_qty) as issue_qty FROM bag_issue WHERE bi2_lg_idx = ? AND bi2_issue_date BETWEEN ? AND ? AND bi2_status = 'normal' GROUP BY bi2_bag_code, bi2_bag_name ", [$lgIdx, $startDate, $endDate])->getResult(); // 현재 재고 $inventory = model(BagInventoryModel::class)->where('bi_lg_idx', $lgIdx)->findAll(); return view('admin/layout', [ 'title' => '봉투 수불 현황', 'content' => view('admin/sales_report/supply_demand', compact('receiving', 'sales', 'issues', 'inventory', 'startDate', 'endDate')), ]); } }