Files
SGF/app/Services/Sgc/IntegrationService.php
2026-11-11 09:00:17 +02:00

225 lines
7.9 KiB
PHP

<?php
namespace App\Services\Sgc;
use App\Models\Sgc\Fatura;
use App\Models\Sgc\Fornecedor;
use App\Models\Sgc\OrdemCompra;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Log;
use Illuminate\Support\Str;
class IntegrationService
{
private ThreeWayMatchService $matchService;
private BudgetCommitmentService $budgetService;
public function __construct(
ThreeWayMatchService $matchService,
BudgetCommitmentService $budgetService
) {
$this->matchService = $matchService;
$this->budgetService = $budgetService;
}
/**
* Recebe fatura do SGC e processa no SGF
*/
public function receberFatura(array $payload, string $idempotencyKey): array
{
// Verificar idempotência
$logExistente = DB::table('sgc_integration_log')
->where('idempotency_key', $idempotencyKey)
->first();
if ($logExistente) {
return [
'status' => 'DUPLICATE',
'original_receipt_id' => $logExistente->id,
'message' => 'Idempotency key já processada',
];
}
try {
$resultado = DB::transaction(function () use ($payload) {
// Buscar ou criar fornecedor
$fornecedor = $this->sincronizarFornecedor($payload['supplier']);
// Buscar OC
$oc = OrdemCompra::where('oc_id', $payload['oc_reference'])->first();
if (!$oc) {
throw new \Exception('OC não encontrada: ' . $payload['oc_reference']);
}
// Verificar se fornecedor bate
if ($oc->fornecedor_id !== $fornecedor->id) {
throw new \Exception('Fornecedor não corresponde à OC');
}
// Criar fatura
$fatura = Fatura::create([
'fatura_id' => $payload['sgf_invoice_id'],
'ordem_compra_id' => $oc->id,
'fornecedor_id' => $fornecedor->id,
'data_fatura' => $payload['dates']['invoice_date'],
'data_vencimento' => $payload['dates']['due_date'],
'valor_fatura' => $payload['amounts']['subtotal'],
'iva_valor' => $payload['amounts']['iva_amount'],
'moeda' => $payload['amounts']['currency'],
'taxa_cambio' => $payload['amounts']['exchange_rate'],
'status_3_way_match' => 'Pendente',
'status_pagamento' => 'Aguardando',
'sgf_doc_number' => $payload['sgf_doc_number'],
]);
// Executar 3-Way Match
$matchResult = $this->matchService->executarMatch($fatura);
return [
'status' => 'ACCEPTED',
'fatura_id' => $fatura->id,
'sgf_doc_number' => $fatura->sgf_doc_number,
'match_result' => $matchResult,
];
});
// Log de sucesso
DB::table('sgc_integration_log')->insert([
'idempotency_key' => $idempotencyKey,
'endpoint' => '/api/v1/integration/sgc/invoices',
'event_type' => 'INVOICE_CREATED',
'payload' => json_encode($payload),
'status' => 'ACCEPTED',
'response' => json_encode($resultado),
'created_at' => now(),
'updated_at' => now(),
]);
return $resultado;
} catch (\Exception $e) {
// Log de erro
DB::table('sgc_integration_log')->insert([
'idempotency_key' => $idempotencyKey,
'endpoint' => '/api/v1/integration/sgc/invoices',
'event_type' => 'INVOICE_CREATED',
'payload' => json_encode($payload),
'status' => 'REJECTED',
'error_code' => 'PROCESSING_ERROR',
'error_message' => $e->getMessage(),
'created_at' => now(),
'updated_at' => now(),
]);
Log::error('Erro ao processar fatura', [
'idempotency_key' => $idempotencyKey,
'error' => $e->getMessage(),
]);
return [
'status' => 'REJECTED',
'error_code' => 'PROCESSING_ERROR',
'message' => $e->getMessage(),
];
}
}
/**
* Recebe confirmação de pagamento do SGC
*/
public function receberPagamento(array $payload, string $idempotencyKey): array
{
// Verificar idempotência
$logExistente = DB::table('sgc_integration_log')
->where('idempotency_key', $idempotencyKey)
->first();
if ($logExistente) {
return [
'status' => 'DUPLICATE',
'original_receipt_id' => $logExistente->id,
];
}
try {
$resultado = DB::transaction(function () use ($payload) {
// Buscar fatura
$fatura = Fatura::where('sgf_doc_number', $payload['sgf_doc_number'])->first();
if (!$fatura) {
throw new \Exception('Fatura não encontrada: ' . $payload['sgf_doc_number']);
}
// Atualizar fatura com pagamento
$fatura->update([
'data_pagamento' => $payload['payment_date'],
'valor_pago' => $payload['amount_paid'],
'status_pagamento' => 'Pago',
'numero_comprovativo' => $payload['bank_reference'],
]);
// Atualizar OC se totalmente paga
$oc = $fatura->ordemCompra;
$totalPago = $oc->faturas()->where('status_pagamento', 'Pago')->sum('valor_pago');
if ($totalPago >= $oc->valor_comprometido) {
$oc->update(['status' => 'Totalmente Paga']);
}
return [
'status' => 'ACCEPTED',
'fatura_id' => $fatura->id,
'payment_id' => $payload['payment_id'],
];
});
// Log de sucesso
DB::table('sgc_integration_log')->insert([
'idempotency_key' => $idempotencyKey,
'endpoint' => '/api/v1/integration/sgc/payments',
'event_type' => 'PAYMENT_EXECUTED',
'payload' => json_encode($payload),
'status' => 'ACCEPTED',
'response' => json_encode($resultado),
'created_at' => now(),
'updated_at' => now(),
]);
return $resultado;
} catch (\Exception $e) {
DB::table('sgc_integration_log')->insert([
'idempotency_key' => $idempotencyKey,
'endpoint' => '/api/v1/integration/sgc/payments',
'event_type' => 'PAYMENT_EXECUTED',
'payload' => json_encode($payload),
'status' => 'REJECTED',
'error_code' => 'PROCESSING_ERROR',
'error_message' => $e->getMessage(),
'created_at' => now(),
'updated_at' => now(),
]);
return [
'status' => 'REJECTED',
'error_code' => 'PROCESSING_ERROR',
'message' => $e->getMessage(),
];
}
}
/**
* Sincroniza fornecedor do SGC para o SGF
*/
private function sincronizarFornecedor(array $supplierData): Fornecedor
{
return Fornecedor::updateOrCreate(
['sgf_fornecedor_id' => $supplierData['sgf_supplier_id']],
[
'nuit' => $supplierData['nuit'],
'nome_fornecedor' => $supplierData['name'],
'categoria_fornecedor' => $supplierData['category'] ?? 'Geral',
]
);
}
}