117 lines
4.0 KiB
PHP
117 lines
4.0 KiB
PHP
|
|
<?php
|
||
|
|
|
||
|
|
namespace App\Services\Barobill;
|
||
|
|
|
||
|
|
use App\Models\Barobill\HometaxInvoice;
|
||
|
|
use App\Services\Service;
|
||
|
|
use Illuminate\Support\Facades\DB;
|
||
|
|
use Illuminate\Support\Facades\Log;
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 홈택스 세금계산서 동기화 서비스 (API 독립 구현)
|
||
|
|
*
|
||
|
|
* MNG의 HometaxSyncService 패턴을 참고하여 독립 작성.
|
||
|
|
* 바로빌 API 응답 데이터를 로컬 DB에 upsert한다.
|
||
|
|
*/
|
||
|
|
class HometaxSyncService extends Service
|
||
|
|
{
|
||
|
|
/**
|
||
|
|
* API 응답 데이터를 로컬 DB에 동기화
|
||
|
|
*
|
||
|
|
* @param array $invoices API에서 받은 세금계산서 목록
|
||
|
|
* @param int $tenantId 테넌트 ID
|
||
|
|
* @param string $invoiceType 'sales' 또는 'purchase'
|
||
|
|
* @return array 동기화 결과
|
||
|
|
*/
|
||
|
|
public function syncInvoices(array $invoices, int $tenantId, string $invoiceType): array
|
||
|
|
{
|
||
|
|
$result = [
|
||
|
|
'inserted' => 0,
|
||
|
|
'updated' => 0,
|
||
|
|
'failed' => 0,
|
||
|
|
'total' => count($invoices),
|
||
|
|
];
|
||
|
|
|
||
|
|
if (empty($invoices)) {
|
||
|
|
return $result;
|
||
|
|
}
|
||
|
|
|
||
|
|
DB::beginTransaction();
|
||
|
|
|
||
|
|
try {
|
||
|
|
foreach ($invoices as $apiData) {
|
||
|
|
if (empty($apiData['ntsConfirmNum'])) {
|
||
|
|
$result['failed']++;
|
||
|
|
|
||
|
|
continue;
|
||
|
|
}
|
||
|
|
|
||
|
|
$modelData = HometaxInvoice::fromApiData($apiData, $tenantId, $invoiceType);
|
||
|
|
|
||
|
|
$existing = HometaxInvoice::withoutGlobalScopes()
|
||
|
|
->where('tenant_id', $tenantId)
|
||
|
|
->where('nts_confirm_num', $modelData['nts_confirm_num'])
|
||
|
|
->where('invoice_type', $invoiceType)
|
||
|
|
->first();
|
||
|
|
|
||
|
|
if ($existing) {
|
||
|
|
$existing->update([
|
||
|
|
'write_date' => $modelData['write_date'],
|
||
|
|
'issue_date' => $modelData['issue_date'],
|
||
|
|
'invoicer_corp_num' => $modelData['invoicer_corp_num'],
|
||
|
|
'invoicer_corp_name' => $modelData['invoicer_corp_name'],
|
||
|
|
'invoicer_ceo_name' => $modelData['invoicer_ceo_name'],
|
||
|
|
'invoicee_corp_num' => $modelData['invoicee_corp_num'],
|
||
|
|
'invoicee_corp_name' => $modelData['invoicee_corp_name'],
|
||
|
|
'invoicee_ceo_name' => $modelData['invoicee_ceo_name'],
|
||
|
|
'supply_amount' => $modelData['supply_amount'],
|
||
|
|
'tax_amount' => $modelData['tax_amount'],
|
||
|
|
'total_amount' => $modelData['total_amount'],
|
||
|
|
'tax_type' => $modelData['tax_type'],
|
||
|
|
'purpose_type' => $modelData['purpose_type'],
|
||
|
|
'item_name' => $modelData['item_name'],
|
||
|
|
'remark' => $modelData['remark'],
|
||
|
|
'synced_at' => now(),
|
||
|
|
]);
|
||
|
|
$result['updated']++;
|
||
|
|
} else {
|
||
|
|
HometaxInvoice::create($modelData);
|
||
|
|
$result['inserted']++;
|
||
|
|
}
|
||
|
|
}
|
||
|
|
|
||
|
|
DB::commit();
|
||
|
|
|
||
|
|
Log::info('[HometaxSync] 동기화 완료', [
|
||
|
|
'tenant_id' => $tenantId,
|
||
|
|
'invoice_type' => $invoiceType,
|
||
|
|
'result' => $result,
|
||
|
|
]);
|
||
|
|
} catch (\Throwable $e) {
|
||
|
|
DB::rollBack();
|
||
|
|
Log::error('[HometaxSync] 동기화 실패', [
|
||
|
|
'tenant_id' => $tenantId,
|
||
|
|
'invoice_type' => $invoiceType,
|
||
|
|
'error' => $e->getMessage(),
|
||
|
|
]);
|
||
|
|
throw $e;
|
||
|
|
}
|
||
|
|
|
||
|
|
return $result;
|
||
|
|
}
|
||
|
|
|
||
|
|
/**
|
||
|
|
* 마지막 동기화 시간 조회
|
||
|
|
*/
|
||
|
|
public function getLastSyncTime(int $tenantId, string $invoiceType): ?string
|
||
|
|
{
|
||
|
|
$lastSync = HometaxInvoice::withoutGlobalScopes()
|
||
|
|
->where('tenant_id', $tenantId)
|
||
|
|
->where('invoice_type', $invoiceType)
|
||
|
|
->orderByDesc('synced_at')
|
||
|
|
->value('synced_at');
|
||
|
|
|
||
|
|
return $lastSync?->format('Y-m-d H:i:s');
|
||
|
|
}
|
||
|
|
}
|