validate([ 'start_date' => 'nullable|date_format:Ymd', 'end_date' => 'nullable|date_format:Ymd', ]); return ApiResponse::handle(function () use ($data) { $tenantId = app('tenant_id'); $startDate = $data['start_date'] ?? Carbon::now()->subMonth()->format('Ymd'); $endDate = $data['end_date'] ?? Carbon::now()->format('Ymd'); return $this->bankSyncService->syncIfNeeded($tenantId, $startDate, $endDate); }, __('message.fetched')); } /** * 수동 카드 동기화 */ public function syncCard(Request $request) { $data = $request->validate([ 'start_date' => 'nullable|date_format:Ymd', 'end_date' => 'nullable|date_format:Ymd', ]); return ApiResponse::handle(function () use ($data) { $tenantId = app('tenant_id'); $startDate = $data['start_date'] ?? Carbon::now()->subMonth()->format('Ymd'); $endDate = $data['end_date'] ?? Carbon::now()->format('Ymd'); return $this->cardSyncService->syncCardTransactions($tenantId, $startDate, $endDate); }, __('message.fetched')); } /** * 수동 홈택스 동기화 */ public function syncHometax(Request $request) { $data = $request->validate([ 'invoices' => 'required|array', 'invoices.*.ntsConfirmNum' => 'required|string', 'invoice_type' => 'required|in:sales,purchase', ]); return ApiResponse::handle(function () use ($data) { $tenantId = app('tenant_id'); return $this->hometaxSyncService->syncInvoices( $data['invoices'], $tenantId, $data['invoice_type'] ); }, __('message.fetched')); } /** * 바로빌 등록계좌 목록 (SOAP 실시간) */ public function accounts() { return ApiResponse::handle(function () { $member = $this->getMember(); if (! $member) { return ['accounts' => [], 'message' => '바로빌 회원 정보 없음']; } $this->soapService->initForMember($member); return [ 'accounts' => $this->bankSyncService->getRegisteredAccounts($member), ]; }, __('message.fetched')); } /** * 바로빌 등록카드 목록 (SOAP 실시간) */ public function cards() { return ApiResponse::handle(function () { $member = $this->getMember(); if (! $member) { return ['cards' => [], 'message' => '바로빌 회원 정보 없음']; } $this->soapService->initForMember($member); return [ 'cards' => $this->cardSyncService->getRegisteredCards($member), ]; }, __('message.fetched')); } /** * 인증서 상태 조회 (만료일, 유효성) */ public function certificate() { return ApiResponse::handle(function () { $member = $this->getMember(); if (! $member) { return ['certificate' => null, 'message' => '바로빌 회원 정보 없음']; } $this->soapService->initForMember($member); $corpNum = $member->biz_no; $valid = $this->soapService->checkCertificateValid($corpNum); $expireDate = $this->soapService->getCertificateExpireDate($corpNum); $registDate = $this->soapService->getCertificateRegistDate($corpNum); return [ 'certificate' => [ 'is_valid' => $valid['success'] && ($valid['data'] ?? 0) >= 0, 'expire_date' => $expireDate['success'] ? ($expireDate['data'] ?? null) : null, 'regist_date' => $registDate['success'] ? ($registDate['data'] ?? null) : null, ], ]; }, __('message.fetched')); } /** * 충전잔액 조회 */ public function balance() { return ApiResponse::handle(function () { $member = $this->getMember(); if (! $member) { return ['balance' => null, 'message' => '바로빌 회원 정보 없음']; } $this->soapService->initForMember($member); $result = $this->soapService->getBalanceCostAmount($member->biz_no); return [ 'balance' => $result['success'] ? ($result['data'] ?? 0) : null, 'success' => $result['success'], 'error' => $result['error'] ?? null, ]; }, __('message.fetched')); } /** * 바로빌 회원 등록 (SOAP RegistCorp) */ public function registerMember(Request $request) { $data = $request->validate([ 'biz_no' => 'required|string|size:10', 'corp_name' => 'required|string', 'ceo_name' => 'required|string', 'biz_type' => 'nullable|string', 'biz_class' => 'nullable|string', 'addr' => 'nullable|string', 'barobill_id' => 'required|string', 'barobill_pwd' => 'required|string', 'manager_name' => 'nullable|string', 'manager_hp' => 'nullable|string', 'manager_email' => 'nullable|email', ]); return ApiResponse::handle(function () use ($data) { $tenantId = app('tenant_id'); $this->soapService->initForMember( BarobillMember::withoutGlobalScopes()->where('tenant_id', $tenantId)->first() ?? new BarobillMember(['server_mode' => 'test']) ); $result = $this->soapService->registCorp($data); if ($result['success']) { BarobillMember::withoutGlobalScopes()->updateOrCreate( ['tenant_id' => $tenantId], [ 'biz_no' => $data['biz_no'], 'corp_name' => $data['corp_name'], 'ceo_name' => $data['ceo_name'], 'biz_type' => $data['biz_type'] ?? null, 'biz_class' => $data['biz_class'] ?? null, 'addr' => $data['addr'] ?? null, 'barobill_id' => $data['barobill_id'], 'barobill_pwd' => $data['barobill_pwd'], 'manager_name' => $data['manager_name'] ?? null, 'manager_hp' => $data['manager_hp'] ?? null, 'manager_email' => $data['manager_email'] ?? null, 'status' => 'active', ] ); } return $result; }, __('message.created')); } /** * 바로빌 회원 수정 (SOAP UpdateCorpInfo) */ public function updateMember(Request $request) { $data = $request->validate([ 'corp_name' => 'required|string', 'ceo_name' => 'required|string', 'biz_type' => 'nullable|string', 'biz_class' => 'nullable|string', 'addr' => 'nullable|string', 'manager_name' => 'nullable|string', 'manager_hp' => 'nullable|string', 'manager_email' => 'nullable|email', ]); return ApiResponse::handle(function () use ($data) { $member = $this->getMember(); if (! $member) { return ['error' => 'NO_MEMBER', 'code' => 404, 'message' => '바로빌 회원 정보 없음']; } $this->soapService->initForMember($member); $data['biz_no'] = $member->biz_no; $result = $this->soapService->updateCorpInfo($data); if ($result['success']) { $member->update([ 'corp_name' => $data['corp_name'], 'ceo_name' => $data['ceo_name'], 'biz_type' => $data['biz_type'] ?? $member->biz_type, 'biz_class' => $data['biz_class'] ?? $member->biz_class, 'addr' => $data['addr'] ?? $member->addr, 'manager_name' => $data['manager_name'] ?? $member->manager_name, 'manager_hp' => $data['manager_hp'] ?? $member->manager_hp, 'manager_email' => $data['manager_email'] ?? $member->manager_email, ]); } return $result; }, __('message.updated')); } /** * 바로빌 회원 상태 (SOAP GetCorpState) */ public function memberStatus() { return ApiResponse::handle(function () { $member = $this->getMember(); if (! $member) { return ['status' => null, 'message' => '바로빌 회원 정보 없음']; } $this->soapService->initForMember($member); $result = $this->soapService->getCorpState($member->biz_no); return [ 'member' => [ 'biz_no' => $member->formatted_biz_no, 'corp_name' => $member->corp_name, 'status' => $member->status, 'server_mode' => $member->server_mode, ], 'barobill_state' => $result['success'] ? $result['data'] : null, 'error' => $result['error'] ?? null, ]; }, __('message.fetched')); } /** * 현재 테넌트의 바로빌 회원 조회 */ private function getMember(): ?BarobillMember { $tenantId = app('tenant_id'); return BarobillMember::withoutGlobalScopes() ->where('tenant_id', $tenantId) ->first(); } }