225 lines
7.9 KiB
PHP
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',
|
|
]
|
|
);
|
|
}
|
|
}
|