Files
sam-manage/app/Models/Credit/CreditInquiry.php
pro 0fe84fdebe feat:신용평가 조회 이력 DB 저장 및 리스트 화면 구현
- credit_inquiries 테이블 마이그레이션 추가
- CreditInquiry 모델 생성 (API 응답 저장, 이슈 카운트 등)
- 조회 이력 리스트 화면으로 변경 (페이지네이션, 필터)
- 원본 데이터 모달 조회 기능 추가
- 신용평가 리포트 모달 (TODO: 가공 형식 구현 예정)

Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
2026-01-22 20:17:23 +09:00

221 lines
6.6 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 = [
'inquiry_key',
'company_key',
'company_name',
'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',
'status',
'error_message',
];
protected $casts = [
'inquired_at' => 'datetime',
'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',
'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 [
'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,
];
}
/**
* API 응답으로부터 모델 생성
*/
public static function createFromApiResponse(string $companyKey, array $apiResult, ?int $userId = null): self
{
// 요약 정보에서 건수 추출
$summaryData = $apiResult['summary']['data'] ?? [];
$creditSummaryList = $summaryData['data']['creditSummaryList'][0]
?? $summaryData['creditSummaryList'][0]
?? [];
// 성공/실패 상태 판단
$successCount = 0;
$totalCount = 6;
$errors = [];
foreach (['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([
'company_key' => $companyKey,
'user_id' => $userId,
'inquired_at' => now(),
// 요약 건수
'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_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);
});
}
}