HEX
Server: Apache/2.4.41 (Ubuntu)
System: Linux ip-172-31-42-149 5.15.0-1084-aws #91~20.04.1-Ubuntu SMP Fri May 2 07:00:04 UTC 2025 aarch64
User: ubuntu (1000)
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/vhost/disk-apps/qas.sports-crowd.com/app/Core/Ticket/Application/TicketService.php
<?php

declare(strict_types=1);

namespace App\Core\Ticket\Application;

use App\Core\Payment\Entities\Amount;
use App\Core\Payment\Entities\Payment;
use App\Core\Payment\Entities\PaymentRetrieveResponse;
use App\Core\Payment\PaymentMethodContext;
use App\Core\Payment\PaymentStatusEnum;
use App\Core\Ticket\QRTypesEnum;
use App\Core\Ticket\TicketOriginEnum;
use App\Core\User\Application\UserService;
use App\CorporateIdentity;
use App\Http\Controllers\Api\TicketApiController;
use App\Http\Controllers\TicketsController;
use App\Parameter;
use App\Services\TicketParametersService;
use App\Team;
use App\Ticket;
use App\TicketMain;
use Carbon\Carbon;
use Illuminate\Http\Request;
use SimpleSoftwareIO\QrCode\Facades\QrCode;

class TicketService
{
    private $userService;
    private $ticketParametersService;
    const ENCRYPTION_KEY = '0123456789abcdef0123456789abcdef';
    const ENCRYPTION_IV = 'abcdef9876543210abcdef9876543210';

    public function __construct()
    {
        $this->userService = new UserService();
        $this->ticketParametersService = new TicketParametersService();
    }

    public function find(int $id)
    {
        return TicketMain::findOrFail($id);
    }

    public function getById(int $id)
    {
        return TicketMain::where("id", $id)->first();
    }

    public function getByReference(string $reference)
    {
        return TicketMain::where("payment_reference", $reference)->first();
    }

    public function getByPin(string $pin)
    {
        return TicketMain::where("pin", $pin)->first();
    }

    public function getByPaymentGatewayTxId(string $txId)
    {
        return TicketMain::where('payment_transaction_id', $txId)->first();
    }

    public function setPaymentGatewayId($ticket, int $paymentGatewayId)
    {
        $ticket->gateway_payments_id = $paymentGatewayId;
        $ticket->update();
    }

    public function setPaymentGatewayTxId($ticket, $paymentGatewayTxId)
    {
        $ticket->payment_transaction_id = $paymentGatewayTxId;
        $ticket->update();
    }

    public function setTicketAsPending($ticket)
    {
        $ticket->pin ??= $this->generatePin();
        $ticket->payment_reference = strtoupper(hash("md5", (string) $ticket->id)) . '_' . $ticket->pin;
        $ticket->payment_state = PaymentStatusEnum::PENDING;
        $ticket->update();
    }

    public function validatePayment($ticket): PaymentRetrieveResponse
    {
        $this->increasePaymentAttemps($ticket);

        if (!$this->hasPaymentProcessor($ticket)) {
            return PaymentRetrieveResponse::createPending();
        }

        $payment = $this->buildPayment($ticket);

        if ($payment->paymentGatewayStatus() == PaymentStatusEnum::CONFIRMED) {
            $controller = new TicketsController;
            if (!$ticket->ticket_user_blocks->isEmpty()) {
                $controller->generateTickets($ticket->ticket_user_blocks, $ticket->id);
            } else if (!$ticket->ticket_user_block_backups->isEmpty()) {
                $controller->generateTickets($ticket->ticket_user_block_backups, $ticket->id, true);
            }

            $retrieveResponse = new PaymentRetrieveResponse(
                (string) $payment->id(),
                $payment->paymentGatewayStatus(),
                $ticket->payment_comment
            );

            $retrieveResponse->setRawData(json_decode($ticket->gateway_response ?? ''));
            return $retrieveResponse;
        }

        $paymentContext = PaymentMethodContext::init($ticket->gateway_payments_id);
        $paymentMethodResponse = $paymentContext->retrieveTicketPayment($ticket);

        if ($paymentMethodResponse->status() == PaymentStatusEnum::CONFIRMED) {
            $this->confirmPayment($ticket, $paymentMethodResponse);
        } else {
            $this->voidPayment($ticket, $paymentMethodResponse);
        }

        $ticket->gateway_response = json_encode($paymentMethodResponse->rawData());
        $ticket->update();

        return $paymentMethodResponse;
    }

    public function buildPayment($ticket): Payment
    {
        $customer = $this->userService->buildCustomerFromUserId($ticket->user_id_log);
        $payment = new Payment(
            $ticket->id,
            $ticket->pin,
            $ticket->payment_reference,
            "Pago de boleta o abono",
            new Amount($ticket->total),
            $customer
        );
        $payment->setPaymentGatewayId($ticket->gateway_payments_id);
        $payment->setPaymentGatewayTxId($ticket->payment_transaction_id);
        $payment->setPaymentGatewayStatus($ticket->payment_state);

        return $payment;
    }

    private function confirmPayment($ticket, PaymentRetrieveResponse $paymentMethodResponse)
    {
        $this->updatePayment(
            $ticket->payment_reference,
            $paymentMethodResponse->status(),
            $paymentMethodResponse->message(),
            $paymentMethodResponse->id()
        );
    }

    private function voidPayment($ticket, PaymentRetrieveResponse $paymentMethodResponse)
    {
        $this->updatePayment(
            $ticket->payment_reference,
            $paymentMethodResponse->status(),
            $paymentMethodResponse->message(),
            $paymentMethodResponse->id()
        );
    }

    // TODO: check for refactor
    private function updatePayment(
        $paymentReference,
        $paymentState,
        $paymentComment,
        $paymentTransactionId
    ) {
        $ticketApiController = new TicketApiController();
        $ticketApiController->updateTicketMainByPaymentReference(
            $paymentReference,
            $paymentState,
            $paymentComment,
            $paymentTransactionId
        );
    }

    private function increasePaymentAttemps($ticket)
    {
        $ticket->payment_attempts = $ticket->payment_attempts + 1;
        $ticket->update();
    }

    private function hasPaymentProcessor($ticket)
    {
        return !is_null($ticket->gateway_payments_id);
    }

    private function generatePin($length = 10)
    {
        return substr(str_shuffle("0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"), 0, $length);
    }

    public function ticketViewDashboard($tickets = null)
    {
        $ticketParameters = $this->ticketParametersService->getParameterObject();
        $corporateIdentity = CorporateIdentity::first();
        $parameters = Parameter::first();
        $mainTeam = Team::where('is_main', true)->first();
        return view("tickets.view.dashboard", compact('tickets', 'ticketParameters', 'corporateIdentity', 'parameters', 'mainTeam'));
    }

    public function generateDynamicQr(Request $request)
    {
        $code = base64_decode($request->get('code'));
        if (!$code) {
            return response()->json([
                'qrCode'    => null,
                'error'     => 'Invalid code'
            ]);
        }

        $ticketParameters = $this->ticketParametersService->getParameterObject();
        if (!property_exists($ticketParameters, 'qrcode_type') || !$ticketParameters->qrcode_type) {
            return response()->json([
                'qrCode'    => null,
                'error'     => 'Invalid QR type'
            ]);
        }

        switch ($ticketParameters->qrcode_type) {
            case QRTypesEnum::STATIC:
            case QRTypesEnum::WITHOUT_TIMESTAMP:
                return $this->standardQR($code);

            case QRTypesEnum::WITH_TIMESTAMP:
                return $this->timestampQR($code);

            default:
                return response()->json([
                    'qrCode'    => null
                ]);
        }
    }

    public function encryptedQR($code)
    {
        // Llaves para la encriptación
        $key = pack("H*", self::ENCRYPTION_KEY);
        $iv  = pack("H*", self::ENCRYPTION_IV);

        $secret = json_encode([
            'data'      => $code,
            'origin'    => TicketOriginEnum::WEB
        ]);

        $encrypted = openssl_encrypt($secret, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);
        $encryptedBase64 = base64_encode($encrypted);
        return $encryptedBase64;
    }

    public function decryptedQR($code)
    {
        try {
            $key = pack("H*", self::ENCRYPTION_KEY);
            $iv  = pack("H*", self::ENCRYPTION_IV);

            $ticketCode = str_replace(['-', '_'], ['+', '/'], $code);
            $encrypted = base64_decode($ticketCode);

            $decryptedData = openssl_decrypt($encrypted, 'AES-128-CBC', $key, OPENSSL_RAW_DATA, $iv);

            $payload = json_decode($decryptedData);
            if (!$payload) {
                throw new \Exception('El código QR no existe');
            }
        } catch (\Throwable $th) {
            throw new \Exception('El código QR no tiene formato correcto');
        }

        return $payload;
    }

    private function standardQR($code)
    {
        $qrCodeSize = $this->ticketParametersService->qrCodeSize();
        $qrCode = QrCode::format('png')
            ->size($qrCodeSize)
            ->errorCorrection('M')
            ->generate($code);
        $base64 = 'data:image/png;base64,' . base64_encode($qrCode->toHtml());

        return response()->json([
            'qrCode'    => $base64
        ]);
    }

    private function timestampQR($code)
    {
        $encryptedBase64 = $this->encryptedQr($code);
        $qrCodeSize = $this->ticketParametersService->qrCodeSize();
        $qrCode = QrCode::format('png')
            ->size($qrCodeSize)
            ->errorCorrection('M')
            ->generate($encryptedBase64);
        $base64 = 'data:image/png;base64,' . base64_encode($qrCode->toHtml());

        return response()->json([
            'qrCode'    => $base64
        ]);
    }

    public function getInvoiceLink($code_ticket)
    {
        $ticket = $this->getTicketByCodeTicket($code_ticket);
        if (!$ticket) {
            return false;
        }
        return $ticket->ticket_main->invoice_link;
    }

    public function getTicketByCodeTicket($code_ticket)
    {
        return Ticket::where('code_ticket', $code_ticket)->first();
    }

    public function getTicketByTicketId($ticketId)
    {
        return Ticket::find($ticketId);
    }

    public function getTicketsByTicketMainIdAndUserId($ticketMainId, $userId)
    {
        return Ticket::where('ticket_main_id', $ticketMainId)
            ->where('user_id', $userId)
            ->get();
    }

    public function isProcessingPayment($ticket)
    {
        return $ticket->payment_state == PaymentStatusEnum::PENDING && $ticket->payment_reference != PaymentStatusEnum::PENDING && Carbon::now()->lessThan(Carbon::parse($ticket->updated_at)->addMinutes(30));
    }
}