service
This commit is contained in:
@@ -15,10 +15,14 @@ class NaverWorker extends BaseCommand
|
|||||||
protected $name = 'naver:worker';
|
protected $name = 'naver:worker';
|
||||||
protected $description = 'Redis에서 데이터를 꺼내 DB에 저장하고 네이버 API를 호출합니다.';
|
protected $description = 'Redis에서 데이터를 꺼내 DB에 저장하고 네이버 API를 호출합니다.';
|
||||||
|
|
||||||
|
// DB 객체를 담을 변수 선언
|
||||||
|
protected $db;
|
||||||
|
|
||||||
public function run(array $params)
|
public function run(array $params)
|
||||||
{
|
{
|
||||||
helper('log'); // 여기서 로드 완료!
|
helper('log'); // 여기서 로드 완료!
|
||||||
|
|
||||||
|
$this->db = \Config\Database::connect();
|
||||||
$logModel = model(NaverWorkerLogModel::class);
|
$logModel = model(NaverWorkerLogModel::class);
|
||||||
$naverService = new \App\Services\NaverService(); // 서비스 생성
|
$naverService = new \App\Services\NaverService(); // 서비스 생성
|
||||||
|
|
||||||
@@ -35,6 +39,17 @@ class NaverWorker extends BaseCommand
|
|||||||
|
|
||||||
|
|
||||||
while (true) {
|
while (true) {
|
||||||
|
|
||||||
|
// 1. DB 연결 상태 체크 (더 견고하게)
|
||||||
|
try {
|
||||||
|
if ($this->db->connID === false || !@$this->db->connID->ping()) {
|
||||||
|
$this->db->reconnect();
|
||||||
|
CLI::write(CLI::color('🔄 Database reconnected.', 'yellow'));
|
||||||
|
}
|
||||||
|
} catch (\Throwable $e) {
|
||||||
|
$this->db->reconnect();
|
||||||
|
}
|
||||||
|
|
||||||
$result = $redis->brPop(['naver:raw_queue'], 30);
|
$result = $redis->brPop(['naver:raw_queue'], 30);
|
||||||
|
|
||||||
if (!$result) {
|
if (!$result) {
|
||||||
@@ -81,6 +96,9 @@ class NaverWorker extends BaseCommand
|
|||||||
$redis->lPush('naver:failed_queue', $rawData);
|
$redis->lPush('naver:failed_queue', $rawData);
|
||||||
helper('log');
|
helper('log');
|
||||||
write_custom_log("FAILED_DATA | Error: " . $e->getMessage(), 'ERROR', 'failed');
|
write_custom_log("FAILED_DATA | Error: " . $e->getMessage(), 'ERROR', 'failed');
|
||||||
|
|
||||||
|
// 루프 과부하 방지 (연속 에러 시)
|
||||||
|
sleep(1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ namespace App\Services;
|
|||||||
use CodeIgniter\CLI\CLI;
|
use CodeIgniter\CLI\CLI;
|
||||||
use App\Libraries\NaverApiClient;
|
use App\Libraries\NaverApiClient;
|
||||||
use App\Models\Entities\VrfcReqModel;
|
use App\Models\Entities\VrfcReqModel;
|
||||||
|
use App\Models\Entities\V2ArticleInfoModel;
|
||||||
use App\Models\Entities\V2stdailyModel;
|
use App\Models\Entities\V2stdailyModel;
|
||||||
use App\Models\Entities\NaverRawStagingModel;
|
use App\Models\Entities\NaverRawStagingModel;
|
||||||
use App\Models\Entities\ReceiptModel;
|
use App\Models\Entities\ReceiptModel;
|
||||||
@@ -15,7 +16,7 @@ use Exception;
|
|||||||
class NaverService
|
class NaverService
|
||||||
{
|
{
|
||||||
protected $db;
|
protected $db;
|
||||||
protected $naverClient, $VrfcReqModel, $V2stdailyModel, $statusService, $rawStagingModel, $receiptModel, $resultModel;
|
protected $naverClient, $VrfcReqModel, $V2stdailyModel, $statusService, $rawStagingModel, $receiptModel, $resultModel , $articleModel;
|
||||||
|
|
||||||
public function __construct()
|
public function __construct()
|
||||||
{
|
{
|
||||||
@@ -23,9 +24,11 @@ class NaverService
|
|||||||
|
|
||||||
$this->naverClient = new NaverApiClient();
|
$this->naverClient = new NaverApiClient();
|
||||||
$this->VrfcReqModel = model(VrfcReqModel::class);
|
$this->VrfcReqModel = model(VrfcReqModel::class);
|
||||||
|
$this->articleModel = model(V2ArticleInfoModel::class);
|
||||||
$this->V2stdailyModel = model(V2stdailyModel::class);
|
$this->V2stdailyModel = model(V2stdailyModel::class);
|
||||||
$this->rawStagingModel = model(NaverRawStagingModel::class);
|
$this->rawStagingModel = model(NaverRawStagingModel::class);
|
||||||
|
|
||||||
|
|
||||||
$this->receiptModel = model(ReceiptModel::class);
|
$this->receiptModel = model(ReceiptModel::class);
|
||||||
$this->resultModel = model(ResultModel::class);
|
$this->resultModel = model(ResultModel::class);
|
||||||
$this->statusService = new StatusService(); // 인스턴스 생성
|
$this->statusService = new StatusService(); // 인스턴스 생성
|
||||||
@@ -248,29 +251,276 @@ class NaverService
|
|||||||
throw $e;
|
throw $e;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
public function processTypeV2($articleNumber, $rawData, $payload){
|
|
||||||
|
|
||||||
|
/**
|
||||||
|
* [Type V2] 일반/서류/비공동주택 처리 로직
|
||||||
|
*/
|
||||||
|
private function processTypeV2($articleNumber, $rawData, $payload)
|
||||||
|
{
|
||||||
|
|
||||||
|
$vrfcParam = $this->v2Parameter($articleNumber, $rawData, $payload);
|
||||||
|
$articleInfoParam = $this->articleInfoParameter($articleNumber, $rawData, $payload);
|
||||||
|
try {
|
||||||
|
|
||||||
|
switch ($payload['requestType']){
|
||||||
|
case "REG":
|
||||||
|
|
||||||
|
$vr_sq = $this->insertVrfcReq($vrfcParam);
|
||||||
|
$articleInfoParam['vr_sq'] = $vr_sq;
|
||||||
|
write_custom_log("articleInfoParam :: " . json_encode($articleInfoParam, JSON_UNESCAPED_UNICODE) , "INFO", "SERVICE");
|
||||||
|
|
||||||
|
// 인서트 실행
|
||||||
|
if ($this->articleModel->insert($articleInfoParam)) {
|
||||||
|
// 성공 로그
|
||||||
|
write_custom_log("articleInfo Insert Success :: vr_sq: $vr_sq", "INFO", "SERVICE");
|
||||||
|
} 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']);
|
||||||
|
}
|
||||||
|
|
||||||
|
break;
|
||||||
|
case "MOD":
|
||||||
|
break;
|
||||||
|
case "CNC":
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
} catch (\Exception $e) {
|
||||||
|
write_custom_log("CRITICAL_ERROR :: " . $e->getMessage(), "ERROR", "SERVICE");
|
||||||
|
|
||||||
|
throw $e;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
private function v2Parameter($articleNumber, $rawData , $payload){
|
||||||
|
$now = db_now();
|
||||||
|
$step = isset($rawData['step']) ? $rawData['step'] : '00';
|
||||||
|
$rdate = $payload['requestDate'] ?? db_now('YmdHis');
|
||||||
|
$insert_user = 0;
|
||||||
|
$stat_cd = '10';
|
||||||
|
$sync_yn = 'N';
|
||||||
|
$insert_tm = $now;
|
||||||
|
$reg_type = function($payload) {
|
||||||
|
switch ($payload['requestType'] ?? '') {
|
||||||
|
case 'REG': return 'C';
|
||||||
|
case 'MOD': return 'U';
|
||||||
|
case 'CNC': return 'D';
|
||||||
|
default: return '0';
|
||||||
|
}
|
||||||
|
};($payload);
|
||||||
|
|
||||||
|
$files = $rawData['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'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// 1. v2_vrfc_req (검증요청) 데이터 준비
|
||||||
|
$vrfcReqData = [
|
||||||
|
'reqSeq' => '', // 네이버 요청 고유 ID
|
||||||
|
'atcl_no' => $articleNumber,
|
||||||
|
'step' => $step, // 기본 단계 설정
|
||||||
|
'cpid' => $rawData['cpId'] ?? 'naver',
|
||||||
|
'cp_atcl_id' => $rawData['cpArticleNumber'] ?? '',
|
||||||
|
'trade_type' => $rawData['tradeTypeCode'] ?? '',
|
||||||
|
'realtor_nm' => $rawData['realtor']['realtorName'] ?? null,
|
||||||
|
'realtor_tel_no' => $rawData['realtor']['representativeCellphoneNumber'] ?? null,
|
||||||
|
'seller_tel_no' => $rawData['seller']['cellphoneNumber'] ?? null,
|
||||||
|
'vrfc_type' => $rawData['verificationTypeCode'] ?? 'D', // D, T, P 등
|
||||||
|
'rgbk_confirm' => null,
|
||||||
|
'req_type' => $reg_type($payload), // 등록:C, 수정:U, 취소:D
|
||||||
|
'rdate' => $rdate,
|
||||||
|
'cpTelNo' => null,
|
||||||
|
'stat_cd' => $stat_cd, // 초기 대기 상태
|
||||||
|
'insert_user' => $insert_user,
|
||||||
|
'insert_tm' => $insert_tm,
|
||||||
|
'sync_yn' => $sync_yn,
|
||||||
|
'rgbk_confirm_owner_nm' => null,
|
||||||
|
'direct_trad_yn' => ($rawData['seller']['isDirectTrade'] ?? false) ? 'Y' : 'N',
|
||||||
|
'confirm_doc_img_url' => $confirm_doc_img_url,
|
||||||
|
'confirm_doc_owner_check_yn' => null,
|
||||||
|
'certRegister' => json_encode($certRegister),
|
||||||
|
'referenceFileUrl' => json_encode($referenceFileUrl),
|
||||||
|
];
|
||||||
|
|
||||||
|
return $vrfcReqData;
|
||||||
|
}
|
||||||
|
|
||||||
|
private function articleInfoParameter($articleNumber, $rawData , $payload){
|
||||||
|
|
||||||
|
// JSON 객체 안전하게 로드
|
||||||
|
$address = $rawData['address'] ?? [];
|
||||||
|
$space = $rawData['space'] ?? [];
|
||||||
|
$price = $rawData['price'] ?? [];
|
||||||
|
$floor = $rawData['floor'] ?? [];
|
||||||
|
$seller = $rawData['seller'] ?? [];
|
||||||
|
$realtor = $rawData['realtor'] ?? [];
|
||||||
|
$files = $rawData['realtor']['file'] ?? [];
|
||||||
|
$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'];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
$ownerTypeCode = null;
|
||||||
|
switch ($rawData['ownerTypeCode']) {
|
||||||
|
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 [
|
||||||
|
// 'vr_sq' => $vr_sq,
|
||||||
|
'atcl_no' => $articleNumber,
|
||||||
|
'cpid' => $rawData['cpId'] ?? null,
|
||||||
|
'cp_atcl_id' => $rawData['cpArticleNumber'] ?? null,
|
||||||
|
'rlet_type_cd' => $rawData['realEstateTypeCode'] ?? null,
|
||||||
|
'trade_type' => $rawData['tradeTypeCode'] ?? null,
|
||||||
|
'address_code' => $address['legalDivision']['sectorNumber'] ?? null,
|
||||||
|
'address1' => $address['complexName'] ?? null,
|
||||||
|
'address2' => trim(($address['buildingName'] ?? '') . ' ' . ($address['hoName'] ?? '')),
|
||||||
|
'address3' => $address['legalDivision']['legalDivisionAddress'] ?? null,
|
||||||
|
|
||||||
|
// 면적 및 가격 (데이터 없으면 null)
|
||||||
|
'sply_spc' => $space['supplySpace'] ?? null,
|
||||||
|
'excls_spc' => $space['exclusiveSpace'] ?? null,
|
||||||
|
'tot_spc' => $space['totalSpace'] ?? null,
|
||||||
|
'grnd_spc' => $space['groundSpace'] ?? null,
|
||||||
|
'bldg_spc' => $space['buildingSpace'] ?? null,
|
||||||
|
'deal_amt' => $price['dealAmount'] ?? 0,
|
||||||
|
'wrrnt_amt' => $price['warrantyAmount'] ?? 0,
|
||||||
|
'lease_amt' => $price['leaseAmount'] ?? 0,
|
||||||
|
'isale_amt' => $price['preSaleAmount'] ?? 0,
|
||||||
|
'prem_amt' => $price['premiumAmount'] ?? 0,
|
||||||
|
'sise' => null,
|
||||||
|
|
||||||
|
// 층 및 일정
|
||||||
|
'floor' => $floor['correspondenceFloorCount'] ?? null,
|
||||||
|
'floor2' => $floor['totalFloorCount'] ?? null,
|
||||||
|
'rdate' => date("Y-m-d H:i:s" , strtotime( $payload['requestDatetime'] )),
|
||||||
|
|
||||||
|
// 셀러
|
||||||
|
'seller_tel_no' => $seller['sellerTelephoneNumber'] ?? null, // JSON seller 객체에 연락처 필드 부재
|
||||||
|
'seller_nm' => $seller['sellerName'] ?? null,
|
||||||
|
|
||||||
|
// 중개업소
|
||||||
|
'realtor_nm' => $realtor['realtorName'] ?? null,
|
||||||
|
'realtor_tel_no' => $realtor['representativeTelephoneNumber'] ?? null,
|
||||||
|
|
||||||
|
// 단지 정보
|
||||||
|
'hscp_no' => $address['complexNumber'] ?? null,
|
||||||
|
'hscp_nm' => $address['complexName'] ?? null,
|
||||||
|
'ptp_no' => $address['pyeongTypeNumber'] ?? null,
|
||||||
|
'ptp_nm' => $address['pyeongTypeNumber'] ?? null,
|
||||||
|
|
||||||
|
// 담당자
|
||||||
|
'charger' => null, // 담당자
|
||||||
|
'reg_price_yn' => 'N', // 가격수정요청여부
|
||||||
|
'reg_charger' => null, // 등기부등본 담당자
|
||||||
|
'dept1_sq' => null, // 부서(본부)
|
||||||
|
'dept2_sq' => null, // 부서(팀)
|
||||||
|
'reg_dept2_sq' => null, // 부서(팀)
|
||||||
|
'reg_dept1_sq' => null, // 부서(본부)
|
||||||
|
|
||||||
|
// 상태 및 기타
|
||||||
|
'dong_ho_chk' => ($address['isDongHoCheck'] ?? false) ? 'Y' : 'N',
|
||||||
|
'hscplqry_lv' => $address['inquiryLevel'] ?? null,
|
||||||
|
|
||||||
|
// 소유자
|
||||||
|
'ownerNm' => $seller['ownerName'] ?? null,
|
||||||
|
'ownerTelNo' => $seller['ownerName'] ?? 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,
|
||||||
|
'rootSiteAtclExpsCnt' => null,
|
||||||
|
'redvlp_area_nm' => $adress['redevelopAreaName'] ?? null,
|
||||||
|
'biz_stp_desc' => $address['bizStepDescription'] ?? null,
|
||||||
|
|
||||||
|
// file
|
||||||
|
'cert_register' => json_encode($certRegister, JSON_UNESCAPED_UNICODE),
|
||||||
|
'direct_trad_yn' => ($seller['isDirectTrade'] ?? false) ? 'Y' : 'N',
|
||||||
|
'confirm_doc_img_url' => json_encode( $confirm_doc_img_url , JSON_UNESCAPED_UNICODE),
|
||||||
|
'confirm_doc_owner_check_yn' => $ownerCheckYn,
|
||||||
|
'owner_birth' => null,
|
||||||
|
'vrfc_type_sub' => ($rawData['verificationTypeCode'] === 'D') ? ($ownerCheckYn === 'Y' ? 'D2' : 'D1') : ($rawData['verificationTypeCode'] === 'N' ? 'N2' : $rawData['verificationTypeCode'] . '1'),
|
||||||
|
'cert_register_save_yn' => 'N',
|
||||||
|
'confirm_doc_img_url_save_yn' => 'N',
|
||||||
|
'address4' => $address['etcAddress'],
|
||||||
|
'reference_file_url' => !empty($referenceFileUrl) ? implode('|', $referenceFileUrl) : '',
|
||||||
|
'reference_file_url_save_yn' => !empty($referenceFileUrl) ? 'Y' : 'N',
|
||||||
|
'registerBookUniqueNo' => $rawData['verificationReference'] ?? null,
|
||||||
|
'relationSellerAndOwner' => null,
|
||||||
|
'ownerTypeCode' => $ownerTypeCode,
|
||||||
|
'registerBookUniqueNumber' => null
|
||||||
|
];
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [REG] 신규 등록
|
* [REG] 신규 등록
|
||||||
*/
|
*/
|
||||||
private function insertVrfcReq($articleNumber, $params)
|
private function insertVrfcReq($vrfcParam)
|
||||||
{
|
{
|
||||||
CLI::write(CLI::color('🟢 매물 정보 시작', 'green'));
|
CLI::write(CLI::color('🟢 매물 정보 시작', 'green'));
|
||||||
$existing = $this->VrfcReqModel->where('atcl_no', $articleNumber)->first();
|
$existing = $this->VrfcReqModel->where('atcl_no', $vrfcParam['atcl_no'])->first();
|
||||||
if ($existing) throw new \Exception("중복 등록 시도: $articleNumber");
|
if ($existing) throw new \Exception("중복 등록 시도: " . $vrfcParam['atcl_no']);
|
||||||
|
|
||||||
$params['stat_cd'] = '10';
|
if (!$this->VrfcReqModel->insert($vrfcParam)) {
|
||||||
$params['insert_user'] = '0';
|
$dbError = $this->VrfcReqModel->db()->error(); // DB 에러 코드와 메시지 가져오기
|
||||||
$params['req_type'] = 'C';
|
|
||||||
|
|
||||||
if (!$this->VrfcReqModel->insert($params)) {
|
|
||||||
$sql = (string)$this->VrfcReqModel->getLastQuery();
|
$sql = (string)$this->VrfcReqModel->getLastQuery();
|
||||||
write_custom_log("INSERT_FAILED | Atcl: $articleNumber | SQL: $sql", 'ERROR', 'failed');
|
write_custom_log("INSERT_FAILED | Atcl: " . $vrfcParam['atcl_no'] . " | Error: {$dbError['message']} | SQL: ".$sql, 'ERROR', 'failed');
|
||||||
throw new \Exception("신규 등록 실패");
|
throw new \Exception("신규 등록 실패: " . $dbError['message']);
|
||||||
}
|
}
|
||||||
|
|
||||||
$vr_sq = $this->VrfcReqModel->getInsertID();
|
$vr_sq = $this->VrfcReqModel->getInsertID();
|
||||||
@@ -279,6 +529,10 @@ class NaverService
|
|||||||
return $vr_sq;
|
return $vr_sq;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private function insertArticleInfo($article){
|
||||||
|
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* [MOD] 수정 처리
|
* [MOD] 수정 처리
|
||||||
*/
|
*/
|
||||||
|
|||||||
Reference in New Issue
Block a user