shopModel = model(DesignatedShopModel::class); $this->lgModel = model(LocalGovernmentModel::class); $this->roles = config('Roles'); } private function isSuperAdmin(): bool { return (int) session()->get('mb_level') === Roles::LEVEL_SUPER_ADMIN; } private function isLocalAdmin(): bool { return (int) session()->get('mb_level') === Roles::LEVEL_LOCAL_ADMIN; } /** * 지정판매소 목록 (효과 지자체 기준: super admin = 선택 지자체, 지자체관리자 = mb_lg_idx) */ public function index() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if ($lgIdx === null || $lgIdx <= 0) { return redirect()->to(site_url('admin')) ->with('error', '작업할 지자체가 선택되지 않았습니다. 지자체를 선택해 주세요.'); } $list = $this->shopModel ->where('ds_lg_idx', $lgIdx) ->orderBy('ds_idx', 'DESC') ->findAll(); // 지자체 이름 매핑용 $lgMap = []; foreach ($this->lgModel->findAll() as $lg) { $lgMap[$lg->lg_idx] = $lg->lg_name; } return view('admin/layout', [ 'title' => '지정판매소 관리', 'content' => view('admin/designated_shop/index', [ 'list' => $list, 'lgMap' => $lgMap, ]), ]); } /** * 지정판매소 등록 폼 (효과 지자체 기준) */ public function create() { helper('admin'); $lgIdx = admin_effective_lg_idx(); if ($lgIdx === null || $lgIdx <= 0) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '작업할 지자체가 선택되지 않았습니다. 지자체를 선택해 주세요.'); } $currentLg = $this->lgModel->find($lgIdx); if ($currentLg === null) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '선택한 지자체 정보를 찾을 수 없습니다.'); } return view('admin/layout', [ 'title' => '지정판매소 등록', 'content' => view('admin/designated_shop/create', [ 'localGovs' => [], 'currentLg' => $currentLg, ]), ]); } /** * 지정판매소 등록 처리 */ public function store() { if (! $this->isSuperAdmin() && ! $this->isLocalAdmin()) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '지정판매소 등록은 관리자만 가능합니다.'); } $rules = [ 'ds_name' => 'required|max_length[100]', 'ds_biz_no' => 'required|max_length[20]', 'ds_rep_name' => 'required|max_length[50]', 'ds_va_number' => 'permit_empty|max_length[50]', 'ds_email' => 'permit_empty|valid_email|max_length[100]', ]; if (! $this->validate($rules)) { return redirect()->back() ->withInput() ->with('errors', $this->validator->getErrors()); } helper('admin'); $lgIdx = admin_effective_lg_idx(); if ($lgIdx === null || $lgIdx <= 0) { return redirect()->back() ->withInput() ->with('error', '소속 지자체가 올바르지 않습니다.'); } $lg = $this->lgModel->find($lgIdx); if ($lg === null || (string) $lg->lg_code === '') { return redirect()->back() ->withInput() ->with('error', '지자체 코드 정보를 찾을 수 없습니다.'); } $dsShopNo = $this->generateNextShopNo($lgIdx, (string) $lg->lg_code); $data = [ 'ds_lg_idx' => $lgIdx, 'ds_mb_idx' => null, 'ds_shop_no' => $dsShopNo, 'ds_name' => (string) $this->request->getPost('ds_name'), 'ds_biz_no' => (string) $this->request->getPost('ds_biz_no'), 'ds_rep_name' => (string) $this->request->getPost('ds_rep_name'), 'ds_va_number' => (string) $this->request->getPost('ds_va_number'), 'ds_zip' => (string) $this->request->getPost('ds_zip'), 'ds_addr' => (string) $this->request->getPost('ds_addr'), 'ds_addr_jibun' => (string) $this->request->getPost('ds_addr_jibun'), 'ds_tel' => (string) $this->request->getPost('ds_tel'), 'ds_rep_phone' => (string) $this->request->getPost('ds_rep_phone'), 'ds_email' => (string) $this->request->getPost('ds_email'), 'ds_gugun_code' => (string) $lg->lg_code, 'ds_designated_at' => $this->request->getPost('ds_designated_at') ?: null, 'ds_state' => 1, 'ds_regdate' => date('Y-m-d H:i:s'), ]; $this->shopModel->insert($data); return redirect()->to(site_url('admin/designated-shops')) ->with('success', '지정판매소가 등록되었습니다.'); } /** * 지정판매소 수정 폼 (효과 지자체 소속만 허용) * 문서: docs/기본 개발계획/23-지정판매소_수정_삭제_기능.md */ public function edit(int $id) { if (! $this->isSuperAdmin() && ! $this->isLocalAdmin()) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '권한이 없습니다.'); } helper('admin'); $lgIdx = admin_effective_lg_idx(); if ($lgIdx === null || $lgIdx <= 0) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '작업할 지자체가 선택되지 않았습니다.'); } $shop = $this->shopModel->find($id); if ($shop === null || (int) $shop->ds_lg_idx !== $lgIdx) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '해당 지정판매소를 찾을 수 없거나 수정할 수 없습니다.'); } $currentLg = $this->lgModel->find($lgIdx); return view('admin/layout', [ 'title' => '지정판매소 수정', 'content' => view('admin/designated_shop/edit', [ 'shop' => $shop, 'currentLg' => $currentLg, ]), ]); } /** * 지정판매소 수정 처리 */ public function update(int $id) { if (! $this->isSuperAdmin() && ! $this->isLocalAdmin()) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '권한이 없습니다.'); } helper('admin'); $lgIdx = admin_effective_lg_idx(); if ($lgIdx === null || $lgIdx <= 0) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '작업할 지자체가 선택되지 않았습니다.'); } $shop = $this->shopModel->find($id); if ($shop === null || (int) $shop->ds_lg_idx !== $lgIdx) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '해당 지정판매소를 찾을 수 없거나 수정할 수 없습니다.'); } $rules = [ 'ds_name' => 'required|max_length[100]', 'ds_biz_no' => 'required|max_length[20]', 'ds_rep_name' => 'required|max_length[50]', 'ds_va_number' => 'permit_empty|max_length[50]', 'ds_email' => 'permit_empty|valid_email|max_length[100]', 'ds_state' => 'permit_empty|in_list[1,2,3]', ]; if (! $this->validate($rules)) { return redirect()->back() ->withInput() ->with('errors', $this->validator->getErrors()); } $data = [ 'ds_name' => (string) $this->request->getPost('ds_name'), 'ds_biz_no' => (string) $this->request->getPost('ds_biz_no'), 'ds_rep_name' => (string) $this->request->getPost('ds_rep_name'), 'ds_va_number' => (string) $this->request->getPost('ds_va_number'), 'ds_zip' => (string) $this->request->getPost('ds_zip'), 'ds_addr' => (string) $this->request->getPost('ds_addr'), 'ds_addr_jibun' => (string) $this->request->getPost('ds_addr_jibun'), 'ds_tel' => (string) $this->request->getPost('ds_tel'), 'ds_rep_phone' => (string) $this->request->getPost('ds_rep_phone'), 'ds_email' => (string) $this->request->getPost('ds_email'), 'ds_designated_at' => $this->request->getPost('ds_designated_at') ?: null, 'ds_state' => (int) ($this->request->getPost('ds_state') ?: 1), ]; $this->shopModel->update($id, $data); return redirect()->to(site_url('admin/designated-shops')) ->with('success', '지정판매소 정보가 수정되었습니다.'); } /** * 지정판매소 삭제 (물리 삭제, 효과 지자체 소속만 허용) * 문서: docs/기본 개발계획/23-지정판매소_수정_삭제_기능.md */ public function delete(int $id) { if (! $this->isSuperAdmin() && ! $this->isLocalAdmin()) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '권한이 없습니다.'); } helper('admin'); $lgIdx = admin_effective_lg_idx(); if ($lgIdx === null || $lgIdx <= 0) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '작업할 지자체가 선택되지 않았습니다.'); } $shop = $this->shopModel->find($id); if ($shop === null || (int) $shop->ds_lg_idx !== $lgIdx) { return redirect()->to(site_url('admin/designated-shops')) ->with('error', '해당 지정판매소를 찾을 수 없거나 삭제할 수 없습니다.'); } $this->shopModel->delete($id); return redirect()->to(site_url('admin/designated-shops')) ->with('success', '지정판매소가 삭제되었습니다.'); } /** * 지자체별 다음 판매소번호 생성 (lg_code + 3자리 일련번호) * 문서: docs/기본 개발계획/22-판매소번호_일련번호_결정.md §3 */ private function generateNextShopNo(int $lgIdx, string $lgCode): string { $prefixLen = strlen($lgCode); $existing = $this->shopModel->where('ds_lg_idx', $lgIdx)->findAll(); $maxSerial = 0; foreach ($existing as $row) { $no = $row->ds_shop_no; if (strlen($no) === $prefixLen + 3 && str_starts_with($no, $lgCode)) { $n = (int) substr($no, -3); if ($n > $maxSerial) { $maxSerial = $n; } } } return $lgCode . sprintf('%03d', $maxSerial + 1); } }