From 1d6dc49971b2152147a451bc39cd3135f3d10e6a Mon Sep 17 00:00:00 2001 From: jjstyle Date: Fri, 23 Jan 2026 20:49:21 +0900 Subject: [PATCH] =?UTF-8?q?vrfcReqModel=20=EC=88=98=EC=A0=95?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- app/Services/NaverService.php | 423 +++++---------------------------- app/Services/StatusService.php | 14 +- 2 files changed, 62 insertions(+), 375 deletions(-) diff --git a/app/Services/NaverService.php b/app/Services/NaverService.php index 92041c7..b9cf87a 100644 --- a/app/Services/NaverService.php +++ b/app/Services/NaverService.php @@ -30,22 +30,18 @@ class NaverService public function __construct() { $this->db = \Config\Database::connect(); - try { - $this->naverClient = new NaverApiClient(); - $this->VrfcReqModel = new VrfcReqModel(); - $this->articleModel = new V2ArticleInfoModel(); - $this->articleEtcModel = new V2articleInfoetcModel(); - $this->V2stdailyModel = new V2stdailyModel(); - $this->rawStagingModel = new NaverRawStagingModel(); - $this->receiptModel = new ReceiptModel(); - $this->resultModel = new ResultModel(); - - $this->statusService = new StatusService(); - helper('log'); - } catch (\Throwable $e) { - CLI::error("Service Init Error: " . $e->getMessage()); - } + } + + /** + * 모델/서비스 지연 로딩 (Null 에러 방지 핵심) + */ + private function getStatusService() { + return $this->statusService ??= new StatusService(); + } + + private function getModel($property, $class) { + return $this->$property ??= new $class(); } /** @@ -53,14 +49,6 @@ class NaverService */ public function processArticle(array $payload) { - // 🟢 방어 코드: null이면 여기서라도 할당 - if ($this->rawStagingModel === null) { - $this->rawStagingModel = new \App\Models\Entities\NaverRawStagingModel(); - } - if ($this->naverClient === null) { - $this->naverClient = new \App\Libraries\NaverApiClient(); - } - $articleNumber = $payload['articleNumber']; $requestType = $payload['requestType'] ?? ''; @@ -74,14 +62,12 @@ class NaverService $rawData = $response['data']; $vType = $rawData['verificationTypeCode'] ?? ''; - - - // 2. [Staging] 원본 DB 저장 (JSON 타입 컬럼 활용) - $this->rawStagingModel->insert([ + // [Staging] 원본 저장 + $this->getModel('rawStagingModel', NaverRawStagingModel::class)->insert([ 'atcl_no' => $articleNumber, 'verification_type' => $vType, 'request_type' => $requestType, - 'raw_json' => $rawData // 모델에서 json_encode 처리됨 + 'raw_json' => $rawData ]); CLI::write(CLI::color('🟢 임시테이블 :: ' . $this->rawStagingModel->getLastQuery() , 'green')); @@ -294,45 +280,13 @@ class NaverService $vr_sq = $this->insertVrfcReq($vrfcParam); $articleInfoParam['vr_sq'] = $vr_sq; write_custom_log("articleInfoParam :: " . json_encode($articleInfoParam, JSON_UNESCAPED_UNICODE) , "INFO", "SERVICE"); + if (!$this->getModel('articleModel', V2articleInfoModel::class)->insert($articleInfoParam)) { + throw new \Exception("ArticleInfo Insert 실패: " . json_encode($this->db->error())); + } - // 인서트 실행 - if ($this->articleModel->insert($articleInfoParam)) { - // 성공 로그 - write_custom_log("articleInfo Insert Success :: vr_sq: $vr_sq", "INFO", "SERVICE"); - // article_info_etc 저장 - $articleInfoEtcParam['vr_sq'] = $vr_sq; - if ( $this->articleEtcModel->insert($articleInfoEtcParam)) { - write_custom_log("articleInfoEtc Insert Success :: vr_sq: $vr_sq", "INFO", "SERVICE"); - } else { - // 1. 모델에서 발생한 에러 정보 가져오기 - $dbError = $this->db->error(); - $lastQuery = (string)$this->articleEtcModel->getLastQuery(); - - // 2. 로그 기록 (에러 메시지 + 실패한 쿼리) - write_custom_log( - "DB_ERROR | Code: {$dbError['code']} | Message: {$dbError['message']} | Query: {$lastQuery}", - "ERROR", - "SERVICE" - ); - - // 필요하다면 예외를 던져서 상위(Worker)의 try-catch에서 처리하게 함 - throw new \Exception("ArticleInfoEtc Insert Failed: " . $dbError['message']); - } - - } else { - // 1. 모델에서 발생한 에러 정보 가져오기 - $dbError = $this->db->error(); - $lastQuery = (string)$this->articleModel->getLastQuery(); - - // 2. 로그 기록 (에러 메시지 + 실패한 쿼리) - write_custom_log( - "DB_ERROR | Code: {$dbError['code']} | Message: {$dbError['message']} | Query: {$lastQuery}", - "ERROR", - "SERVICE" - ); - - // 필요하다면 예외를 던져서 상위(Worker)의 try-catch에서 처리하게 함 - throw new \Exception("ArticleInfo Insert Failed: " . $dbError['message']); + $articleInfoEtcParam['vr_sq'] = $vr_sq; + if (!$this->getModel('articleEtcModel', V2articleInfoetcModel::class)->insert($articleInfoEtcParam)) { + throw new \Exception("ArticleInfoEtc Insert 실패"); } break; @@ -349,6 +303,28 @@ class NaverService } } + /** + * [REG] 신규 등록 + */ + private function insertVrfcReq($vrfcParam) + { + CLI::write(CLI::color('🟢 매물 정보 시작', 'green')); + $model = $this->getModel('VrfcReqModel', VrfcReqModel::class); + $existing = $model->where('atcl_no', $vrfcParam['atcl_no'])->first(); + if ($existing) throw new \Exception("중복 등록 시도: " . $vrfcParam['atcl_no']); + + if (!$model->insert($vrfcParam)) { + $dbError = $this->db->error(); + throw new \Exception("신규 등록 실패: " . $dbError['message']); + } + + $vr_sq = $model->getInsertID(); + // 🟢 여기서 Null 에러 방지 (getStatusService 사용) + $this->getStatusService()->recordStatusAndHistory($vr_sq, '10', 'C9', "신규접수 : 10"); + + return $vr_sq; + } + private function v2Parameter($articleNumber, $rawData , $payload){ $now = db_now(); @@ -439,28 +415,15 @@ class NaverService } } - $ownerTypeCode = null; - $ownerTypeCodeResponse = isset($rawData['ownerTypeCode']) ?? null; + $ownerTypeCodeRaw = $rawData['ownerTypeCode'] ?? null; + $ownerTypeCode = match($ownerTypeCodeRaw) { + "INDIV" => 0, + "CORP" => 1, + "FRGNR" => 2, + "DELEG" => 3, + default => null, + }; - if ($ownerTypeCodeResponse !== null ){ - switch ($ownerTypeCodeResponse) { - case "INDIV": - $ownerTypeCode = 0; - break; - case "CORP": - $ownerTypeCode = 1; - break; - case "FRGNR": - $ownerTypeCode = 2; - break; - case "DELEG": - $ownerTypeCode = 3; - break; - } - } - - - $ownerCheckYn = ($seller['isOwnerCertificationAgree'] ?? false) ? 'Y' : 'N'; return [ @@ -535,7 +498,7 @@ class NaverService 'cupnNo' => null, 'roomSiteAtclRgstCnt' => null, 'rootSiteAtclExpsCnt' => null, - 'redvlp_area_nm' => $adress['redevelopAreaName'] ?? null, + 'redvlp_area_nm' => $address['redevelopAreaName'] ?? null, 'biz_stp_desc' => $address['bizStepDescription'] ?? null, // file @@ -596,7 +559,7 @@ class NaverService return [ 'atcl_no' => $articleNumber, - 'vir_addr_yn' => ($address['isVirtualAddress'] === true) ? 'Y' : (($address['isVirtualAddress'] === false) ? 'N' : null), + 'vir_addr_yn' => ($address['isVirtualAddress'] ?? null) === true ? 'Y' : (($address['isVirtualAddress'] ?? null) === false ? 'N' : null), 'bild_no' => null, 'vrfcMthdTpcd' => null, 'cert_uncnfrm_status' => null, @@ -623,287 +586,9 @@ class NaverService ]; } - /** - * [REG] 신규 등록 - */ - private function insertVrfcReq($vrfcParam) - { - CLI::write(CLI::color('🟢 매물 정보 시작', 'green')); - $existing = $this->VrfcReqModel->where('atcl_no', $vrfcParam['atcl_no'])->first(); - if ($existing) throw new \Exception("중복 등록 시도: " . $vrfcParam['atcl_no']); + - if (!$this->VrfcReqModel->insert($vrfcParam)) { - $dbError = $this->VrfcReqModel->db()->error(); // DB 에러 코드와 메시지 가져오기 - $sql = (string)$this->VrfcReqModel->getLastQuery(); - write_custom_log("INSERT_FAILED | Atcl: " . $vrfcParam['atcl_no'] . " | Error: {$dbError['message']} | SQL: ".$sql, 'ERROR', 'failed'); - throw new \Exception("신규 등록 실패: " . $dbError['message']); - } - - $vr_sq = $this->VrfcReqModel->getInsertID(); - $this->statusService->recordStatusAndHistory($vr_sq, '10', 'C9', "신규접수 : 10"); - - return $vr_sq; - } - - private function insertArticleInfo($article){ - - } - - /** - * [MOD] 수정 처리 - */ - private function updateVrfcReq($articleNumber, $params) - { - - // 1. 데이터 존재 여부 확인 - $existing = $this->VrfcReqModel->where('atcl_no', $articleNumber)->first(); - - if (!$existing) { - // [A] 데이터가 없으면 먼저 신규 등록(10) 실행 - write_custom_log("MOD_NOT_FOUND | Atcl: $articleNumber | First, Insert new data.", 'INFO', 'service'); - - $vr_sq = $this->insertVrfcReq($articleNumber, $params); - - // 새로 등록된 정보를 다시 가져옴 (updateProcess를 태우기 위해) - $existing = $this->VrfcReqModel->find($vr_sq); - - // 통계 기록 (신규 등록 건으로 카운트) - $this->V2stdailyModel->set_v2_st_daily(null, $params['cpid'], $params['vrfc_type'] . '0103', '1', 'add'); - } - - $params['stat_cd'] = '30'; - $params['req_type'] = 'U'; - $params['insert_tm'] = db_now(); - - return $this->updateProcess($existing, $params, 'MOD', "재접수 상태변경: {$existing['stat_cd']} => 30"); - } - - /** - * [CNC] 취소 처리 - */ - private function deleteVrfcReq($articleNumber, $params) - { - try { - $existing = $this->findExisting($articleNumber); - } catch (\Exception $e) { - // 취소(CNC)하려는데 데이터가 없으면 이미 지워졌거나 오류일 수 있습니다. - // 여기서는 로그만 남기고 종료하거나, 필요 시 Exception을 던집니다. - throw new \Exception("CNC_NOT_FOUND | Atcl: $articleNumber WARNING service"); - } - $params['stat_cd'] = '19'; - $params['req_type'] = 'D'; - - return $this->updateProcess($existing, $params, 'CNC', "취소 처리: {$existing['stat_cd']} => 19"); - } - - /** - * [FIN] 완료 처리 - */ - private function finVrfcReq($articleNumber, $params) - { - try { - $existing = $this->findExisting($articleNumber); - } catch (\Exception $e) { - // 완료(FIN)하려는데 데이터가 없으면 이미 지워졌거나 오류일 수 있습니다. - // 여기서는 로그만 남기고 종료하거나, 필요 시 Exception을 던집니다. - throw new \Exception("FIN_NOT_FOUND | Atcl: $articleNumber WARNING service"); - } - $params['stat_cd'] = '60'; - $params['req_type'] = 'F'; - - return $this->updateProcess($existing, $params, 'FIN', "완료 처리: {$existing['stat_cd']} => 60"); - } - - // --- 내부 공통 유틸리티 함수 --- - - private function findExisting($articleNumber) { - $existing = $this->VrfcReqModel->where('atcl_no', $articleNumber)->first(); - if (!$existing) throw new \Exception("해당 매물 없음: $articleNumber 재등록 필요"); - return $existing; - } - - /** - * 공통 업데이트 및 이력 기록 로직 (Lock 최소화) - */ - private function updateProcess($existing, $params, $type, $memo) - { - $vr_sq = $existing['vr_sq']; - - if (!$this->VrfcReqModel->update($vr_sq, $params)) { - $sql = (string)$this->VrfcReqModel->getLastQuery(); - write_custom_log("UPDATE_FAILED | Type: $type | vr_sq: $vr_sq | SQL: $sql", 'ERROR', 'failed'); - throw new \Exception("[$type] 업데이트 실패"); - } - - $this->statusService->recordStatusAndHistory($vr_sq, $params['stat_cd'], 'C9', $memo); - return $vr_sq; - } - - - /** - * API 데이터를 DB 컬럼에 맞게 변환 - */ - private function mapToDatabaseParams(array $articleInfo, array $payload): array - { - $files = $articleInfo['files'] ?? []; - $certRegister = []; - $confirm_doc_img_url = []; - $referenceFileUrl = []; - $requestDatetime = date('YmdHis', strtotime($payload['requestDatetime'] ?? 'now')); - - foreach ($files as $file) { - $fileTypeCode = $file['fileTypeCode']; - if ($fileTypeCode == 'RCDOC') { - $certRegister[] = $file['fileUrl']; - } elseif ($fileTypeCode == 'ADDOC') { - $confirm_doc_img_url[] = $file['fileUrl']; - } elseif ($fileTypeCode == 'REFER') { - $referenceFileUrl[] = $file['fileUrl']; - } - } - - $ownerTypeRaw = $articleInfo['seller']['ownerTypeCode'] ?? null; - - $vrfc_params = [ - 'reqSeq' => '', - 'atcl_no' => $articleInfo['articleNumber'], - 'step' => '', - 'cpid' => $articleInfo['cpId'], - 'cp_atcl_id' => $articleInfo['cpArticleNumber'], - 'trade_type' => $articleInfo['tradeTypeCode'], - 'realtor_nm' => $articleInfo['realtor']['realtorName'], - 'realtor_tel_no' => $articleInfo['realtor']['representativeCellphoneNumber'], - 'seller_tel_no' => $articleInfo['seller']['sellerTelephoneNumber'], - 'vrfc_type' => $articleInfo['verificationTypeCode'], - 'rgbk_confirm' => $articleInfo['isUnregisteredVerificationRequested'] ? 'Y' : 'N', - 'req_type' => '', - 'rdate' => $requestDatetime ?? db_now('Y-m-d H:i:s'), - 'cpTelNo' => $articleInfo['seller']['sellerTelephoneNumber'], - 'stat_cd' => '', - 'try_cnt' => '0', - 'insert_user' => '', - 'insert_tm' => db_now(), - 'memo' => '', - 'contact_fail_cnt' => '0', - 'sync_yn' => 'Y', - 'reg_try_cnt' => '0', - 'tel_fail_cause' => null, - 'rgbk_confirm_owner_nm' => $articleInfo['seller']['ownerName'] ?? null, - 'direct_trad_yn' => $articleInfo['seller']['isDirectTrade'] === true ? 'Y' : 'N', - 'confirm_doc_img_url' => empty($confirm_doc_img_url) ? null : json_encode($confirm_doc_img_url, JSON_UNESCAPED_UNICODE), - 'confirm_doc_owner_check_yn' => '', - 'owner_verifiable' => null, - 'vrfc_cmpl_type' => null, - 'rgbk_doc_img_url' => null, - 'certRegister' => empty($certRegister) ? null : json_encode($certRegister, JSON_UNESCAPED_UNICODE), - 'referenceFileUrl' => empty($referenceFileUrl) ? null : json_encode($referenceFileUrl, JSON_UNESCAPED_UNICODE), - ]; - - $articl_info_param = [ - 'address_code' => $articleInfo['address']['legalDivision']['sectorNumber'] ?? '', //읍면동코드 - 'address1' => $articleInfo['address']['legalDivision']['legalDivisionAddress'] ?? '', //법정도 주소 - 'address2' => $articleInfo['address']['jibunAddress'] ?? '', - 'address3' => $articleInfo['address']['referenceAddress'] ?? '', - 'address4' => $articleInfo['address']['etcAddress'] ?? '', - 'sply_spc' => $articleInfo['space']['supplySpace'] ?? 0, - 'excls_spc' => $articleInfo['space']['exclusiveSpace'] ?? 0, - 'tot_spc' => $articleInfo['space']['totalSpace'] ?? 0, - 'grnd_spc' => $articleInfo['space']['groundSpace'] ?? 0, - 'bldg_spc' => $articleInfo['space']['buildingSpace'] ?? 0, - 'deal_amt' => $articleInfo['price']['dealAmount'] ?? 0, // 매매금액 - 'wrrnt_amt' => $articleInfo['price']['warrantyAmount'] ?? 0, // 보증금 - 'lease_amt' => $articleInfo['price']['leaseAmount'] ?? 0, // 월세가 -> 임대가 - 'isale_amt' => $articleInfo['price']['preSaleAmount'] ?? 0, // 분양가 - 'prem_amt' => $articleInfo['price']['premiumAmount'] ?? 0, // 프리미엄 - 'sise' => null, // 매매, 전세 시세 - 'floor' => $articleInfo['floor']['correspondenceFloorCount'] ?? 0, // 층 / 해당 층 - '_correspondenceFloorType' => $articleInfo['floor']['correspondenceFloorType'] ?? null, // 층 / 해당 층 타입 // 기존 없음 - 'floor2' => $articleInfo['floor']['totalFloorCount'] ?? 0, // 층 / 총 층수 // 기존 없음 - '_undergroundFloorCount' => $articleInfo['floor']['undergroundFloorCount'] ?? 0, // 층 / 지하 층수 // 기존 없음 - 'rdate' => $requestDatetime ?? db_now('Y-m-d H:i:s'), - 'seller_tel_no' => $articleInfo['seller']['sellerTelephoneNumber'] ?? null, - 'seller_nm' => $articleInfo['seller']['sellerName'] ?? null, - 'ownerTelNo' => $articleInfo['seller']['ownerTelephoneNumber'] ?? null, // 소유자전화번호 기존 없음 - 'ownerNm' => $articleInfo['seller']['ownerName'] ?? null, // 소유자명 기존 없음 - '_isOwnerCertificationAgree' => $articleInfo['seller']['isOwnerCertificationAgree'] ?? null, // 소유자확인동의여부 기존 없음 - 'direct_trad_yn' => $articleInfo['seller']['isDirectTrade'] ?? null, // 직거래여부 기존 없음 - 'realtor_nm' => $articleInfo['realtor']['realtorName'] ?? null, - 'realtor_tel_no' => $articleInfo['realtor']['representativeCellphoneNumber'] ?? null, - '_representativeTelephoneNumber' => $articleInfo['realtor']['representativeTelephoneNumber'] ?? null, // 중개사대표전화번호 기존 없음 - 'hscp_no' => $articleInfo['address']['complexNumber'] ?? null, - 'hscp_nm' => $articleInfo['address']['complexName'] ?? null, - 'ptp_no' => $articleInfo['address']['pyeongTypeNumber'] ?? null, - 'ptp_nm' => null, - 'charger' => null, - 'req_price_yn' => 'N', - 'reg_charger' => null, - 'dept1_sq' => null, - 'dept2_sq' => null, - 'reg_dept2_sq' => null, - 'reg_dept1_sq' => null, - 'dong_ho_chk' => $articleInfo['address']['isDongHoChecked'] ?? null, - 'hscplqry_lv' => $articleInfo['address']['inquiryLevel'] ?? null, - 'chg_trade_type' => null, - 'chg_address2' => null, - 'chg_address3' => null, - 'chg_seller_tel' => null, - 'chg_amt' => null, - 'reg_status' => null, - 'cupnNo' => null, - 'roomSiteAtclRgstCnt' => null, - 'roomSiteAtclExpsCnt' => null, - 'redvlp_area_nm' => $articleInfo['address']['redevelopmentArea']['redevelopmentAreaName'] ?? null, - 'biz_stp_desc' => $articleInfo['address']['redevelopmentArea']['businessStep'] ?? null, - 'cert_register' => empty($certRegister) ? null : json_encode($certRegister, JSON_UNESCAPED_UNICODE), - 'confirm_doc_img_url' => empty($confirm_doc_img_url) ? null : json_encode($confirm_doc_img_url, JSON_UNESCAPED_UNICODE), - 'confirm_doc_owner_check_yn' => $articleInfo['seller']['isOwnerCertificationAgree'] === true ? 'Y' : 'N', - 'owner_birth' => $articleInfo['seller']['ownerBirthDate'] ?? null, - 'vrfc_type_sub' => null, - 'cert_register_save_yn' => '', - 'confirm_doc_img_url_save_yn' => '', - 'reference_file_url' => empty($referenceFileUrl) ? null : json_encode($referenceFileUrl, JSON_UNESCAPED_UNICODE), - 'reference_file_url_save_yn' => '', - 'reference_file_url_yn' => empty($referenceFileUrl) ? 'N' : 'Y', - 'registerBookUniqueNo' => null, // 검증 참고란 - 'relationSellerAndOwner' => null, // 의뢰인과 소유주 관계 - 'ownerTypeCode' => getOwnerTypeCodeNo($ownerTypeRaw) ?? null, // 소유자구분코드 - 'registerBookUniqueNumber' => null, // 등기부 고유번호 - ]; - - - $article_info_etc_param = [ - 'corp_own' => $ownerTypeRaw == 'CORP' ? 'Y' : 'N', - 'bild_no' => null, // 건물번호 - 'address2a' => $articleInfo['address']['liAddress'] ?? null, // 지번주소 - 'address2b' => $articleInfo['address']['jibunAddress'] ?? null, // 도로명주소 - 'expsStartYmdt' => $articleInfo['exposureStartDateTime'] ?? null, - 'vrfcAutoPassYn' => $articleInfo['isAutoVerificationRequested'] === true ? 'Y' : 'N', - 'registerBookUniqueNo' => null, - 'ownerTypeCode' => getOwnerTypeCodeNo($ownerTypeRaw) ?? null, - 'orgRepCphNo' => null, - 'orgRepTelNo' => null,// 원중개사 대표자명 - 'orgRltrNm' => null, // 원중개사 대표자명 - 'smsSendTime' => null, // 서류확인 내용 - 'document_cert_method' => null, - 'noRgbkVrfcReqYn' => $articleInfo['isUnregisteredVerificationRequested'] === true ? 'Y' : 'N', - 'areaByBdbkVrfcReqYn' => $articleInfo['isBuildingRegisterAreaCheckRequested'] === true ? 'Y' : 'N', //건축물대장기준 면적검증요청 여부 Y / N 또는 항목미전송 - 'orgAtclNo' => null, // 원매물 번호 - 'atclStatCd' => null, // 매물상태코드 J1W : 공동중개 검증 원)중개사 확인 요청 - 'repNm' => $articleInfo['realtor']['representativeName'] ?? null, // 원중개사 대표자명 - 'cpName' => $articleInfo['realtor']['realtorName'], // 중개업소 대표자명 ? - 'document_not_received' => null, - 'final_failure' => null - ]; - - // $vrfc_params = array_merge($vrfc_params, $articl_info_param, $article_info_etc_param); - - // 개인: INDIV => 0 - // 법인: CORP => 1 - // 외국인: FRGNR => 2 - // 위임장: DELEG => 3 - - return $vrfc_params; - } + diff --git a/app/Services/StatusService.php b/app/Services/StatusService.php index 5ddd996..36cb14b 100644 --- a/app/Services/StatusService.php +++ b/app/Services/StatusService.php @@ -11,8 +11,8 @@ class StatusService public function __construct() { - $this->V2chgstatModel = model(V2chgstatModel::class); - $this->V2chghistoryModel = model(V2chghistoryModel::class); + // $this->V2chgstatModel = model(V2chgstatModel::class); + // $this->V2chghistoryModel = model(V2chghistoryModel::class); } /** @@ -20,22 +20,24 @@ class StatusService */ public function recordStatusAndHistory($vr_sq, $stat_cd, $chg_type, $memo) { + $statModel = model(V2chgstatModel::class); + $histModel = model(V2chghistoryModel::class); // 1. 상태(stat) 저장 (Insert or Update) try { - $this->V2chgstatModel->saveChgstat([ + $statModel->saveChgstat([ 'vr_sq' => $vr_sq, 'stat_cd' => $stat_cd, 'insert_user' => '0', 'insert_tm' => db_now() ], 'I'); } catch (\Exception $e) { - $lastSql = (string)$this->V2chgstatModel->getLastQuery(); + $lastSql = (string)$statModel->getLastQuery(); write_custom_log("STAT_SAVE_ERR | vr_sq: $vr_sq | SQL: $lastSql | Msg: " . $e->getMessage(), 'ERROR', 'failed'); } // 2. 이력(history) 저장 try { - $this->V2chghistoryModel->v2_savehistory([ + $histModel->v2_savehistory([ 'vr_sq' => $vr_sq, 'stat_cd' => $stat_cd, 'chg_type' => $chg_type, @@ -44,7 +46,7 @@ class StatusService 'insert_tm' => db_now() ]); } catch (\Exception $e) { - $lastSql = (string)$this->V2chghistoryModel->getLastQuery(); + $lastSql = (string)$histModel->getLastQuery(); write_custom_log("HIST_SAVE_ERR | vr_sq: $vr_sq | SQL: $lastSql | Msg: " . $e->getMessage(), 'ERROR', 'failed'); } }