319 lines
10 KiB
PHP
319 lines
10 KiB
PHP
<?php
|
|
|
|
namespace App\Models\Credit;
|
|
|
|
use Illuminate\Database\Eloquent\Model;
|
|
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
|
use Illuminate\Support\Str;
|
|
|
|
/**
|
|
* 신용평가 조회 이력 모델
|
|
*/
|
|
class CreditInquiry extends Model
|
|
{
|
|
protected $fillable = [
|
|
'tenant_id',
|
|
'inquiry_key',
|
|
'company_key',
|
|
'company_name',
|
|
'ceo_name',
|
|
'company_address',
|
|
'business_type',
|
|
'business_item',
|
|
'establishment_date',
|
|
'nts_status',
|
|
'nts_status_code',
|
|
'nts_tax_type',
|
|
'nts_closure_date',
|
|
'user_id',
|
|
'inquired_at',
|
|
'short_term_overdue_cnt',
|
|
'negative_info_kci_cnt',
|
|
'negative_info_pb_cnt',
|
|
'negative_info_cb_cnt',
|
|
'suspension_info_cnt',
|
|
'workout_cnt',
|
|
'raw_summary',
|
|
'raw_short_term_overdue',
|
|
'raw_negative_info_kci',
|
|
'raw_negative_info_cb',
|
|
'raw_suspension_info',
|
|
'raw_workout_info',
|
|
'raw_company_info',
|
|
'raw_nts_status',
|
|
'status',
|
|
'error_message',
|
|
];
|
|
|
|
protected $casts = [
|
|
'inquired_at' => 'datetime',
|
|
'establishment_date' => 'date',
|
|
'nts_closure_date' => 'date',
|
|
'raw_summary' => 'array',
|
|
'raw_short_term_overdue' => 'array',
|
|
'raw_negative_info_kci' => 'array',
|
|
'raw_negative_info_cb' => 'array',
|
|
'raw_suspension_info' => 'array',
|
|
'raw_workout_info' => 'array',
|
|
'raw_company_info' => 'array',
|
|
'raw_nts_status' => 'array',
|
|
'short_term_overdue_cnt' => 'integer',
|
|
'negative_info_kci_cnt' => 'integer',
|
|
'negative_info_pb_cnt' => 'integer',
|
|
'negative_info_cb_cnt' => 'integer',
|
|
'suspension_info_cnt' => 'integer',
|
|
'workout_cnt' => 'integer',
|
|
];
|
|
|
|
/**
|
|
* 모델 부팅 시 inquiry_key 자동 생성
|
|
*/
|
|
protected static function boot()
|
|
{
|
|
parent::boot();
|
|
|
|
static::creating(function ($model) {
|
|
if (empty($model->inquiry_key)) {
|
|
$model->inquiry_key = self::generateInquiryKey();
|
|
}
|
|
if (empty($model->inquired_at)) {
|
|
$model->inquired_at = now();
|
|
}
|
|
});
|
|
}
|
|
|
|
/**
|
|
* 고유 조회 키 생성
|
|
*/
|
|
public static function generateInquiryKey(): string
|
|
{
|
|
return date('Ymd').Str::upper(Str::random(24));
|
|
}
|
|
|
|
/**
|
|
* 조회자 관계
|
|
*/
|
|
public function user(): BelongsTo
|
|
{
|
|
return $this->belongsTo(\App\Models\User::class);
|
|
}
|
|
|
|
/**
|
|
* 총 이슈 건수 계산
|
|
*/
|
|
public function getTotalIssueCountAttribute(): int
|
|
{
|
|
return $this->short_term_overdue_cnt
|
|
+ $this->negative_info_kci_cnt
|
|
+ $this->negative_info_pb_cnt
|
|
+ $this->negative_info_cb_cnt
|
|
+ $this->suspension_info_cnt
|
|
+ $this->workout_cnt;
|
|
}
|
|
|
|
/**
|
|
* 이슈 여부 확인
|
|
*/
|
|
public function getHasIssueAttribute(): bool
|
|
{
|
|
return $this->total_issue_count > 0;
|
|
}
|
|
|
|
/**
|
|
* 포맷된 사업자번호
|
|
*/
|
|
public function getFormattedCompanyKeyAttribute(): string
|
|
{
|
|
$key = $this->company_key;
|
|
if (strlen($key) === 10) {
|
|
return substr($key, 0, 3).'-'.substr($key, 3, 2).'-'.substr($key, 5);
|
|
}
|
|
|
|
return $key;
|
|
}
|
|
|
|
/**
|
|
* 전체 원본 데이터 조합
|
|
*/
|
|
public function getAllRawData(): array
|
|
{
|
|
return [
|
|
'companyInfo' => $this->raw_company_info,
|
|
'ntsStatus' => $this->raw_nts_status,
|
|
'summary' => $this->raw_summary,
|
|
'shortTermOverdue' => $this->raw_short_term_overdue,
|
|
'negativeInfoKCI' => $this->raw_negative_info_kci,
|
|
'negativeInfoCB' => $this->raw_negative_info_cb,
|
|
'suspensionInfo' => $this->raw_suspension_info,
|
|
'workoutInfo' => $this->raw_workout_info,
|
|
];
|
|
}
|
|
|
|
/**
|
|
* 국세청 상태가 정상(영업중)인지 확인
|
|
*/
|
|
public function isNtsActive(): bool
|
|
{
|
|
return $this->nts_status_code === '01';
|
|
}
|
|
|
|
/**
|
|
* 국세청 상태 라벨
|
|
*/
|
|
public function getNtsStatusLabelAttribute(): string
|
|
{
|
|
return match ($this->nts_status_code) {
|
|
'01' => '계속사업자',
|
|
'02' => '휴업자',
|
|
'03' => '폐업자',
|
|
default => $this->nts_status ?: '미확인',
|
|
};
|
|
}
|
|
|
|
/**
|
|
* API 응답으로부터 모델 생성
|
|
*
|
|
* @param string $companyKey 사업자번호
|
|
* @param array $apiResult 쿠콘 API 결과
|
|
* @param array|null $ntsResult 국세청 API 결과
|
|
* @param int|null $userId 조회자 ID
|
|
* @param int|null $tenantId 테넌트 ID
|
|
*/
|
|
public static function createFromApiResponse(
|
|
string $companyKey,
|
|
array $apiResult,
|
|
?array $ntsResult = null,
|
|
?int $userId = null,
|
|
?int $tenantId = null
|
|
): self {
|
|
// 요약 정보에서 건수 추출
|
|
$summaryData = $apiResult['summary']['data'] ?? [];
|
|
$creditSummaryList = $summaryData['data']['creditSummaryList'][0]
|
|
?? $summaryData['creditSummaryList'][0]
|
|
?? [];
|
|
|
|
// 기업 기본정보 추출 (OA08)
|
|
$companyInfoData = $apiResult['companyInfo']['data']['data'] ?? $apiResult['companyInfo']['data'] ?? [];
|
|
$companyName = $companyInfoData['korentrnm'] ?? $companyInfoData['entrpNm'] ?? null;
|
|
$ceoName = $companyInfoData['korreprnm'] ?? $companyInfoData['reprNm'] ?? null;
|
|
$companyAddress = $companyInfoData['addr'] ?? $companyInfoData['address'] ?? null;
|
|
$businessType = $companyInfoData['bizcnd'] ?? $companyInfoData['indutyNm'] ?? null;
|
|
$businessItem = $companyInfoData['bizitm'] ?? $companyInfoData['indutyDetailNm'] ?? null;
|
|
$establishmentDate = null;
|
|
if (! empty($companyInfoData['estbDt']) || ! empty($companyInfoData['estbDate'])) {
|
|
$estbDt = $companyInfoData['estbDt'] ?? $companyInfoData['estbDate'];
|
|
if (strlen($estbDt) === 8) {
|
|
$establishmentDate = substr($estbDt, 0, 4).'-'.substr($estbDt, 4, 2).'-'.substr($estbDt, 6, 2);
|
|
}
|
|
}
|
|
|
|
// 국세청 상태 추출
|
|
$ntsStatus = null;
|
|
$ntsStatusCode = null;
|
|
$ntsTaxType = null;
|
|
$ntsClosureDate = null;
|
|
if ($ntsResult && ($ntsResult['success'] ?? false)) {
|
|
$ntsData = $ntsResult['data'] ?? [];
|
|
$ntsStatus = $ntsData['b_stt'] ?? null;
|
|
$ntsStatusCode = $ntsData['b_stt_cd'] ?? null;
|
|
$ntsTaxType = $ntsData['tax_type'] ?? null;
|
|
if (! empty($ntsData['end_dt']) && strlen($ntsData['end_dt']) === 8) {
|
|
$ntsClosureDate = substr($ntsData['end_dt'], 0, 4).'-'.substr($ntsData['end_dt'], 4, 2).'-'.substr($ntsData['end_dt'], 6, 2);
|
|
}
|
|
}
|
|
|
|
// 성공/실패 상태 판단
|
|
$successCount = 0;
|
|
$totalCount = 7; // companyInfo 추가
|
|
$errors = [];
|
|
|
|
foreach (['companyInfo', 'summary', 'shortTermOverdue', 'negativeInfoKCI', 'negativeInfoCB', 'suspensionInfo', 'workoutInfo'] as $key) {
|
|
if (isset($apiResult[$key]['success']) && $apiResult[$key]['success']) {
|
|
$successCount++;
|
|
} else {
|
|
$errors[] = $key.': '.($apiResult[$key]['error'] ?? 'Unknown error');
|
|
}
|
|
}
|
|
|
|
$status = match (true) {
|
|
$successCount === $totalCount => 'success',
|
|
$successCount > 0 => 'partial',
|
|
default => 'failed',
|
|
};
|
|
|
|
return self::create([
|
|
'tenant_id' => $tenantId,
|
|
'company_key' => $companyKey,
|
|
'user_id' => $userId,
|
|
'inquired_at' => now(),
|
|
|
|
// 기업 기본정보
|
|
'company_name' => $companyName,
|
|
'ceo_name' => $ceoName,
|
|
'company_address' => $companyAddress,
|
|
'business_type' => $businessType,
|
|
'business_item' => $businessItem,
|
|
'establishment_date' => $establishmentDate,
|
|
|
|
// 국세청 상태
|
|
'nts_status' => $ntsStatus,
|
|
'nts_status_code' => $ntsStatusCode,
|
|
'nts_tax_type' => $ntsTaxType,
|
|
'nts_closure_date' => $ntsClosureDate,
|
|
|
|
// 요약 건수
|
|
'short_term_overdue_cnt' => $creditSummaryList['shorttermOverdueCnt'] ?? 0,
|
|
'negative_info_kci_cnt' => $creditSummaryList['negativeInfoBbCnt'] ?? 0,
|
|
'negative_info_pb_cnt' => $creditSummaryList['negativeInfoPbCnt'] ?? 0,
|
|
'negative_info_cb_cnt' => $creditSummaryList['negativeInfoCbCnt'] ?? 0,
|
|
'suspension_info_cnt' => $creditSummaryList['suspensionInfoCnt'] ?? 0,
|
|
'workout_cnt' => $creditSummaryList['workoutCnt'] ?? 0,
|
|
|
|
// 원본 데이터
|
|
'raw_company_info' => $apiResult['companyInfo'] ?? null,
|
|
'raw_nts_status' => $ntsResult,
|
|
'raw_summary' => $apiResult['summary'] ?? null,
|
|
'raw_short_term_overdue' => $apiResult['shortTermOverdue'] ?? null,
|
|
'raw_negative_info_kci' => $apiResult['negativeInfoKCI'] ?? null,
|
|
'raw_negative_info_cb' => $apiResult['negativeInfoCB'] ?? null,
|
|
'raw_suspension_info' => $apiResult['suspensionInfo'] ?? null,
|
|
'raw_workout_info' => $apiResult['workoutInfo'] ?? null,
|
|
|
|
// 상태
|
|
'status' => $status,
|
|
'error_message' => $status !== 'success' ? implode('; ', $errors) : null,
|
|
]);
|
|
}
|
|
|
|
/**
|
|
* 스코프: 사업자번호로 검색
|
|
*/
|
|
public function scopeByCompanyKey($query, string $companyKey)
|
|
{
|
|
return $query->where('company_key', $companyKey);
|
|
}
|
|
|
|
/**
|
|
* 스코프: 기간으로 검색
|
|
*/
|
|
public function scopeBetweenDates($query, $startDate, $endDate)
|
|
{
|
|
return $query->whereBetween('inquired_at', [$startDate, $endDate]);
|
|
}
|
|
|
|
/**
|
|
* 스코프: 이슈 있는 것만
|
|
*/
|
|
public function scopeWithIssues($query)
|
|
{
|
|
return $query->where(function ($q) {
|
|
$q->where('short_term_overdue_cnt', '>', 0)
|
|
->orWhere('negative_info_kci_cnt', '>', 0)
|
|
->orWhere('negative_info_pb_cnt', '>', 0)
|
|
->orWhere('negative_info_cb_cnt', '>', 0)
|
|
->orWhere('suspension_info_cnt', '>', 0)
|
|
->orWhere('workout_cnt', '>', 0);
|
|
});
|
|
}
|
|
}
|