diff --git a/app/Commands/NaverWorker.php b/app/Commands/NaverWorker.php index b57b206..6ece227 100644 --- a/app/Commands/NaverWorker.php +++ b/app/Commands/NaverWorker.php @@ -35,8 +35,31 @@ class NaverWorker extends BaseCommand try { $payload = json_decode($rawData, true); + $requestType = $payload['reqeustType'] ?? ''; + if (!in_array($requestType, ['REG', 'MOD', 'CNC', 'FIN'])) { + throw new \Exception("잘못된 요청 유형: $requestType"); + } // 2. 실제 작업 수행 - $this->processTask($payload); + /* + REG : 수동검증요청 , + MOD 매물정보수정 - 매물제공업체의 매물정보 수정으로 재검증요청 1차 실패 후 재검증 요청 , + CNC : 사용자취소 , + FIN : 서비스 노출/대기 검수완료 상태(필요한 상태인지 확인 필요) + */ + switch ($requestType) { + case 'REG': + $this->insertVrfc($payload); + case 'MOD': + // 수동검증요청 및 매물정보수정 처리 + break; + case 'CNC': + // 사용자취소 처리 + break; + case 'FIN': + // 서비스 노출/대기 검수완료 상태 처리 + break; + } + CLI::write("✅ Success: " . ($payload['articleNumber'] ?? 'Unknown'), 'cyan'); @@ -57,125 +80,126 @@ class NaverWorker extends BaseCommand } } - private function processTask($payload) + private function insertVrfc($payload) { - // 실제 비즈니스 로직 - // { - // "articleNumber": "2500000001", - // "reqeustType": "REG", - // "requestDatetime": "2025-12-22 19:20:12" - // } - // 1. 필수 데이터 검증 if (empty($payload['articleNumber']) || empty($payload['reqeustType'])) { throw new \Exception("필수 파라미터 누락"); } $articleNumber = $payload['articleNumber']; - /* - REG : 수동검증요청 , - MOD 매물정보수정 - 매물제공업체의 매물정보 수정으로 재검증요청 1차 실패 후 재검증 요청 , - CNC : 사용자취소 , - FIN : 서비스 노출/대기 검수완료 상태(필요한 상태인지 확인 필요) - */ $requestType = $payload['reqeustType']; + $requestDatetime = date('Y-m-d H:i:s', strtotime($payload['requestDatetime'])); // 2. 네이버 API 클라이언트 초기화 $naverClient = new \App\Libraries\NaverApiClient(); - // 3. 요청 유형에 따른 처리 - if (in_array($requestType, ['REG', 'MOD'])) { - // 매물 정보 조회 - $articleInfojson = $naverClient->getArticleInfo($articleNumber); - if (!$articleInfojson || !isset($articleInfojson['data']) || empty($articleInfojson['code'] !== 'success')) { - throw new \Exception("매물 정보 조회 실패: $articleNumber ::: message : " . ($articleInfojson['message'] ?? 'No response')); - } - // 받아온 정보 로그 기록 - 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 = $articleInfojson['data']; - - /** - * $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 테이블 사용 - */ - - // 공통 정보 - "articleNumber":"2500016420", - "verificationTypeCode":"S", - "cpId": "naver", - "cpArticleNumber":"nv-2025052201", - "realEstateTypeCode":"A01", - "realEstateType": "아파트", - "tradeTypeCode":"A1", - "tradeType": "매매", - "isUnregisteredVerificationRequested": false, - "isBuildingRegisterAreaCheckRequested":false, - "isAutoVerificationRequested": false, - - // $comp_sq = '2'; - // $rcpt_rating = '3'; - // $rcpt_key = $articleInfo['articleNumber']; // 매물 번호와 동일 - // $rcpt_cpid = $articleInfo['cpId']; - // $rcpt_atclno = $articleInfo['articleNumber']; - // $cpArticleNumber = $articleInfo['cpArticleNumber']; - - // $rcpt_deal_type - // $rcpt_product_info1 - // $rcpt_product_info2 - - // $rcpt_living_yn - // $rcpt_sido - // $rcpt_gugun - // $rcpt_dong - // $rcpt_x - // $rcpt_y - - // $rcpt_hscp_nm - // $rcpt_hscp_no - // $rcpt_ptp_nm - // $rcpt_ptp_no - - // $rcpt_dtl_addr - // $rcpt_li_addr - // $rcpt_jibun_addr - // $rcpt_etc_addr - // $rcpt_ref_addr - - // $rcpt_floor - // $rcpt_floor2 - // $rcpt_product - // $rcpt_product_nm - // $agent_id - // $agent_nm - // $agent_contact_tel - // $agent_head_tel - // $agent_fax - // $rsrv_date - // $rsrv_tm_ap - - - - - if ($articleInfo['verificationTypeCode'] == 'S') { // 현장확인매물 - // 현장확인매물 처리 로직 - $receiptModel = new ReceiptModel(); - - - } else { // 그외 일반매물 - - } - - + + // 매물 정보 조회 + $articleInfojson = $naverClient->getArticleInfo($articleNumber); + if (!$articleInfojson || !isset($articleInfojson['data']) || empty($articleInfojson['code'] !== 'success')) { + throw new \Exception("매물 정보 조회 실패: $articleNumber ::: message : " . ($articleInfojson['message'] ?? 'No response')); } + // 받아온 정보 로그 기록 + 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 = $articleInfojson['data']; + /** + * $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); + // } + + // } + + + diff --git a/app/Helpers/function_helper.php b/app/Helpers/function_helper.php index 724a8d7..6800182 100644 --- a/app/Helpers/function_helper.php +++ b/app/Helpers/function_helper.php @@ -237,3 +237,18 @@ function han($s) } // function to_han ($str) { return preg_replace('/(\\\u[a-f0-9]+)+/e','han("$0")',$str); } + +if (! function_exists('db_now')) { + /** + * DB의 현재 시간을 지정된 포맷으로 반환하는 RawSql 생성 + * @param string|null $format MariaDB 포맷 (예: '%Y-%m-%d %H:%i:%s') + */ + function db_now(?string $format = null) { + if ($format) { + // 포맷이 있으면 DATE_FORMAT(NOW(), '포맷') 형태로 생성 + return new \CodeIgniter\Database\RawSql("DATE_FORMAT(NOW(), '$format')"); + } + // 포맷이 없으면 기본 NOW() 반환 + return new \CodeIgniter\Database\RawSql('NOW()'); + } +} \ No newline at end of file diff --git a/app/Libraries/NaverApiClient.php b/app/Libraries/NaverApiClient.php index 76d8d1b..5690f6a 100644 --- a/app/Libraries/NaverApiClient.php +++ b/app/Libraries/NaverApiClient.php @@ -5,13 +5,14 @@ namespace App\Libraries; class NaverApiClient { protected $baseUrl = 'https://test-b2b.land.naver.com'; - protected $charger = 'admin'; + protected $charger = ''; /** * [GET] 매물 정보 조회 */ public function getArticleInfo(string $articleNumber): ?array { + $this->charger = 'admin'; $url = "{$this->baseUrl}/kiso/center/verification-article/{$articleNumber}?charger={$this->charger}"; return $this->request('GET', $url); @@ -22,8 +23,9 @@ class NaverApiClient * @param string $articleNumber 매물번호 * @param array $updateData 수정할 데이터 (tradeType, price, space 등) */ - public function updateArticleInfo(string $articleNumber, array $updateData): ?array + public function updateArticleInfo(string $articleNumber, array $updateData, string $charger = 'admin'): ?array { + $this->charger = $charger; $url = "{$this->baseUrl}/kiso/center/verification-article/{$articleNumber}?charger={$this->charger}"; return $this->request('PUT', $url, $updateData); @@ -34,6 +36,11 @@ class NaverApiClient */ private function request(string $method, string $url, array $data = null): ?array { + /** + * curl --location 'https://test-b2b.land.naver.com/kiso/center/verification-article/2500000001?charger=admin' \ +--header 'X-Naver-Client-Id: yqBbvQZ123_hjH3b3Df9' \ + */ + $ch = curl_init(); curl_setopt($ch, CURLOPT_URL, $url); curl_setopt($ch, CURLOPT_RETURNTRANSFER, true); @@ -46,7 +53,23 @@ class NaverApiClient curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); curl_setopt($ch, CURLOPT_HTTPHEADER, [ 'Content-Type: application/json', - 'Content-Length: ' . strlen($payload) + 'Content-Length: ' . strlen($payload), + 'X-Naver-Client-Id: yqBbvQZ123_hjH3b3Df9' + ]); + } + } elseif ($method === 'GET') { + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'X-Naver-Client-Id: yqBbvQZ123_hjH3b3Df9' + ]); + } elseif ($method === 'POST') { + curl_setopt($ch, CURLOPT_POST, true); + if ($data) { + $payload = json_encode($data); + curl_setopt($ch, CURLOPT_POSTFIELDS, $payload); + curl_setopt($ch, CURLOPT_HTTPHEADER, [ + 'Content-Type: application/json', + 'Content-Length: ' . strlen($payload), + 'X-Naver-Client-Id: yqBbvQZ123_hjH3b3Df9' ]); } } diff --git a/app/Models/V2ArticleModel.php b/app/Models/V2ArticleModel.php new file mode 100644 index 0000000..8eb030d --- /dev/null +++ b/app/Models/V2ArticleModel.php @@ -0,0 +1,94 @@ +