Files
confirms/app/Services/NaverService.php
2026-01-05 15:11:12 +09:00

247 lines
9.1 KiB
PHP

<?php
namespace App\Services;
use App\Libraries\NaverApiClient;
use App\Models\Entities\VrfcReqModel;
use App\Models\Entities\V2stdailyModel;
use App\Models\Entities\V2chgstatModel;
use App\Models\Entities\V2chghistoryModel;
class NaverService
{
protected $naverClient, $VrfcReqModel, $V2stdailyModel, $V2chgstatModel, $V2chghistoryModel;
public function __construct()
{
$this->naverClient = new NaverApiClient();
$this->VrfcReqModel = model(VrfcReqModel::class);
$this->V2stdailyModel = model(V2stdailyModel::class);
$this->V2chgstatModel = model(V2chgstatModel::class);
$this->V2chghistoryModel = model(V2chghistoryModel::class);
helper('log');
}
/**
* 메인 프로세스: 요청 타입에 따른 분기 처리
*/
public function processArticle(array $payload)
{
$articleNumber = $payload['articleNumber'];
$requestType = $payload['requestType'] ?? '';
// 1. 네이버 API 호출
$response = $this->naverClient->getArticleInfo($articleNumber);
if (!$response || $response['code'] !== 'success') {
throw new \Exception("네이버 API 응답 에러: $articleNumber");
}
$vrfcParams = $this->mapToDatabaseParams($response['data'], $payload);
write_custom_log("PROCESS_START | Type: $requestType | Atcl: $articleNumber", 'INFO', 'service');
switch ($requestType) {
case 'REG': // 신규 등록
$vr_sq = $this->insertVrfcReq($articleNumber, $vrfcParams);
if ($vr_sq) $this->V2stdailyModel->set_v2_st_daily(null, $vrfcParams['cpid'], $vrfcParams['vrfc_type'] . '0103', '1', 'add');
break;
case 'MOD': // 수정
$vr_sq = $this->updateVrfcReq($articleNumber, $vrfcParams);
if ($vr_sq) $this->V2stdailyModel->set_v2_st_daily(null, $vrfcParams['cpid'], $vrfcParams['vrfc_type'] . '0102', '1', 'add');
break;
case 'CNC': // 취소
$vr_sq = $this->deleteVrfcReq($articleNumber, $vrfcParams);
if ($vr_sq) $this->V2stdailyModel->set_v2_st_daily(null, $vrfcParams['cpid'], 'A0101', '1', 'add');
break;
case 'FIN': // 완료
$vr_sq = $this->finVrfcReq($articleNumber, $vrfcParams);
break;
default:
throw new \Exception("알 수 없는 requestType: $requestType");
}
return ['vr_sq' => $vr_sq, 'articleNumber' => $articleNumber];
}
/**
* [REG] 신규 등록
*/
private function insertVrfcReq($articleNumber, $params)
{
$existing = $this->VrfcReqModel->where('atcl_no', $articleNumber)->first();
if ($existing) throw new \Exception("중복 등록 시도: $articleNumber");
$params['stat_cd'] = '10';
$params['insert_user'] = '0';
$params['req_type'] = 'C';
if (!$this->VrfcReqModel->insert($params)) {
$sql = (string)$this->VrfcReqModel->getLastQuery();
write_custom_log("INSERT_FAILED | Atcl: $articleNumber | SQL: $sql", 'ERROR', 'failed');
throw new \Exception("신규 등록 실패");
}
$vr_sq = $this->VrfcReqModel->getInsertID();
$this->recordStatusAndHistory($vr_sq, '10', 'C9', "신규접수 : 10");
return $vr_sq;
}
/**
* [MOD] 수정 처리
*/
private function updateVrfcReq($articleNumber, $params)
{
$existing = $this->findExisting($articleNumber);
if (!$existing) return $this->insertVrfcReq($articleNumber, $params);
$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)
{
$existing = $this->findExisting($articleNumber);
$params['stat_cd'] = '19';
$params['req_type'] = 'D';
return $this->updateProcess($existing, $params, 'CNC', "취소 처리: {$existing['stat_cd']} => 19");
}
/**
* [FIN] 완료 처리
*/
private function finVrfcReq($articleNumber, $params)
{
$existing = $this->findExisting($articleNumber);
$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->recordStatusAndHistory($vr_sq, $params['stat_cd'], 'C9', $memo);
return $vr_sq;
}
/**
* 상태 및 이력 테이블 기록 (독립적 에러 처리)
*/
private function recordStatusAndHistory($vr_sq, $stat_cd, $chg_type, $memo)
{
// 1. 상태(stat) 저장
try {
$this->V2chgstatModel->saveChgstat([
'vr_sq' => $vr_sq, 'stat_cd' => $stat_cd, 'insert_user' => '0', 'insert_tm' => db_now()
], 'I');
} catch (\Exception $e) {
write_custom_log("STAT_SAVE_ERR | vr_sq: $vr_sq | Msg: " . $e->getMessage(), 'ERROR', 'failed');
}
// 2. 이력(history) 저장
try {
$this->V2chghistoryModel->v2_savehistory([
'vr_sq' => $vr_sq, 'stat_cd' => $stat_cd, 'chg_type' => $chg_type,
'memo' => $memo, 'insert_id' => 'SYSTEM', 'insert_tm' => db_now()
]);
} catch (\Exception $e) {
write_custom_log("HIST_SAVE_ERR | vr_sq: $vr_sq | Msg: " . $e->getMessage(), 'ERROR', 'failed');
}
}
/**
* 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'];
}
}
$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),
];
return $vrfc_params;
}
}