diff --git a/app/Commands/NaverWorker.php b/app/Commands/NaverWorker.php index 35c5bcf..757c5ea 100644 --- a/app/Commands/NaverWorker.php +++ b/app/Commands/NaverWorker.php @@ -15,6 +15,8 @@ class NaverWorker extends BaseCommand public function run(array $params) { + helper('log'); // 여기서 로드 완료! + $redis = new \Redis(); try { $redis->connect('redis', 6379); @@ -25,200 +27,32 @@ class NaverWorker extends BaseCommand return; } + $naverService = new \App\Services\NaverService(); // 서비스 생성 + while (true) { - try { - // 1. Redis에서 데이터를 꺼냄 - $result = $redis->brPop(['naver:raw_queue'], 30); - - if ($result) { - $rawData = $result[1]; - try { - $responseJson = json_decode($rawData, true); - $payload = $responseJson['request_data'] ?? []; - if ( empty($payload) ) { - throw new \Exception( date("Y-m-d H:i:s") . "::빈 페이로드 데이터: " . $rawData); - } - CLI::write("Processing: " . json_encode($payload, JSON_UNESCAPED_UNICODE)); - - $requestType = $payload['requestType'] ?? ''; - if (!in_array($requestType, ['REG', 'MOD', 'CNC', 'FIN'])) { - throw new \Exception( date("Y-m-d H:i:s") . "::잘못된 요청 유형: " . json_encode($payload, JSON_UNESCAPED_UNICODE)); - } - // 2. 실제 작업 수행 - /* - REG : 수동검증요청 , - MOD 매물정보수정 - 매물제공업체의 매물정보 수정으로 재검증요청 1차 실패 후 재검증 요청 , - CNC : 사용자취소 , - FIN : 서비스 노출/대기 검수완료 상태(필요한 상태인지 확인 필요) - */ - switch ($requestType) { - case 'REG': - $this->insertVrfc($payload); - break; - case 'MOD': - // 수동검증요청 및 매물정보수정 처리 - break; - case 'CNC': - // 사용자취소 처리 - break; - case 'FIN': - // 서비스 노출/대기 검수완료 상태 처리 - break; - } - - - CLI::write("✅ Success: " . ($payload['articleNumber'] ?? 'Unknown'), 'cyan'); + $result = $redis->brPop(['naver:raw_queue'], 30); + + if ($result) { + try { + $responseJson = json_decode($result[1], true); + $payload = $responseJson['request_data'] ?? []; - } catch (\Exception $e) { - // 3. 실패 시: Helper 함수 사용 - $errorMsg = $e->getMessage(); - - CLI::error("❌ Task Failed: $errorMsg"); - - // 공통 헬퍼 함수 호출 - write_custom_log("FAILED_DATA | Error: $errorMsg | Data: $rawData", 'ERROR', 'failed'); + if (empty($payload)) { + throw new \Exception("빈 페이로드 데이터"); } + + // 서비스의 함수 하나로 모든 처리 완료 + $insertId = $naverService->processArticle($payload); + + CLI::write("✅ Success! DB ID: $insertId", 'cyan'); + + } catch (\Exception $e) { + CLI::error("❌ Task Failed: " . $e->getMessage()); + // 실패 로그는 여기서 남김 + helper('log'); + write_custom_log("FAILED_DATA | Error: " . $e->getMessage(), 'ERROR', 'failed'); } - } catch (\Exception $e) { - CLI::error("Worker Loop Error: " . $e->getMessage()); - sleep(1); } } } - - private function insertVrfc($payload) - { - // 1. 필수 데이터 검증 - if (empty($payload['articleNumber']) || empty($payload['requestType'])) { - throw new \Exception("필수 파라미터 누락"); - } - - $articleNumber = $payload['articleNumber']; - $requestType = $payload['requestType']; - $requestDatetime = date('Y-m-d H:i:s', strtotime($payload['requestDatetime'])); - - // 2. 네이버 API 클라이언트 초기화 - $naverClient = new \App\Libraries\NaverApiClient(); - - // 매물 정보 조회 - $articleInfojson = $naverClient->getArticleInfo($articleNumber); - // if (!$articleInfojson || !isset($articleInfojson['data']) || empty($articleInfojson['code'] !== 'success')) { - // throw new \Exception("매물 정보 조회 실패: $articleNumber ::: message : " . ($articleInfojson['message'] ?? 'No response')); - // } - - if (!$articleInfojson || !isset($articleInfojson['data']) || $articleInfojson['code'] !== 'success') { - $msg = $articleInfojson['message'] ?? 'No message'; - throw new \Exception("네이버 API 응답 에러: $articleNumber | 메시지: $msg"); - } - - $articleInfo = $articleInfojson['data']; - - // 받아온 정보 로그 기록 - write_custom_log("ARTICLE_INFO | ArticleNumber: $articleNumber | Info: " . json_encode($articleInfo , JSON_UNESCAPED_UNICODE), 'INFO', 'service'); - CLI::write("Fetched Article Info: " . json_encode($articleInfo)); - - /** - * $articleInfo['verificationTypeCode'] - * S : 현장확인매물 - * D : 홍보확인서 - * N : 신홍보확인서 - * M : 모바일 - * T : 전화 - * O : 모바일확인V2 - * - * S - reciept , result 테이블 사용 - * D,N,M,T,O - v2_vrfc_req , v2_article_info , v2_article_info_etc , v2_article_fail 테이블 사용 - */ - - // {"code":"success","message":"","data":{"articleNumber":"2500000001","realEstateType":"빌라/연립","realEstateTypeCode":"C02","cpId":"toad","cpArticleNumber":"15882606","tradeType":"전세","tradeTypeCode":"B1","statusTypeCode":"E12","verificationTypeCode":"M","isUnregisteredVerificationRequested":false,"isBuildingRegisterAreaCheckRequested":false,"isAutoVerificationRequested":false,"exposureStartDateTime":"2025-01-02 09:12:02","facilities":{"roomCount":2,"bathroomCount":1},"address":{"legalDivision":{"cityNumber":"1100000000","divisionNumber":"1168000000","sectorNumber":"1168010700","legalDivisionAddress":"서울특별시 강남구 신사동"},"isVirtualAddress":false,"correspondenceFloorCount":2,"longitude":0.0,"latitude":0.0},"space":{"totalSpace":34.5,"groundSpace":34.5,"buildingSpace":34.5,"supplySpace":34.5,"exclusiveSpace":34.5},"price":{"dealAmount":777777777,"warrantyAmount":2999999999,"leaseAmount":7777777},"floor":{"correspondenceFloorCount":2,"totalFloorCount":3,"undergroundFloorCount":null}}} - $comp_sq = '2'; - $rcpt_rating = '3'; - - $files = $articleInfo['files'] ?? []; - $certRegister = []; - $confirm_doc_img_url = []; - $referenceFileUrl = []; - 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']; - } - } - - $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' => '10', - 'try_cnt' => '0', - 'insert_user' => 'admin', - 'insert_tm' => db_now(), - 'memo' => '', - 'contact_fail_cnt' => '0', - 'sync_yn' => 'N', - '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' => 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' => json_encode($certRegister, JSON_UNESCAPED_UNICODE), - 'referenceFileUrl' => json_encode($referenceFileUrl, JSON_UNESCAPED_UNICODE), - ]; - - write_custom_log("VRFC_PARAMS | " . json_encode($vrfc_params , JSON_UNESCAPED_UNICODE), 'INFO', 'service'); - - - // if ($articleInfo['verificationTypeCode'] == 'S') { // 현장확인매물 - // // 현장확인매물 처리 로직 - - // } else { // 그외 일반매물 - // // V2 매물 처리 로직 - // $v2ArticleModel = model(\App\Models\V2ArticleModel::class); - // // 매물 번호로 중복 체크 - // $existingV2 = $v2ArticleModel->where('atcl_no', $articleInfo['articleNumber'])->first(); - // if ($existingV2) { - // throw new \Exception("중복 매물 번호: " . $articleInfo['articleNumber']); - // } - - - // $v2ArticleModel->insert($vrfc_params); - // $vr_sq = $v2ArticleModel->getInsertID(); // 방금 삽입한 vr_sq 값 가져오기 - // CLI::write("Inserted V2 Article with vr_sq: " . $vr_sq); - // // 오류 처리 - // if ($v2ArticleModel->errors()) { - // $errorMessages = implode(', ', $v2ArticleModel->errors()); - // throw new \Exception("V2 매물 삽입 오류: " . $errorMessages); - // } - - // } - - - - - - - - - CLI::write("Processing: " . ($payload['articleNumber'] ?? 'Unknown')); - } } \ No newline at end of file diff --git a/app/Models/V2ArticleModel.php b/app/Models/VrfcReqModel.php similarity index 99% rename from app/Models/V2ArticleModel.php rename to app/Models/VrfcReqModel.php index 8eb030d..4871a66 100644 --- a/app/Models/V2ArticleModel.php +++ b/app/Models/VrfcReqModel.php @@ -2,7 +2,7 @@ namespace App\Models; use CodeIgniter\Model; -class V2ArticleModel extends Model { +class VrfcReqModel extends Model { // Model implementation here protected $table = 'v2_vrfc_req'; protected $primaryKey = 'vr_sq'; diff --git a/app/Services/NaverService.php b/app/Services/NaverService.php new file mode 100644 index 0000000..3141b4d --- /dev/null +++ b/app/Services/NaverService.php @@ -0,0 +1,96 @@ +naverClient = new NaverApiClient(); + $this->VrfcReqModel = model(VrfcReqModel::class); + helper('log'); // 헬퍼 로드 + } + + /** + * 매물 정보를 처리하고 DB에 저장하는 메인 함수 + */ + public function processArticle(array $payload) + { + $articleNumber = $payload['articleNumber']; + $requestDatetime = date('Y-m-d H:i:s', strtotime($payload['requestDatetime'] ?? 'now')); + + // 1. 네이버 API 호출 + $response = $this->naverClient->getArticleInfo($articleNumber); + + if (!$response || !isset($response['data']) || $response['code'] !== 'success') { + $msg = $response['message'] ?? 'No message'; + throw new \Exception("네이버 API 응답 에러: $articleNumber | 메시지: $msg"); + } + + $articleInfo = $response['data']; + + // 로그 기록 + write_custom_log("ARTICLE_INFO | ArticleNumber: $articleNumber", 'INFO', 'service'); + + // 2. 파라미터 매핑 (기존의 $vrfc_params 생성 로직) + $vrfcParams = $this->mapVrfcParams($articleInfo, $requestDatetime); + + // 3. DB 저장 + if (!$this->v2ArticleModel->insert($vrfcParams)) { + $errorMessages = implode(', ', $this->v2ArticleModel->errors()); + throw new \Exception("V2 매물 삽입 오류: " . $errorMessages); + } + + return $this->v2ArticleModel->getInsertID(); + } + + /** + * API 데이터를 DB 컬럼에 맞게 변환 + */ + private function mapVrfcParams(array $articleInfo, string $requestDatetime): array + { + $files = $articleInfo['files'] ?? []; + $certRegister = []; + $confirm_doc_img_url = []; + $referenceFileUrl = []; + + 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']; + } + } + + return [ + 'atcl_no' => $articleInfo['articleNumber'], + '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'] ?? false) ? 'Y' : 'N', + 'rdate' => $requestDatetime, + 'stat_cd' => '10', + 'insert_user' => 'admin', + 'insert_tm' => date('Y-m-d H:i:s'), + 'rgbk_confirm_owner_nm' => $articleInfo['seller']['ownerName'] ?? null, + 'confirm_doc_img_url' => json_encode($confirm_doc_img_url, JSON_UNESCAPED_UNICODE), + 'certRegister' => json_encode($certRegister, JSON_UNESCAPED_UNICODE), + 'referenceFileUrl' => json_encode($referenceFileUrl, JSON_UNESCAPED_UNICODE), + // 필요한 나머지 컬럼들 추가... + ]; + } +} \ No newline at end of file