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:
@@ -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