HEX
Server: Apache/2.4.58 (Ubuntu)
System: Linux Bradford-Sitios 6.14.0-1017-azure #17~24.04.1-Ubuntu SMP Mon Dec 1 20:10:50 UTC 2025 x86_64
User: www-data (33)
PHP: 7.4.33
Disabled: pcntl_alarm,pcntl_fork,pcntl_waitpid,pcntl_wait,pcntl_wifexited,pcntl_wifstopped,pcntl_wifsignaled,pcntl_wifcontinued,pcntl_wexitstatus,pcntl_wtermsig,pcntl_wstopsig,pcntl_signal,pcntl_signal_get_handler,pcntl_signal_dispatch,pcntl_get_last_error,pcntl_strerror,pcntl_sigprocmask,pcntl_sigwaitinfo,pcntl_sigtimedwait,pcntl_exec,pcntl_getpriority,pcntl_setpriority,pcntl_async_signals,pcntl_unshare,
Upload Files
File: /var/www/matriculas_api_dev/app/Services/WebhookFirmaAkiService.php
<?php

namespace App\Services;

use App\Repositories\ContractRepository;
use Illuminate\Support\Facades\Log;
use Exception;
use Illuminate\Support\Facades\Http;

class WebhookFirmaAkiService
{
    protected $contractRepository;

    public function __construct(ContractRepository $contractRepository)
    {
        $this->contractRepository = $contractRepository;
    }

    public function process(array $payload, array $headers, object $webhookLog): array
    {
        Log::info("Webhook FirmaAki recibido", $payload);

        $code       = data_get($payload, 'code');                   // Ej: SIGN, COMPLETE, REJECT, EMAIL SENT
        $statusCode = data_get($payload, 'document.statusCode');    // Ej: SIGNED, REJECTED
        $documentId = data_get($payload, 'document.id');    // Ej: SIGNED, REJECTED
        $contractCode = data_get($payload, 'document.metadata.contractId'); // Ej: CTR-2026-0001
        $reason     = data_get($payload, 'data.reason') ?? data_get($payload, 'data.0.reason');
        $fileName    = data_get($payload, 'document.name');
        $fileUrl    = data_get($payload, 'document.file');

        if (empty($contractCode)) {
            Log::warning("Webhook FirmaAki sin contractId, payload incompleto", $payload);
            return ['handled' => false, 'message' => 'Missing contractId'];
        }

        try {
            $webhookLog->event_code = $code;
            $webhookLog->integration_type = 'SIGNATURE';
            $webhookLog->external_id = $documentId;

            $contract = $this->contractRepository->getByCode($contractCode);
            if (!$contract) {

                Log::warning("Contrato no encontrado para contractCode", ['contract_id' => $contractCode]);
                return ['handled' => false, 'message' => 'Contract not found'];
            }
            $webhookLog->internal_id = $contract->id;
            switch (strtoupper($code)) {
                // πŸ”Ή EMAIL SENT β†’ solo registrar el evento
                case 'EMAIL SENT':
                    $webhookLog->status_code = 'SUCCESS';
                    $webhookLog->reason = 'Contrato enviado al apoderado. Correo: ' . data_get($payload, 'email');
                    break;

                // πŸ”Ή OPEN β†’ se abriΓ³ el documento
                case 'OPEN':
                    $webhookLog->status_code = 'SUCCESS';
                    $webhookLog->reason = 'Contrato abierto por el apoderado';
                    break;

                // πŸ”Ή SIGN β†’ firmado por el usuario (antes de completar)
                case 'SIGN':
                    $webhookLog->status_code = 'SUCCESS';
                    $webhookLog->reason = 'Contrato firmado parcialmente';
                    $contract->status_signature_id = $this->contractRepository->getStatus('signed', 'signature');
                    $contract->updated_at = now();
                    $contract->save();
                    break;

                // πŸ”Ή COMPLETE β†’ documento cerrado (firmado o rechazado)
                case 'COMPLETE':
                    if ($statusCode === 'SIGNED') {
                        $webhookLog->status_code = 'SUCCESS';
                        $webhookLog->reason = 'Contrato firmado exitosamente';
                        Log::info("Contrato firmado exitosamente", ['contract_id' => $contractCode]);
                        $contract->status_signature_id = $this->contractRepository->getStatus('signed', 'signature');
                        $contract->status_contract_id  = $this->contractRepository->getStatus('finished', 'contract');
                        $contract->file_code     = $fileName;
                        $contract->paid_at     = now();

                        try {
                            $response = Http::timeout(30)->get($fileUrl);

                            if ($response->successful()) {
                                $pdfBase64 = base64_encode($response->body());
                                $contract->file_data = $pdfBase64;

                                Log::info("Archivo PDF descargado y convertido correctamente", [
                                    'contract_id' => $contractCode,
                                    'size_kb' => round(strlen($pdfBase64) / 1024, 2)
                                ]);
                            } else {
                                Log::warning("No se pudo descargar el PDF firmado", [
                                    'contract_id' => $contractCode,
                                    'url' => $fileUrl,
                                    'status' => $response->status()
                                ]);
                            }
                        } catch (\Throwable $e) {
                            Log::error("Error al descargar o convertir PDF firmado", [
                                'contract_id' => $contractCode,
                                'url' => $fileUrl,
                                'error' => $e->getMessage()
                            ]);
                        }
                    } elseif ($statusCode === 'REJECTED') {
                        $webhookLog->status_code = 'FAILED';
                        $webhookLog->reason = 'Contrato rechazado por el apoderado';

                        $contract->status_signature_id = $this->contractRepository->getStatus('failed', 'signature');
                        $contract->status_contract_id  = $this->contractRepository->getStatus('pending_signature', 'contract');
                    }
                    $contract->updated_at = now();
                    $contract->save();
                    break;

                // πŸ”Ή REJECT o CANCEL β†’ documento cancelado o rechazado
                case 'REJECT':
                case 'CANCEL':

                    $webhookLog->status_code = 'FAILED';
                    $webhookLog->reason = 'Contrato cancelado por el apoderado';

                    $contract->status_signature_id = $this->contractRepository->getStatus('failed', 'signature');
                    $contract->status_contract_id  = $this->contractRepository->getStatus('pending_signature', 'contract');
                    $contract->updated_at          = now();
                    $contract->save();
                    break;

                default:
                    Log::warning("Evento no reconocido en Webhook FirmaAki", [
                        'code' => $code,
                        'contract_id' => $contractCode,
                    ]);
                    break;
            }
            $webhookLog->save(); // βœ… Guarda los valores reales

            return ['handled' => true, 'contract_id' => $contractCode, 'event' => $code];
        } catch (Exception $e) {
            $webhookLog->status_code = 'ERROR';
            $webhookLog->reason = 'Error procesando webhook FirmaAki: ' . $e->getMessage();
            $webhookLog->save();
            return ['handled' => false, 'error' => $e->getMessage()];
        }
    }
}