P2-15~18, P5-04~11, CT-05~06 웹 미구현 기능 전체 구현
P2-15: 지정판매소 다조건 조회 (이름/구군/상태 필터) P2-17: 지정판매소 지도 표시 (Kakao Maps) P2-18: 지정판매소 현황 (연도별 신규/취소 통계) P5-04: 년 판매 현황 (월별 피벗 테이블) P5-05: 지정판매소별 판매현황 (판매소별 수량/금액) P5-06: 홈택스 세금계산서 엑셀 내보내기 P5-08: 반품/파기 현황 (기간별 조회) P5-10: LOT 수불 조회 (LOT 번호 검색) P5-11: 기타 입출고 (등록 + 재고 연동) CT-05: CRUD 로깅 (activity_log 테이블 + audit_helper) CT-06: 대시보드 실 데이터 (발주/판매/재고/불출 통계) Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -78,7 +78,7 @@ class BagIssue extends BaseController
|
||||
$db = \Config\Database::connect();
|
||||
$db->transStart();
|
||||
|
||||
$this->issueModel->insert([
|
||||
$issueData = [
|
||||
'bi2_lg_idx' => $lgIdx,
|
||||
'bi2_year' => (int) $this->request->getPost('bi2_year'),
|
||||
'bi2_quarter' => (int) $this->request->getPost('bi2_quarter'),
|
||||
@@ -91,7 +91,13 @@ class BagIssue extends BaseController
|
||||
'bi2_qty' => $qty,
|
||||
'bi2_status' => 'normal',
|
||||
'bi2_regdate' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
];
|
||||
$this->issueModel->insert($issueData);
|
||||
$bi2Idx = (int) $this->issueModel->getInsertID();
|
||||
|
||||
// CT-05: 감사 로그
|
||||
helper('audit');
|
||||
audit_log('create', 'bag_issue', $bi2Idx, null, array_merge($issueData, ['bi2_idx' => $bi2Idx]));
|
||||
|
||||
// 재고 감산
|
||||
model(BagInventoryModel::class)->adjustQty($lgIdx, $bagCode, $bagName, -$qty);
|
||||
@@ -112,7 +118,11 @@ class BagIssue extends BaseController
|
||||
$db = \Config\Database::connect();
|
||||
$db->transStart();
|
||||
|
||||
$before = (array) $item;
|
||||
$this->issueModel->update($id, ['bi2_status' => 'cancelled']);
|
||||
// CT-05: 감사 로그
|
||||
helper('audit');
|
||||
audit_log('update', 'bag_issue', $id, $before, ['bi2_status' => 'cancelled']);
|
||||
// 재고 복원
|
||||
model(BagInventoryModel::class)->adjustQty((int) $item->bi2_lg_idx, $item->bi2_bag_code, $item->bi2_bag_name, (int) $item->bi2_qty);
|
||||
|
||||
|
||||
@@ -179,6 +179,10 @@ class BagOrder extends BaseController
|
||||
$this->orderModel->insert($orderData);
|
||||
$boIdx = (int) $this->orderModel->getInsertID();
|
||||
|
||||
// CT-05: 감사 로그
|
||||
helper('audit');
|
||||
audit_log('create', 'bag_order', $boIdx, null, array_merge($orderData, ['bo_idx' => $boIdx]));
|
||||
|
||||
// 품목 저장
|
||||
$bagCodes = $this->request->getPost('item_bag_code') ?? [];
|
||||
$qtyBoxes = $this->request->getPost('item_qty_box') ?? [];
|
||||
@@ -250,7 +254,10 @@ class BagOrder extends BaseController
|
||||
return redirect()->to(site_url('admin/bag-orders'))->with('error', '발주를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
$before = (array) $order;
|
||||
$this->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('admin/bag-orders'))->with('success', '발주가 취소되었습니다.');
|
||||
}
|
||||
|
||||
@@ -262,7 +269,10 @@ class BagOrder extends BaseController
|
||||
return redirect()->to(site_url('admin/bag-orders'))->with('error', '발주를 찾을 수 없습니다.');
|
||||
}
|
||||
|
||||
$before = (array) $order;
|
||||
$this->orderModel->update($id, ['bo_status' => 'deleted', 'bo_moddate' => date('Y-m-d H:i:s')]);
|
||||
helper('audit');
|
||||
audit_log('delete', 'bag_order', $id, $before, ['bo_status' => 'deleted']);
|
||||
return redirect()->to(site_url('admin/bag-orders'))->with('success', '발주가 삭제 처리되었습니다.');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -131,7 +131,7 @@ class BagSale extends BaseController
|
||||
$db = \Config\Database::connect();
|
||||
$db->transStart();
|
||||
|
||||
$this->saleModel->insert([
|
||||
$saleData = [
|
||||
'bs_lg_idx' => $lgIdx,
|
||||
'bs_ds_idx' => $dsIdx,
|
||||
'bs_ds_name' => $shop ? $shop->ds_name : '',
|
||||
@@ -143,7 +143,13 @@ class BagSale extends BaseController
|
||||
'bs_amount' => $unitPrice * abs($actualQty),
|
||||
'bs_type' => $type,
|
||||
'bs_regdate' => date('Y-m-d H:i:s'),
|
||||
]);
|
||||
];
|
||||
$this->saleModel->insert($saleData);
|
||||
$bsIdx = (int) $this->saleModel->getInsertID();
|
||||
|
||||
// CT-05: 감사 로그
|
||||
helper('audit');
|
||||
audit_log('create', 'bag_sale', $bsIdx, null, array_merge($saleData, ['bs_idx' => $bsIdx]));
|
||||
|
||||
// 재고 감산(판매) / 가산(반품)
|
||||
model(BagInventoryModel::class)->adjustQty($lgIdx, $bagCode, $detail ? $detail->cd_name : '', -$actualQty);
|
||||
|
||||
@@ -1,5 +1,7 @@
|
||||
<?php
|
||||
|
||||
declare(strict_types=1);
|
||||
|
||||
namespace App\Controllers\Admin;
|
||||
|
||||
use App\Controllers\BaseController;
|
||||
@@ -8,9 +10,82 @@ class Dashboard extends BaseController
|
||||
{
|
||||
public function index(): string
|
||||
{
|
||||
helper('admin');
|
||||
$lgIdx = admin_effective_lg_idx();
|
||||
|
||||
$stats = [
|
||||
'order_count' => 0,
|
||||
'order_amount' => 0,
|
||||
'sale_count' => 0,
|
||||
'sale_amount' => 0,
|
||||
'inventory_count' => 0,
|
||||
'issue_count_month'=> 0,
|
||||
'recent_orders' => [],
|
||||
'recent_sales' => [],
|
||||
];
|
||||
|
||||
if ($lgIdx) {
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
// 총 발주 건수/금액
|
||||
$orderStats = $db->query("
|
||||
SELECT COUNT(*) as cnt,
|
||||
COALESCE(SUM(sub.total_amt), 0) as total_amount
|
||||
FROM bag_order bo
|
||||
LEFT JOIN (
|
||||
SELECT boi_bo_idx, SUM(boi_amount) as total_amt
|
||||
FROM bag_order_item GROUP BY boi_bo_idx
|
||||
) sub ON sub.boi_bo_idx = bo.bo_idx
|
||||
WHERE bo.bo_lg_idx = ? AND bo.bo_status = 'normal'
|
||||
", [$lgIdx])->getRow();
|
||||
$stats['order_count'] = (int) ($orderStats->cnt ?? 0);
|
||||
$stats['order_amount'] = (int) ($orderStats->total_amount ?? 0);
|
||||
|
||||
// 총 판매 건수/금액
|
||||
$saleStats = $db->query("
|
||||
SELECT COUNT(*) as cnt, COALESCE(SUM(bs_amount), 0) as total_amount
|
||||
FROM bag_sale
|
||||
WHERE bs_lg_idx = ? AND bs_type = 'sale'
|
||||
", [$lgIdx])->getRow();
|
||||
$stats['sale_count'] = (int) ($saleStats->cnt ?? 0);
|
||||
$stats['sale_amount'] = (int) ($saleStats->total_amount ?? 0);
|
||||
|
||||
// 현재 재고 품목 수
|
||||
$invCount = $db->query("
|
||||
SELECT COUNT(*) as cnt FROM bag_inventory WHERE bi_lg_idx = ? AND bi_qty > 0
|
||||
", [$lgIdx])->getRow();
|
||||
$stats['inventory_count'] = (int) ($invCount->cnt ?? 0);
|
||||
|
||||
// 이번 달 불출 건수
|
||||
$monthStart = date('Y-m-01');
|
||||
$issueCount = $db->query("
|
||||
SELECT COUNT(*) as cnt FROM bag_issue
|
||||
WHERE bi2_lg_idx = ? AND bi2_status = 'normal' AND bi2_issue_date >= ?
|
||||
", [$lgIdx, $monthStart])->getRow();
|
||||
$stats['issue_count_month'] = (int) ($issueCount->cnt ?? 0);
|
||||
|
||||
// 최근 발주 5건
|
||||
$stats['recent_orders'] = $db->query("
|
||||
SELECT bo_idx, bo_lot_no, bo_order_date, bo_status
|
||||
FROM bag_order
|
||||
WHERE bo_lg_idx = ?
|
||||
ORDER BY bo_order_date DESC, bo_idx DESC
|
||||
LIMIT 5
|
||||
", [$lgIdx])->getResult();
|
||||
|
||||
// 최근 판매 5건
|
||||
$stats['recent_sales'] = $db->query("
|
||||
SELECT bs_idx, bs_ds_name, bs_bag_name, bs_qty, bs_amount, bs_sale_date, bs_type
|
||||
FROM bag_sale
|
||||
WHERE bs_lg_idx = ?
|
||||
ORDER BY bs_sale_date DESC, bs_idx DESC
|
||||
LIMIT 5
|
||||
", [$lgIdx])->getResult();
|
||||
}
|
||||
|
||||
return view('admin/layout', [
|
||||
'title' => '대시보드',
|
||||
'content' => view('admin/dashboard/index'),
|
||||
'content' => view('admin/dashboard/index', ['stats' => $stats, 'lgIdx' => $lgIdx]),
|
||||
]);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -43,10 +43,24 @@ class DesignatedShop extends BaseController
|
||||
->with('error', '작업할 지자체가 선택되지 않았습니다. 지자체를 선택해 주세요.');
|
||||
}
|
||||
|
||||
$list = $this->shopModel
|
||||
->where('ds_lg_idx', $lgIdx)
|
||||
->orderBy('ds_idx', 'DESC')
|
||||
->paginate(20);
|
||||
$builder = $this->shopModel->where('ds_lg_idx', $lgIdx);
|
||||
|
||||
// 다조건 검색 (P2-15)
|
||||
$dsName = $this->request->getGet('ds_name');
|
||||
$dsGugunCode = $this->request->getGet('ds_gugun_code');
|
||||
$dsState = $this->request->getGet('ds_state');
|
||||
|
||||
if ($dsName !== null && $dsName !== '') {
|
||||
$builder->like('ds_name', $dsName);
|
||||
}
|
||||
if ($dsGugunCode !== null && $dsGugunCode !== '') {
|
||||
$builder->where('ds_gugun_code', $dsGugunCode);
|
||||
}
|
||||
if ($dsState !== null && $dsState !== '') {
|
||||
$builder->where('ds_state', (int) $dsState);
|
||||
}
|
||||
|
||||
$list = $builder->orderBy('ds_idx', 'DESC')->paginate(20);
|
||||
$pager = $this->shopModel->pager;
|
||||
|
||||
// 지자체 이름 매핑용
|
||||
@@ -55,12 +69,20 @@ class DesignatedShop extends BaseController
|
||||
$lgMap[$lg->lg_idx] = $lg->lg_name;
|
||||
}
|
||||
|
||||
// 구군코드 목록 (검색 필터용)
|
||||
$db = \Config\Database::connect();
|
||||
$gugunCodes = $db->query("SELECT DISTINCT ds_gugun_code FROM designated_shop WHERE ds_lg_idx = ? AND ds_gugun_code != '' ORDER BY ds_gugun_code", [$lgIdx])->getResult();
|
||||
|
||||
return view('admin/layout', [
|
||||
'title' => '지정판매소 관리',
|
||||
'content' => view('admin/designated_shop/index', [
|
||||
'list' => $list,
|
||||
'lgMap' => $lgMap,
|
||||
'pager' => $pager,
|
||||
'list' => $list,
|
||||
'lgMap' => $lgMap,
|
||||
'pager' => $pager,
|
||||
'dsName' => $dsName ?? '',
|
||||
'dsGugunCode' => $dsGugunCode ?? '',
|
||||
'dsState' => $dsState ?? '',
|
||||
'gugunCodes' => $gugunCodes,
|
||||
]),
|
||||
]);
|
||||
}
|
||||
@@ -317,6 +339,78 @@ class DesignatedShop extends BaseController
|
||||
->with('success', '지정판매소가 삭제되었습니다.');
|
||||
}
|
||||
|
||||
/**
|
||||
* P2-17: 지정판매소 지도 표시
|
||||
*/
|
||||
public function map()
|
||||
{
|
||||
helper('admin');
|
||||
$lgIdx = admin_effective_lg_idx();
|
||||
if ($lgIdx === null || $lgIdx <= 0) {
|
||||
return redirect()->to(site_url('admin'))
|
||||
->with('error', '작업할 지자체가 선택되지 않았습니다.');
|
||||
}
|
||||
|
||||
$shops = $this->shopModel
|
||||
->where('ds_lg_idx', $lgIdx)
|
||||
->where('ds_state', 1)
|
||||
->findAll();
|
||||
|
||||
return view('admin/layout', [
|
||||
'title' => '지정판매소 지도',
|
||||
'content' => view('admin/designated_shop/map', [
|
||||
'shops' => $shops,
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* P2-18: 지정판매소 현황 (연도별 신규/취소)
|
||||
*/
|
||||
public function status()
|
||||
{
|
||||
helper('admin');
|
||||
$lgIdx = admin_effective_lg_idx();
|
||||
if ($lgIdx === null || $lgIdx <= 0) {
|
||||
return redirect()->to(site_url('admin'))
|
||||
->with('error', '작업할 지자체가 선택되지 않았습니다.');
|
||||
}
|
||||
|
||||
$db = \Config\Database::connect();
|
||||
|
||||
// 연도별 신규등록 건수 (ds_designated_at 기준)
|
||||
$newByYear = $db->query("
|
||||
SELECT YEAR(ds_designated_at) as yr, COUNT(*) as cnt
|
||||
FROM designated_shop
|
||||
WHERE ds_lg_idx = ? AND ds_designated_at IS NOT NULL
|
||||
GROUP BY YEAR(ds_designated_at)
|
||||
ORDER BY yr DESC
|
||||
", [$lgIdx])->getResult();
|
||||
|
||||
// 연도별 취소/비활성 건수 (ds_state != 1, ds_regdate 기준)
|
||||
$cancelByYear = $db->query("
|
||||
SELECT YEAR(ds_regdate) as yr, COUNT(*) as cnt
|
||||
FROM designated_shop
|
||||
WHERE ds_lg_idx = ? AND ds_state != 1
|
||||
GROUP BY YEAR(ds_regdate)
|
||||
ORDER BY yr DESC
|
||||
", [$lgIdx])->getResult();
|
||||
|
||||
// 전체 현황 합계
|
||||
$totalActive = $this->shopModel->where('ds_lg_idx', $lgIdx)->where('ds_state', 1)->countAllResults(false);
|
||||
$totalInactive = $this->shopModel->where('ds_lg_idx', $lgIdx)->where('ds_state !=', 1)->countAllResults(false);
|
||||
|
||||
return view('admin/layout', [
|
||||
'title' => '지정판매소 현황',
|
||||
'content' => view('admin/designated_shop/status', [
|
||||
'newByYear' => $newByYear,
|
||||
'cancelByYear' => $cancelByYear,
|
||||
'totalActive' => $totalActive,
|
||||
'totalInactive' => $totalInactive,
|
||||
]),
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 지자체별 다음 판매소번호 생성 (lg_code + 3자리 일련번호)
|
||||
* 문서: docs/기본 개발계획/22-판매소번호_일련번호_결정.md §3
|
||||
|
||||
@@ -128,6 +128,264 @@ class SalesReport extends BaseController
|
||||
]);
|
||||
}
|
||||
|
||||
/**
|
||||
* 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: 봉투 수불 현황
|
||||
*/
|
||||
|
||||
Reference in New Issue
Block a user