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'); } }