feat: improve bag price and packaging unit management

This commit is contained in:
taekyoungc
2026-04-08 00:21:53 +09:00
parent c2dc2fd38a
commit b5eed31b94
16 changed files with 362 additions and 160 deletions

View File

@@ -3,10 +3,10 @@
namespace App\Controllers\Admin;
use App\Controllers\BaseController;
use App\Models\BagPriceModel;
use App\Models\BagPriceHistoryModel;
use App\Models\CodeKindModel;
use App\Models\BagPriceModel;
use App\Models\CodeDetailModel;
use App\Models\CodeKindModel;
class BagPrice extends BaseController
{
@@ -23,36 +23,18 @@ class BagPrice extends BaseController
{
helper('admin');
$lgIdx = admin_effective_lg_idx();
if (!$lgIdx) {
return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.');
if ($lgIdx === null) {
return redirect()->to(work_area_home_url())->with('error', '지자체를 선택해 주세요.');
}
$builder = $this->priceModel->where('bp_lg_idx', $lgIdx);
$list = $this->priceModel->where('bp_lg_idx', $lgIdx)
->orderBy('bp_bag_code', 'ASC')
->orderBy('bp_start_date', 'DESC')
->paginate(20);
// 기간 필터 (P2-04)
$startDate = $this->request->getGet('start_date');
$endDate = $this->request->getGet('end_date');
if ($startDate) {
$builder->where('bp_start_date >=', $startDate);
}
if ($endDate) {
$builder->groupStart()
->where('bp_end_date IS NULL')
->orWhere('bp_end_date <=', $endDate)
->groupEnd();
}
$list = $builder->orderBy('bp_bag_code', 'ASC')->orderBy('bp_start_date', 'DESC')->paginate(20);
$pager = $this->priceModel->pager;
return view('admin/layout', [
'title' => '봉투 단가 관리',
'content' => view('admin/bag_price/index', [
'list' => $list,
'startDate' => $startDate,
'endDate' => $endDate,
'pager' => $pager,
]),
return $this->renderWorkPage('봉투 단가 관리', 'admin/bag_price/index', [
'list' => $list,
'pager' => $this->priceModel->pager,
]);
}
@@ -60,22 +42,18 @@ class BagPrice extends BaseController
{
helper('admin');
$lgIdx = admin_effective_lg_idx();
if (!$lgIdx) {
return redirect()->to(site_url('admin/bag-prices'))->with('error', '지자체를 선택해 주세요.');
if (! $lgIdx) {
return redirect()->to(mgmt_url('bag-prices'))->with('error', '지자체를 선택해 주세요.');
}
// 봉투명 코드(O) 목록
$kindModel = model(CodeKindModel::class);
$kind = $kindModel->where('ck_code', 'O')->first();
$bagCodes = [];
$kind = $kindModel->where('ck_code', 'O')->first();
$bagCodes = [];
if ($kind) {
$bagCodes = model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true);
$bagCodes = model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx);
}
return view('admin/layout', [
'title' => '봉투 단가 등록',
'content' => view('admin/bag_price/create', ['bagCodes' => $bagCodes]),
]);
return $this->renderWorkPage('봉투 단가 등록', 'admin/bag_price/create', ['bagCodes' => $bagCodes]);
}
public function store()
@@ -96,13 +74,12 @@ class BagPrice extends BaseController
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
}
// 봉투명 스냅샷
$bagCode = $this->request->getPost('bp_bag_code');
$bagCode = $this->request->getPost('bp_bag_code');
$kindModel = model(CodeKindModel::class);
$kind = $kindModel->where('ck_code', 'O')->first();
$bagName = '';
$kind = $kindModel->where('ck_code', 'O')->first();
$bagName = '';
if ($kind) {
$detail = model(CodeDetailModel::class)->where('cd_ck_idx', $kind->ck_idx)->where('cd_code', $bagCode)->first();
$detail = model(CodeDetailModel::class)->findResolvedByKindAndCode((int) $kind->ck_idx, (string) $bagCode, $lgIdx);
$bagName = $detail ? $detail->cd_name : '';
}
@@ -120,36 +97,34 @@ class BagPrice extends BaseController
'bp_reg_mb_idx' => session()->get('mb_idx'),
]);
return redirect()->to(site_url('admin/bag-prices'))->with('success', '봉투 단가가 등록되었습니다.');
return redirect()->to(mgmt_url('bag-prices'))->with('success', '봉투 단가가 등록되었습니다.');
}
public function edit(int $id)
{
helper('admin');
$item = $this->priceModel->find($id);
if (!$item || (int) $item->bp_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(site_url('admin/bag-prices'))->with('error', '단가 정보를 찾을 수 없습니다.');
$lgIdx = admin_effective_lg_idx();
$item = $this->priceModel->find($id);
if (! $item || (int) $item->bp_lg_idx !== $lgIdx) {
return redirect()->to(mgmt_url('bag-prices'))->with('error', '단가 정보를 찾을 수 없습니다.');
}
$kindModel = model(CodeKindModel::class);
$kind = $kindModel->where('ck_code', 'O')->first();
$bagCodes = [];
$kind = $kindModel->where('ck_code', 'O')->first();
$bagCodes = [];
if ($kind) {
$bagCodes = model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true);
$bagCodes = model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx);
}
return view('admin/layout', [
'title' => '봉투 단가 수정',
'content' => view('admin/bag_price/edit', ['item' => $item, 'bagCodes' => $bagCodes]),
]);
return $this->renderWorkPage('봉투 단가 수정', 'admin/bag_price/edit', ['item' => $item, 'bagCodes' => $bagCodes]);
}
public function update(int $id)
{
helper('admin');
$item = $this->priceModel->find($id);
if (!$item || (int) $item->bp_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(site_url('admin/bag-prices'))->with('error', '단가 정보를 찾을 수 없습니다.');
if (! $item || (int) $item->bp_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(mgmt_url('bag-prices'))->with('error', '단가 정보를 찾을 수 없습니다.');
}
$rules = [
@@ -165,7 +140,6 @@ class BagPrice extends BaseController
return redirect()->back()->withInput()->with('errors', $this->validator->getErrors());
}
// 이력 기록
$db = \Config\Database::connect();
$db->transStart();
@@ -175,12 +149,12 @@ class BagPrice extends BaseController
$newVal = (string) $this->request->getPost($field);
if ($oldVal !== $newVal) {
$this->historyModel->insert([
'bph_bp_idx' => $id,
'bph_field' => $field,
'bph_old_value' => $oldVal,
'bph_new_value' => $newVal,
'bph_changed_at'=> date('Y-m-d H:i:s'),
'bph_changed_by'=> session()->get('mb_idx'),
'bph_bp_idx' => $id,
'bph_field' => $field,
'bph_old_value' => $oldVal,
'bph_new_value' => $newVal,
'bph_changed_at' => date('Y-m-d H:i:s'),
'bph_changed_by' => session()->get('mb_idx'),
]);
}
}
@@ -197,34 +171,32 @@ class BagPrice extends BaseController
$db->transComplete();
return redirect()->to(site_url('admin/bag-prices'))->with('success', '봉투 단가가 수정되었습니다.');
return redirect()->to(mgmt_url('bag-prices'))->with('success', '봉투 단가가 수정되었습니다.');
}
public function delete(int $id)
{
helper('admin');
$item = $this->priceModel->find($id);
if (!$item || (int) $item->bp_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(site_url('admin/bag-prices'))->with('error', '단가 정보를 찾을 수 없습니다.');
if (! $item || (int) $item->bp_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(mgmt_url('bag-prices'))->with('error', '단가 정보를 찾을 수 없습니다.');
}
$this->priceModel->delete($id);
return redirect()->to(site_url('admin/bag-prices'))->with('success', '봉투 단가가 삭제되었습니다.');
return redirect()->to(mgmt_url('bag-prices'))->with('success', '봉투 단가가 삭제되었습니다.');
}
public function history(int $bpIdx)
{
helper('admin');
$item = $this->priceModel->find($bpIdx);
if (!$item || (int) $item->bp_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(site_url('admin/bag-prices'))->with('error', '단가 정보를 찾을 수 없습니다.');
if (! $item || (int) $item->bp_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(mgmt_url('bag-prices'))->with('error', '단가 정보를 찾을 수 없습니다.');
}
$list = $this->historyModel->where('bph_bp_idx', $bpIdx)->orderBy('bph_changed_at', 'DESC')->findAll();
return view('admin/layout', [
'title' => '단가 변경 이력 — ' . $item->bp_bag_name,
'content' => view('admin/bag_price/history', ['item' => $item, 'list' => $list]),
]);
return $this->renderWorkPage('단가 변경 이력 — ' . $item->bp_bag_name, 'admin/bag_price/history', ['item' => $item, 'list' => $list]);
}
}

View File

@@ -23,8 +23,8 @@ class PackagingUnit extends BaseController
{
helper('admin');
$lgIdx = admin_effective_lg_idx();
if (!$lgIdx) {
return redirect()->to(site_url('admin'))->with('error', '지자체를 선택해 주세요.');
if (! $lgIdx) {
return redirect()->to(work_area_home_url())->with('error', '지자체를 선택해 주세요.');
}
$builder = $this->unitModel->where('pu_lg_idx', $lgIdx);
@@ -38,31 +38,26 @@ class PackagingUnit extends BaseController
$builder->groupStart()->where('pu_end_date IS NULL')->orWhere('pu_end_date <=', $endDate)->groupEnd();
}
$list = $builder->orderBy('pu_bag_code', 'ASC')->orderBy('pu_start_date', 'DESC')->paginate(20);
$list = $builder->orderBy('pu_bag_code', 'ASC')->orderBy('pu_start_date', 'DESC')->paginate(20);
$pager = $this->unitModel->pager;
return view('admin/layout', [
'title' => '포장 단위 관리',
'content' => view('admin/packaging_unit/index', [
'list' => $list, 'startDate' => $startDate, 'endDate' => $endDate, 'pager' => $pager,
]),
return $this->renderWorkPage('포장 단위 관리', 'admin/packaging_unit/index', [
'list' => $list, 'startDate' => $startDate, 'endDate' => $endDate, 'pager' => $pager,
]);
}
public function create()
{
helper('admin');
if (!admin_effective_lg_idx()) {
return redirect()->to(site_url('admin/packaging-units'))->with('error', '지자체를 선택해 주세요.');
if (! admin_effective_lg_idx()) {
return redirect()->to(mgmt_url('packaging-units'))->with('error', '지자체를 선택해 주세요.');
}
$kind = model(CodeKindModel::class)->where('ck_code', 'O')->first();
$bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true) : [];
$lgIdx = admin_effective_lg_idx();
$kind = model(CodeKindModel::class)->where('ck_code', 'O')->first();
$bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx) : [];
return view('admin/layout', [
'title' => '포장 단위 등록',
'content' => view('admin/packaging_unit/create', ['bagCodes' => $bagCodes]),
]);
return $this->renderWorkPage('포장 단위 등록', 'admin/packaging_unit/create', ['bagCodes' => $bagCodes]);
}
public function store()
@@ -83,10 +78,10 @@ class PackagingUnit extends BaseController
}
$bagCode = $this->request->getPost('pu_bag_code');
$kind = model(CodeKindModel::class)->where('ck_code', 'O')->first();
$kind = model(CodeKindModel::class)->where('ck_code', 'O')->first();
$bagName = '';
if ($kind) {
$detail = model(CodeDetailModel::class)->where('cd_ck_idx', $kind->ck_idx)->where('cd_code', $bagCode)->first();
$detail = model(CodeDetailModel::class)->findResolvedByKindAndCode((int) $kind->ck_idx, (string) $bagCode, $lgIdx);
$bagName = $detail ? $detail->cd_name : '';
}
@@ -107,32 +102,30 @@ class PackagingUnit extends BaseController
'pu_reg_mb_idx' => session()->get('mb_idx'),
]);
return redirect()->to(site_url('admin/packaging-units'))->with('success', '포장 단위가 등록되었습니다.');
return redirect()->to(mgmt_url('packaging-units'))->with('success', '포장 단위가 등록되었습니다.');
}
public function edit(int $id)
{
helper('admin');
$item = $this->unitModel->find($id);
if (!$item || (int) $item->pu_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(site_url('admin/packaging-units'))->with('error', '포장 단위를 찾을 수 없습니다.');
if (! $item || (int) $item->pu_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(mgmt_url('packaging-units'))->with('error', '포장 단위를 찾을 수 없습니다.');
}
$kind = model(CodeKindModel::class)->where('ck_code', 'O')->first();
$bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true) : [];
$lgIdx = admin_effective_lg_idx();
$kind = model(CodeKindModel::class)->where('ck_code', 'O')->first();
$bagCodes = $kind ? model(CodeDetailModel::class)->getByKind((int) $kind->ck_idx, true, $lgIdx) : [];
return view('admin/layout', [
'title' => '포장 단위 수정',
'content' => view('admin/packaging_unit/edit', ['item' => $item, 'bagCodes' => $bagCodes]),
]);
return $this->renderWorkPage('포장 단위 수정', 'admin/packaging_unit/edit', ['item' => $item, 'bagCodes' => $bagCodes]);
}
public function update(int $id)
{
helper('admin');
$item = $this->unitModel->find($id);
if (!$item || (int) $item->pu_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(site_url('admin/packaging-units'))->with('error', '포장 단위를 찾을 수 없습니다.');
if (! $item || (int) $item->pu_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(mgmt_url('packaging-units'))->with('error', '포장 단위를 찾을 수 없습니다.');
}
$rules = [
@@ -156,12 +149,12 @@ class PackagingUnit extends BaseController
$newVal = (string) $this->request->getPost($field);
if ($oldVal !== $newVal) {
$this->historyModel->insert([
'puh_pu_idx' => $id,
'puh_field' => $field,
'puh_old_value' => $oldVal,
'puh_new_value' => $newVal,
'puh_changed_at'=> date('Y-m-d H:i:s'),
'puh_changed_by'=> session()->get('mb_idx'),
'puh_pu_idx' => $id,
'puh_field' => $field,
'puh_old_value' => $oldVal,
'puh_new_value' => $newVal,
'puh_changed_at' => date('Y-m-d H:i:s'),
'puh_changed_by' => session()->get('mb_idx'),
]);
}
}
@@ -180,34 +173,33 @@ class PackagingUnit extends BaseController
]);
$db->transComplete();
return redirect()->to(site_url('admin/packaging-units'))->with('success', '포장 단위가 수정되었습니다.');
return redirect()->to(mgmt_url('packaging-units'))->with('success', '포장 단위가 수정되었습니다.');
}
public function delete(int $id)
{
helper('admin');
$item = $this->unitModel->find($id);
if (!$item || (int) $item->pu_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(site_url('admin/packaging-units'))->with('error', '포장 단위를 찾을 수 없습니다.');
if (! $item || (int) $item->pu_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(mgmt_url('packaging-units'))->with('error', '포장 단위를 찾을 수 없습니다.');
}
$this->unitModel->delete($id);
return redirect()->to(site_url('admin/packaging-units'))->with('success', '포장 단위가 삭제되었습니다.');
return redirect()->to(mgmt_url('packaging-units'))->with('success', '포장 단위가 삭제되었습니다.');
}
public function history(int $puIdx)
{
helper('admin');
$item = $this->unitModel->find($puIdx);
if (!$item || (int) $item->pu_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(site_url('admin/packaging-units'))->with('error', '포장 단위를 찾을 수 없습니다.');
if (! $item || (int) $item->pu_lg_idx !== admin_effective_lg_idx()) {
return redirect()->to(mgmt_url('packaging-units'))->with('error', '포장 단위를 찾을 수 없습니다.');
}
$list = $this->historyModel->where('puh_pu_idx', $puIdx)->orderBy('puh_changed_at', 'DESC')->findAll();
return view('admin/layout', [
'title' => '포장 단위 변경 이력 — ' . $item->pu_bag_name,
'content' => view('admin/packaging_unit/history', ['item' => $item, 'list' => $list]),
]);
return $this->renderWorkPage('포장 단위 변경 이력 — ' . $item->pu_bag_name, 'admin/packaging_unit/history', ['item' => $item, 'list' => $list]);
}
}

View File

@@ -9,14 +9,14 @@ class PasswordChange extends BaseController
{
public function index()
{
return view('admin/layout', [
'title' => '비밀번호 변경',
'content' => view('admin/password_change/index'),
]);
helper('admin');
return $this->renderWorkPage('비밀번호 변경', 'admin/password_change/index');
}
public function update()
{
helper('admin');
$rules = [
'current_password' => 'required',
'new_password' => 'required|min_length[4]|max_length[255]',
@@ -50,6 +50,6 @@ class PasswordChange extends BaseController
'mb_passwd' => password_hash($this->request->getPost('new_password'), PASSWORD_DEFAULT),
]);
return redirect()->to(site_url('admin/password-change'))->with('success', '비밀번호가 변경되었습니다.');
return redirect()->to(mgmt_url('password-change'))->with('success', '비밀번호가 변경되었습니다.');
}
}

View File

@@ -2,7 +2,7 @@
<span class="text-sm font-bold text-gray-700">봉투 단가 등록</span>
</section>
<div class="border border-gray-300 p-4 mt-2 bg-white max-w-3xl">
<form action="<?= base_url('admin/bag-prices/store') ?>" method="POST" class="space-y-4">
<form action="<?= mgmt_url('bag-prices/store') ?>" method="POST" class="space-y-4">
<?= csrf_field() ?>
<div class="flex flex-wrap items-center gap-2">
@@ -48,7 +48,7 @@
<div class="flex gap-2 pt-2">
<button type="submit" class="bg-btn-search text-white px-6 py-1.5 rounded-sm text-sm shadow hover:opacity-90 transition">등록</button>
<a href="<?= base_url('admin/bag-prices') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
<a href="<?= mgmt_url('bag-prices') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
</div>
</form>
</div>

View File

@@ -2,7 +2,7 @@
<span class="text-sm font-bold text-gray-700">봉투 단가 수정</span>
</section>
<div class="border border-gray-300 p-4 mt-2 bg-white max-w-3xl">
<form action="<?= base_url('admin/bag-prices/update/' . (int) $item->bp_idx) ?>" method="POST" class="space-y-4">
<form action="<?= mgmt_url('bag-prices/update/' . (int) $item->bp_idx) ?>" method="POST" class="space-y-4">
<?= csrf_field() ?>
<div class="flex flex-wrap items-center gap-2">
@@ -49,7 +49,7 @@
<div class="flex gap-2 pt-2">
<button type="submit" class="bg-btn-search text-white px-6 py-1.5 rounded-sm text-sm shadow hover:opacity-90 transition">수정</button>
<a href="<?= base_url('admin/bag-prices') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
<a href="<?= mgmt_url('bag-prices') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
</div>
</form>
</div>

View File

@@ -1,6 +1,6 @@
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel">
<div class="flex items-center gap-2">
<a href="<?= base_url('admin/bag-prices') ?>" class="text-blue-600 hover:underline text-sm">&larr; 단가 목록</a>
<a href="<?= mgmt_url('bag-prices') ?>" class="text-blue-600 hover:underline text-sm">&larr; 단가 목록</a>
<span class="text-gray-400">|</span>
<span class="text-sm font-bold text-gray-700">단가 변경 이력 <?= esc($item->bp_bag_name) ?> (<?= esc($item->bp_bag_code) ?>)</span>
</div>

View File

@@ -1,23 +1,20 @@
<?= view('components/print_header', ['printTitle' => '봉투 단가 관리']) ?>
<style>
@media print {
.no-print { display: none !important; }
}
</style>
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel">
<div class="flex flex-wrap items-center justify-between gap-y-2">
<span class="text-sm font-bold text-gray-700">봉투 단가 관리</span>
<div class="flex items-center gap-2">
<button onclick="window.print()" class="no-print border border-btn-print-border text-gray-600 px-3 py-1 rounded-sm text-sm hover:bg-gray-50 transition">인쇄</button>
<a href="<?= base_url('admin/bag-prices/create') ?>" class="bg-btn-search text-white px-4 py-1.5 rounded-sm flex items-center gap-1 text-sm shadow hover:opacity-90 transition border border-transparent">단가 등록</a>
<div class="flex items-center gap-2 no-print">
<button onclick="window.print()" class="border border-btn-print-border text-gray-600 px-3 py-1 rounded-sm text-sm hover:bg-gray-50 transition">인쇄</button>
<a href="<?= base_url('bag/prices') ?>" class="text-blue-600 hover:underline text-sm">단가 조회·검색</a>
<a href="<?= mgmt_url('bag-prices/create') ?>" class="bg-btn-search text-white px-4 py-1.5 rounded-sm flex items-center gap-1 text-sm shadow hover:opacity-90 transition border border-transparent">단가 등록</a>
</div>
</div>
</section>
<section class="p-2 bg-white border-b border-gray-200">
<form method="GET" action="<?= base_url('admin/bag-prices') ?>" class="flex flex-wrap items-center gap-2">
<label class="text-sm text-gray-600">적용시작일</label>
<input type="date" name="start_date" value="<?= esc($startDate ?? '') ?>" class="border border-gray-300 rounded px-2 py-1 text-sm"/>
<label class="text-sm text-gray-600">~</label>
<input type="date" name="end_date" value="<?= esc($endDate ?? '') ?>" class="border border-gray-300 rounded px-2 py-1 text-sm"/>
<button type="submit" class="bg-btn-search text-white px-4 py-1 rounded-sm text-sm">조회</button>
<a href="<?= base_url('admin/bag-prices') ?>" class="text-sm text-gray-500 hover:underline">초기화</a>
</form>
</section>
<p class="text-xs text-gray-500 mt-2 no-print">목록·등록·수정·삭제는 이 화면에서, <strong>기간·봉투별 조회·인쇄</strong>는 <a href="<?= base_url('bag/prices') ?>" class="text-blue-600 hover:underline">봉투 단가(조회)</a>에서 이용하세요.</p>
<div class="border border-gray-300 overflow-auto mt-2">
<table class="w-full data-table">
<thead>
@@ -31,7 +28,7 @@
<th>적용시작</th>
<th>적용종료</th>
<th class="w-20">상태</th>
<th class="w-36">작업</th>
<th class="w-36 no-print">작업</th>
</tr>
</thead>
<tbody class="text-right">
@@ -46,10 +43,10 @@
<td class="text-center"><?= esc($row->bp_start_date) ?></td>
<td class="text-center"><?= esc($row->bp_end_date ?? '현재') ?></td>
<td class="text-center"><?= (int) $row->bp_state === 1 ? '사용' : '미사용' ?></td>
<td class="text-center">
<a href="<?= base_url('admin/bag-prices/history/' . (int) $row->bp_idx) ?>" class="text-green-600 hover:underline text-sm mr-1">이력</a>
<a href="<?= base_url('admin/bag-prices/edit/' . (int) $row->bp_idx) ?>" class="text-blue-600 hover:underline text-sm mr-1">수정</a>
<form action="<?= base_url('admin/bag-prices/delete/' . (int) $row->bp_idx) ?>" method="POST" class="inline" onsubmit="return confirm('삭제하시겠습니까?');">
<td class="text-center no-print">
<a href="<?= mgmt_url('bag-prices/history/' . (int) $row->bp_idx) ?>" class="text-green-600 hover:underline text-sm mr-1">이력</a>
<a href="<?= mgmt_url('bag-prices/edit/' . (int) $row->bp_idx) ?>" class="text-blue-600 hover:underline text-sm mr-1">수정</a>
<form action="<?= mgmt_url('bag-prices/delete/' . (int) $row->bp_idx) ?>" method="POST" class="inline" onsubmit="return confirm('삭제하시겠습니까?');">
<?= csrf_field() ?>
<button type="submit" class="text-red-600 hover:underline text-sm">삭제</button>
</form>
@@ -62,4 +59,4 @@
</tbody>
</table>
</div>
<?php if (isset($pager)): ?><div class="mt-3"><?= $pager->links() ?></div><?php endif; ?>
<?php if (isset($pager)): ?><div class="mt-3 no-print"><?= $pager->links() ?></div><?php endif; ?>

View File

@@ -2,7 +2,7 @@
<span class="text-sm font-bold text-gray-700">포장 단위 등록</span>
</section>
<div class="border border-gray-300 p-4 mt-2 bg-white max-w-3xl">
<form action="<?= base_url('admin/packaging-units/store') ?>" method="POST" class="space-y-4">
<form action="<?= mgmt_url('packaging-units/store') ?>" method="POST" class="space-y-4">
<?= csrf_field() ?>
<div class="flex flex-wrap items-center gap-2">
@@ -42,7 +42,7 @@
<div class="flex gap-2 pt-2">
<button type="submit" class="bg-btn-search text-white px-6 py-1.5 rounded-sm text-sm shadow hover:opacity-90 transition">등록</button>
<a href="<?= base_url('admin/packaging-units') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
<a href="<?= mgmt_url('packaging-units') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
</div>
</form>
</div>

View File

@@ -2,7 +2,7 @@
<span class="text-sm font-bold text-gray-700">포장 단위 수정</span>
</section>
<div class="border border-gray-300 p-4 mt-2 bg-white max-w-3xl">
<form action="<?= base_url('admin/packaging-units/update/' . (int) $item->pu_idx) ?>" method="POST" class="space-y-4">
<form action="<?= mgmt_url('packaging-units/update/' . (int) $item->pu_idx) ?>" method="POST" class="space-y-4">
<?= csrf_field() ?>
<div class="flex flex-wrap items-center gap-2">
@@ -43,7 +43,7 @@
<div class="flex gap-2 pt-2">
<button type="submit" class="bg-btn-search text-white px-6 py-1.5 rounded-sm text-sm shadow hover:opacity-90 transition">수정</button>
<a href="<?= base_url('admin/packaging-units') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
<a href="<?= mgmt_url('packaging-units') ?>" class="bg-gray-200 text-gray-700 px-6 py-1.5 rounded-sm text-sm hover:bg-gray-300 transition">취소</a>
</div>
</form>
</div>

View File

@@ -1,6 +1,6 @@
<section class="border-b border-gray-300 p-2 shrink-0 bg-control-panel">
<div class="flex items-center gap-2">
<a href="<?= base_url('admin/packaging-units') ?>" class="text-blue-600 hover:underline text-sm">&larr; 포장 단위 목록</a>
<a href="<?= mgmt_url('packaging-units') ?>" class="text-blue-600 hover:underline text-sm">&larr; 포장 단위 목록</a>
<span class="text-gray-400">|</span>
<span class="text-sm font-bold text-gray-700">변경 이력 <?= esc($item->pu_bag_name) ?> (<?= esc($item->pu_bag_code) ?>)</span>
</div>

View File

@@ -4,18 +4,18 @@
<span class="text-sm font-bold text-gray-700">포장 단위 관리</span>
<div class="flex items-center gap-2">
<button onclick="window.print()" class="no-print border border-btn-print-border text-gray-600 px-3 py-1 rounded-sm text-sm hover:bg-gray-50 transition">인쇄</button>
<a href="<?= base_url('admin/packaging-units/create') ?>" class="bg-btn-search text-white px-4 py-1.5 rounded-sm flex items-center gap-1 text-sm shadow hover:opacity-90 transition border border-transparent">포장 단위 등록</a>
<a href="<?= mgmt_url('packaging-units/create') ?>" class="bg-btn-search text-white px-4 py-1.5 rounded-sm flex items-center gap-1 text-sm shadow hover:opacity-90 transition border border-transparent">포장 단위 등록</a>
</div>
</div>
</section>
<section class="p-2 bg-white border-b border-gray-200">
<form method="GET" action="<?= base_url('admin/packaging-units') ?>" class="flex flex-wrap items-center gap-2">
<form method="GET" action="<?= mgmt_url('packaging-units') ?>" class="flex flex-wrap items-center gap-2">
<label class="text-sm text-gray-600">적용시작일</label>
<input type="date" name="start_date" value="<?= esc($startDate ?? '') ?>" class="border border-gray-300 rounded px-2 py-1 text-sm"/>
<label class="text-sm text-gray-600">~</label>
<input type="date" name="end_date" value="<?= esc($endDate ?? '') ?>" class="border border-gray-300 rounded px-2 py-1 text-sm"/>
<button type="submit" class="bg-btn-search text-white px-4 py-1 rounded-sm text-sm">조회</button>
<a href="<?= base_url('admin/packaging-units') ?>" class="text-sm text-gray-500 hover:underline">초기화</a>
<a href="<?= mgmt_url('packaging-units') ?>" class="text-sm text-gray-500 hover:underline">초기화</a>
</form>
</section>
<div class="border border-gray-300 overflow-auto mt-2">
@@ -47,9 +47,9 @@
<td class="text-center"><?= esc($row->pu_end_date ?? '현재') ?></td>
<td class="text-center"><?= (int) $row->pu_state === 1 ? '사용' : '미사용' ?></td>
<td class="text-center">
<a href="<?= base_url('admin/packaging-units/history/' . (int) $row->pu_idx) ?>" class="text-green-600 hover:underline text-sm mr-1">이력</a>
<a href="<?= base_url('admin/packaging-units/edit/' . (int) $row->pu_idx) ?>" class="text-blue-600 hover:underline text-sm mr-1">수정</a>
<form action="<?= base_url('admin/packaging-units/delete/' . (int) $row->pu_idx) ?>" method="POST" class="inline" onsubmit="return confirm('삭제하시겠습니까?');">
<a href="<?= mgmt_url('packaging-units/history/' . (int) $row->pu_idx) ?>" class="text-green-600 hover:underline text-sm mr-1">이력</a>
<a href="<?= mgmt_url('packaging-units/edit/' . (int) $row->pu_idx) ?>" class="text-blue-600 hover:underline text-sm mr-1">수정</a>
<form action="<?= mgmt_url('packaging-units/delete/' . (int) $row->pu_idx) ?>" method="POST" class="inline" onsubmit="return confirm('삭제하시겠습니까?');">
<?= csrf_field() ?>
<button type="submit" class="text-red-600 hover:underline text-sm">삭제</button>
</form>

View File

@@ -2,7 +2,7 @@
<span class="text-sm font-bold text-gray-700">비밀번호 변경</span>
</section>
<div class="border border-gray-300 p-4 mt-2 bg-white max-w-md">
<form action="<?= base_url('admin/password-change') ?>" method="POST" class="space-y-4">
<form action="<?= mgmt_url('password-change') ?>" method="POST" class="space-y-4">
<?= csrf_field() ?>
<div class="flex flex-wrap items-center gap-2">

View File

@@ -0,0 +1,37 @@
<div class="space-y-4">
<p class="text-sm text-gray-600">
<a href="<?= base_url('bag/basic-info') ?>" class="text-blue-600 hover:underline">&larr; 기본정보관리</a>
<span class="mx-2 text-gray-300">|</span>
<a href="<?= base_url('bag/prices') ?>" class="text-blue-600 hover:underline">봉투 단가</a>
</p>
<section>
<div class="flex items-center justify-between mb-2 border-b pb-1">
<h3 class="text-base font-bold text-gray-700">포장 단위</h3>
<a href="<?= base_url('bag/packaging-units/manage') ?>" class="text-blue-600 hover:underline text-sm">관리 &rarr;</a>
</div>
<table class="data-table">
<thead><tr>
<th class="w-16">번호</th><th>봉투코드</th><th>봉투명</th><th>박스당 </th><th>팩당 낱장 </th><th>1박스 낱장</th><th>적용시작</th><th>적용종료</th><th>상태</th>
</tr></thead>
<tbody>
<?php if (! empty($packagingUnits)): ?>
<?php foreach ($packagingUnits as $i => $row): ?>
<tr>
<td class="text-center"><?= $i + 1 ?></td>
<td class="text-center"><?= esc($row->pu_bag_code) ?></td>
<td><?= esc($row->pu_bag_name ?? '') ?></td>
<td class="text-right"><?= number_format((int) ($row->pu_box_per_pack ?? 0)) ?></td>
<td class="text-right"><?= number_format((int) ($row->pu_pack_per_sheet ?? 0)) ?></td>
<td class="text-right"><?= number_format((int) ($row->pu_total_per_box ?? 0)) ?></td>
<td class="text-center"><?= esc($row->pu_start_date ?? '') ?></td>
<td class="text-center"><?= ($row->pu_end_date ?? '') !== '' && $row->pu_end_date !== null ? esc((string) $row->pu_end_date) : '현재' ?></td>
<td class="text-center"><?= (int) ($row->pu_state ?? 1) === 1 ? '사용' : '만료' ?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="9" class="text-center text-gray-400 py-4">등록된 포장 단위가 없습니다.</td></tr>
<?php endif; ?>
</tbody>
</table>
</section>
</div>

144
app/Views/bag/prices.php Normal file
View File

@@ -0,0 +1,144 @@
<?php
$_ph = ['printTitle' => '봉투 단가 조회', 'printExtraLines' => $printExtraLines ?? []];
if (($printLgName ?? '') !== '') {
$_ph['printLgName'] = $printLgName;
}
echo view('components/print_header', $_ph);
unset($_ph);
?>
<style>
@media print {
.no-print { display: none !important; }
}
</style>
<div class="space-y-4">
<p class="text-sm text-gray-600 no-print">
<a href="<?= base_url('bag/basic-info') ?>" class="text-blue-600 hover:underline">&larr; 기본정보관리</a>
<span class="mx-2 text-gray-300">|</span>
<a href="<?= base_url('bag/packaging-units') ?>" class="text-blue-600 hover:underline">포장 단위</a>
<span class="mx-2 text-gray-300">|</span>
<a href="<?= base_url('bag/bag-prices') ?>" class="text-blue-600 hover:underline">단가 관리(CRUD)</a>
</p>
<?php if (($lgIdx ?? null) === null): ?>
<p class="text-sm text-amber-800 bg-amber-50 border border-amber-200 rounded p-3">작업 지자체가 선택되지 않았습니다. 관리자는 지자체 선택 후 단가를 조회할 수 있습니다.</p>
<?php endif; ?>
<section class="no-print border border-gray-200 rounded-lg bg-white p-3">
<form method="post" action="<?= site_url('bag/prices') ?>" class="flex flex-wrap items-end gap-3" autocomplete="off">
<?= csrf_field() ?>
<div class="flex flex-col gap-0.5">
<label class="text-xs text-gray-500">봉투구분</label>
<select name="bag_kind_e" class="border border-gray-300 rounded px-2 py-1.5 text-sm min-w-[9rem]">
<option value="">전체</option>
<?php foreach ($bag_kind_options ?? [] as $cd): ?>
<option value="<?= esc($cd->cd_code) ?>" <?= (string) ($cd->cd_code ?? '') === (string) ($bag_kind_e ?? '') ? 'selected' : '' ?>>
<?= esc($cd->cd_name) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="flex flex-col gap-0.5">
<label class="text-xs text-gray-500">봉투코드</label>
<select name="bag_code" class="border border-gray-300 rounded px-2 py-1.5 text-sm min-w-[11rem]">
<option value="">전체</option>
<?php foreach ($bag_codes ?? [] as $cd): ?>
<option value="<?= esc($cd->cd_code) ?>" <?= (string) ($cd->cd_code ?? '') === (string) ($bag_code ?? '') ? 'selected' : '' ?>>
<?= esc($cd->cd_code) ?> — <?= esc($cd->cd_name) ?>
</option>
<?php endforeach; ?>
</select>
</div>
<div class="flex flex-col gap-0.5">
<label class="text-xs text-gray-500">조회 기간 (적용기간 겹침)</label>
<?php
$sp = $startParts ?? ['y' => '', 'm' => '', 'd' => ''];
$ep = $endParts ?? ['y' => '', 'm' => '', 'd' => ''];
$ymin = (int) ($dateYearMin ?? ((int) date('Y') - 12));
$ymax = (int) ($dateYearMax ?? ((int) date('Y') + 2));
?>
<div class="flex flex-wrap items-center gap-1">
<span class="text-xs text-gray-500 mr-0.5">시작</span>
<select name="start_y" class="border border-gray-300 rounded px-1.5 py-1.5 text-sm min-w-[4.5rem]" title="시작 연도">
<option value="">연도</option>
<?php for ($yy = $ymin; $yy <= $ymax; $yy++): ?>
<option value="<?= $yy ?>" <?= (string) ($sp['y'] ?? '') === (string) $yy ? 'selected' : '' ?>><?= $yy ?></option>
<?php endfor; ?>
</select>
<select name="start_m" class="border border-gray-300 rounded px-1.5 py-1.5 text-sm min-w-[3.75rem]" title="시작 월">
<option value="">월</option>
<?php for ($mi = 1; $mi <= 12; $mi++): ?>
<option value="<?= $mi ?>" <?= isset($sp['m']) && (int) $sp['m'] === $mi ? 'selected' : '' ?>><?= $mi ?>월</option>
<?php endfor; ?>
</select>
<select name="start_d" class="border border-gray-300 rounded px-1.5 py-1.5 text-sm min-w-[3.75rem]" title="시작 일">
<option value="">일</option>
<?php for ($di = 1; $di <= 31; $di++): ?>
<option value="<?= $di ?>" <?= isset($sp['d']) && (int) $sp['d'] === $di ? 'selected' : '' ?>><?= $di ?>일</option>
<?php endfor; ?>
</select>
<span class="text-sm text-gray-500 mx-0.5">~</span>
<span class="text-xs text-gray-500 mr-0.5">종료</span>
<select name="end_y" class="border border-gray-300 rounded px-1.5 py-1.5 text-sm min-w-[4.5rem]" title="종료 연도">
<option value="">연도</option>
<?php for ($yy = $ymin; $yy <= $ymax; $yy++): ?>
<option value="<?= $yy ?>" <?= (string) ($ep['y'] ?? '') === (string) $yy ? 'selected' : '' ?>><?= $yy ?></option>
<?php endfor; ?>
</select>
<select name="end_m" class="border border-gray-300 rounded px-1.5 py-1.5 text-sm min-w-[3.75rem]" title="종료 월">
<option value="">월</option>
<?php for ($mi = 1; $mi <= 12; $mi++): ?>
<option value="<?= $mi ?>" <?= isset($ep['m']) && (int) $ep['m'] === $mi ? 'selected' : '' ?>><?= $mi ?>월</option>
<?php endfor; ?>
</select>
<select name="end_d" class="border border-gray-300 rounded px-1.5 py-1.5 text-sm min-w-[3.75rem]" title="종료 일">
<option value="">일</option>
<?php for ($di = 1; $di <= 31; $di++): ?>
<option value="<?= $di ?>" <?= isset($ep['d']) && (int) $ep['d'] === $di ? 'selected' : '' ?>><?= $di ?>일</option>
<?php endfor; ?>
</select>
</div>
</div>
<div class="flex items-center gap-2 pb-0.5">
<button type="submit" class="bg-btn-search text-white px-4 py-1.5 rounded-sm text-sm">조회</button>
<a href="<?= base_url('bag/prices') ?>" class="text-sm text-gray-500 hover:underline">초기화</a>
<button type="button" onclick="window.print()" class="border border-gray-300 text-gray-700 px-3 py-1.5 rounded-sm text-sm hover:bg-gray-50">인쇄</button>
</div>
</form>
</section>
<section>
<div class="flex items-center justify-between mb-2 border-b pb-1">
<h3 class="text-base font-bold text-gray-700">봉투 단가</h3>
</div>
<div class="overflow-auto border border-gray-200">
<table class="data-table w-full">
<thead><tr>
<th class="w-16">번호</th><th>봉투코드</th><th>봉투명</th><th>발주단가</th><th>도매가</th><th>소비자가</th><th>적용시작</th><th>적용종료</th><th>상태</th>
</tr></thead>
<tbody>
<?php if (! empty($bagPrices)): ?>
<?php foreach ($bagPrices as $row): ?>
<tr>
<td class="text-center"><?= esc($row->bp_idx) ?></td>
<td class="text-center font-mono"><?= esc($row->bp_bag_code) ?></td>
<td class="text-left"><?= esc($row->bp_bag_name ?? '') ?></td>
<td class="text-right"><?= number_format((float) ($row->bp_order_price ?? 0)) ?></td>
<td class="text-right"><?= number_format((float) ($row->bp_wholesale ?? 0)) ?></td>
<td class="text-right"><?= number_format((float) ($row->bp_consumer ?? 0)) ?></td>
<td class="text-center"><?= esc($row->bp_start_date ?? '') ?></td>
<td class="text-center"><?= ($row->bp_end_date ?? '') !== '' && $row->bp_end_date !== null ? esc((string) $row->bp_end_date) : '현재' ?></td>
<td class="text-center"><?= (int) ($row->bp_state ?? 1) === 1 ? '사용' : '만료' ?></td>
</tr>
<?php endforeach; ?>
<?php else: ?>
<tr><td colspan="9" class="text-center text-gray-400 py-4">등록된 단가 정보가 없습니다.</td></tr>
<?php endif; ?>
</tbody>
</table>
</div>
<?php if (! empty($pager)): ?>
<div class="mt-3 no-print"><?= $pager->links() ?></div>
<?php endif; ?>
</section>
</div>