integrationService = $integrationService; } /** * POST /api/v1/integration/sgc/invoices * Recebe fatura do SGC */ public function storeInvoice(StoreInvoiceRequest $request): JsonResponse { $idempotencyKey = $request->header('X-Idempotency-Key'); if (!$idempotencyKey) { return response()->json([ 'status' => 'REJECTED', 'error_code' => 'MISSING_IDEMPOTENCY_KEY', 'message' => 'Header X-Idempotency-Key é obrigatório', ], 400); } // Verificar assinatura HMAC (em produção) // $this->verificarAssinatura($request); $resultado = $this->integrationService->receberFatura( $request->validated(), $idempotencyKey ); $statusCode = match($resultado['status']) { 'ACCEPTED' => 201, 'DUPLICATE' => 409, 'REJECTED' => 400, default => 500, }; return response()->json($resultado, $statusCode); } /** * POST /api/v1/integration/sgc/payments * Recebe confirmação de pagamento do SGC */ public function storePayment(StorePaymentRequest $request): JsonResponse { $idempotencyKey = $request->header('X-Idempotency-Key'); if (!$idempotencyKey) { return response()->json([ 'status' => 'REJECTED', 'error_code' => 'MISSING_IDEMPOTENCY_KEY', 'message' => 'Header X-Idempotency-Key é obrigatório', ], 400); } $resultado = $this->integrationService->receberPagamento( $request->validated(), $idempotencyKey ); $statusCode = match($resultado['status']) { 'ACCEPTED' => 201, 'DUPLICATE' => 409, 'REJECTED' => 400, default => 500, }; return response()->json($resultado, $statusCode); } /** * GET /api/v1/integration/sgc/invoices/{sgfDocNumber}/status * Consulta estado de uma fatura */ public function getInvoiceStatus(string $sgfDocNumber): JsonResponse { $fatura = \App\Models\Sgc\Fatura::where('sgf_doc_number', $sgfDocNumber) ->with(['ordemCompra', 'fornecedor']) ->first(); if (!$fatura) { return response()->json([ 'status' => 'NOT_FOUND', 'message' => 'Fatura não encontrada', ], 404); } // Construir lifecycle $lifecycle = [ ['event' => 'RECEBIDA', 'at' => $fatura->created_at], ]; if ($fatura->status_3_way_match !== 'Pendente') { $lifecycle[] = [ 'event' => '3WAY_MATCH', 'at' => $fatura->updated_at, 'result' => $fatura->status_3_way_match, ]; } if ($fatura->status_pagamento === 'Pago') { $lifecycle[] = [ 'event' => 'PAGA', 'at' => $fatura->data_pagamento, 'reference' => $fatura->numero_comprovativo, ]; } return response()->json([ 'sgf_doc_number' => $fatura->sgf_doc_number, 'current_status' => $fatura->status_pagamento, 'lifecycle' => $lifecycle, ]); } /** * GET /api/v1/integration/sgc/stats * Estatísticas de integração */ public function getStats(): JsonResponse { $stats = [ 'faturas' => [ 'total' => \App\Models\Sgc\Fatura::count(), 'conformes' => \App\Models\Sgc\Fatura::conformes()->count(), 'com_excecao' => \App\Models\Sgc\Fatura::comExcecao()->count(), 'pagas' => \App\Models\Sgc\Fatura::pagas()->count(), ], 'ordens_compra' => [ 'total' => \App\Models\Sgc\OrdemCompra::count(), 'cabimentadas' => \App\Models\Sgc\OrdemCompra::cabimentadas()->count(), ], 'integracao' => [ 'aceites' => DB::table('sgc_integration_log') ->where('status', 'ACCEPTED')->count(), 'rejeitadas' => DB::table('sgc_integration_log') ->where('status', 'REJECTED')->count(), 'duplicadas' => DB::table('sgc_integration_log') ->where('status', 'DUPLICATE')->count(), ], ]; return response()->json($stats); } /** * Verifica assinatura HMAC (em produção) */ private function verificarAssinatura(Request $request): bool { $signature = $request->header('X-SGC-Signature'); $secret = config('services.sgc.webhook_secret'); $payload = json_encode($request->all(), JSON_UNESCAPED_SLASHES); $expectedSignature = hash_hmac('sha256', $payload, $secret); return hash_equals($expectedSignature, $signature); } }