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/Http/Controllers/TicketsController.php
<?php

namespace App\Http\Controllers;

use App\Core\Ticket\Application\TicketService;
use App\Core\Ticket\Entities\TicketNotification;
use App\Core\Ticket\StageTypesEnum;
use App\Core\Ticket\TicketNotificationEnum;
use App\Core\Ticket\TicketStatusEnum;
use App\Core\Ticket\TicketTypesEnum;
use App\CorporateIdentity;
use Excel;
use DB;
use App\Door;
use App\Seat;
use App\Team;
use App\User;
use App\Zone;
use DateTime;
use Madzipper;
use App\Season;
use App\Ticket;
use App\Parameter;
use App\TicketLog;
use Carbon\Carbon;
use App\MatchEvent;
use App\TicketMain;
use App\TicketType;
use App\Tournament;
use App\PreSubscriber;
use App\TicketUserBlock;
use App\MatchEventZonePrice;
use Illuminate\Http\Request;
use App\TicketUserBlockBackup;
use App\Mail\NewSuscriptorMail;
use App\Mail\TicketPurchaseMail;
use App\Mail\TicketPurchaseEmailList;
use Illuminate\Support\Facades\Auth;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Facades\Crypt;
use App\Http\Controllers\UserController;
use Illuminate\Database\Eloquent\Builder;
use App\Http\Controllers\PrintTicketController;
use App\Http\Controllers\Imports\CancelTicketsImport;
use App\Http\Controllers\Imports\CancelTicketsTemplate;
use App\Http\Controllers\Imports\MatchEventSeatsImport;
use App\Http\Controllers\Imports\MatchEventSeatsTemplate;
use App\Http\Controllers\Imports\MatchEventSpecialTextImport;
use App\Http\Controllers\Imports\MatchEventSpecialTextTemplate;
use App\Events\SmsNotificationEvent;
use App\Events\Ticket\NotificationTicketEvent;
use App\Events\Ticket\TicketBillingEvent;
use App\FlashTicketConfiguration;
use App\Http\Controllers\UtilController;
use App\MatchEventStage;
use DataTables;
use App\Http\Controllers\Exports\ListTickeLogsExport;
use App\Mail\TicketNotificationCancelled;
use App\Mail\TicketNotificationUnavailable;
use App\Mail\TicketPurchaseEmailListMultiple;
use App\Module;
use App\Services\TicketsService;
use App\Services\TicketParametersService;
use App\Services\ZonesService;
use App\TicketParameter;

class TicketsController extends Controller
{
    private $util;
    private $ticketsService;
    private $ticketParametersService;
    private $ticketService;

    private $parameters;
    public $responseCapacityZone;

    public function __construct()
    {
        $this->parameters = Parameter::first();
        $this->util = new UtilController;
        $this->ticketsService = new TicketsService;
        $this->ticketParametersService = new TicketParametersService;
        $this->ticketService = new TicketService();
    }

    /**
     * Display a listing of the resource.
     *
     * @return \Illuminate\Http\Response
     */
    public function index(Request $request)
    {
        $list_events = $this->getMatchEvents($request);
        $events = [];
        foreach ($list_events as $key => $event) {

            // Se oculta un partido para el rol de gana
            $str_event = preg_replace("/\s+/", ",", trim($this->parameters->hide_match));
            $str_replace_event = str_replace('.', ',', trim($str_event));
            $explode_event = explode(',', $str_replace_event);
            $array_event_id_hide = array_filter($explode_event);

            if (is_array($array_event_id_hide)) {
                if (in_array(Auth::user()->rol->id, [$this->__EXTERNAL_OPERATOR_ROL]) && in_array($event->id, $array_event_id_hide)) {
                    continue;
                }
            }

            if ($event->active) {
                $events[] = $event;
            }
        }

        if ($this->validateRolePermissions('ticketing', 'seller'))
            $types = TicketType::select('id', 'name')->where('active', true)->where('id', TicketTypesEnum::FREE_SALE)->get();
        else
            $types = TicketType::select('id', 'name')->where('active', true)->get();

        $parameters = $this->parameters;
        $zonesService = new ZonesService;
        return view('tickets.list', compact('events', 'types', 'parameters'));
    }

    public function renderTicket($codes, $type = null)
    {
        $printTicketController = new PrintTicketController;
        $codes = explode(",", $codes);
        $tickets = Ticket::whereIn('code_ticket', $codes)->get();
        $qrSize = TicketParameter::where('key', 'qrcode_size')->value('value');

        $ticketBackgroundBase64 = null;
        $ticketBackgroundUrl = $tickets[0]->match_event->image ?? $tickets[0]->match_event->season->tournament->ticket_background;
        if ($ticketBackgroundUrl) {
            $imageData = file_get_contents($ticketBackgroundUrl);
            $ticketBackgroundBase64 = 'data:image/png;base64,' . base64_encode($imageData);
        }

        for ($i = 0; $i < count($tickets); $i++) {
            $ticket = $tickets[$i];
            $tickets[$i]->qrData = 'data:image/png;base64,' . $printTicketController->generateQRCode($ticket->code_ticket)['base64'];
            $tickets[$i]->price_formatted = $this->util->formatCurrency($ticket->price);
            $tickets[$i]->team = CorporateIdentity::value('platform_name');
            if ($ticketBackgroundBase64) {
                $tickets[$i]->ticketBackgroundBase64 = $ticketBackgroundBase64;
            }
        }

        return view(
            'tickets.templates.ticket_template',
            [
                'tickets' => $tickets,
                'type' => $type,
                'qrSize' => $qrSize
            ]
        );
    }

    public function getMatchEvents(Request $request)
    {
        $matchEvents = MatchEvent::select(
            'match_events.id',
            'match_events.name',
            'match_events.code',
            'match_events.date_name',
            'match_events.sales_type',
            'match_events.event_start',
            'match_events.stadium_to_play',
            'match_events.active',
            'event_start_sale',
            'event_end_sale',
            'season_id',
            'team_id',
            'match_events.zone_id',
        )
            ->where('match_events.active', true);

        if ($request->user() && !in_array($request->user()->rol->id, [$this->__SUPERADMIN_ROL, $this->__ADMIN_ROL, $this->__TICKET_OFFICE_ROL, $this->__TICKET_OFFICE_ROL_INTERNAL])) {
            $userId = $request->user()->id;
            $matchEvents = $matchEvents
                ->leftJoin('match_event_tags', 'match_event_tags.match_event_id', '=', 'match_events.id')
                ->leftJoin('user_tags', 'user_tags.tag_id', '=', 'match_event_tags.tag_id')
                ->leftjoin('tags', function ($join) {
                    $join->on('tags.id', '=', 'user_tags.tag_id')->where('tags.active', 1);
                })
                ->where(function ($q) use ($userId) {
                    $q->where('user_tags.user_id', $userId)->orWhereNull('match_event_tags.id');
                });
        } else {
            $matchEvents = $matchEvents->where('match_events.sales_type', '=', 'seleccionada');
        }

        $matchEvents = $matchEvents->groupBy('match_events.id')->get();

        $presuscription = $this->parameters->presuscription;
        if ($presuscription && $request->user()) {
            $totalSubscribers = PreSubscriber::where('email', $request->user()->email)->where('payment', false)->count();
            $presuscription = $totalSubscribers > 0 ? 1 : 0;
        }

        $newMatchEvents = [];
        foreach ($matchEvents as $matchEvent) {
            $stadium = Zone::select('id', 'img')->where('active', true)->where('id', $matchEvent->zone_id)->first();
            if (!$stadium) {
                continue;
            }
            $matchEvent->stadium = $stadium->img;

            $seasonApp = Season::select('id', 'name', 'is_suscription')->where('active', true)->where('id', $matchEvent->season_id)->first();
            if (!$seasonApp) {
                continue;
            }
            $matchEvent->season_app = $seasonApp;

            $teamApp = Team::select('id', 'name', 'display_name', 'logo')->where('active', true)->where('id', $matchEvent->team_id)->first();
            if (!$teamApp) {
                continue;
            }
            $matchEvent->team_app = $teamApp;

            $matchEvent->sales = $matchEvent->sales_type == 'seleccionada' ? ('/select-tickets/' . $matchEvent->id) : ('/flash-tickets/' . $matchEvent->id);
            $matchEvent->subscriberSales = $seasonApp->is_suscription ? ($presuscription > 0 ? ('/flash-tickets/' . $matchEvent->id . '/' . $presuscription) : '') : '';
            $matchEventZonePrices = MatchEventZonePrice::where('match_event_id', $matchEvent->id)->count();
            $matchEvent->invalidEvent = $matchEvent->sales_type == 'seleccionada' && ($matchEventZonePrices == 0 || $matchEvent->zone_id == null) ? 1 : 0;

            $newMatchEvents[] = $matchEvent;
        }
        return $newMatchEvents;
    }

    public function getTribunesParent($match_event_id = null)
    {
        $stadiumsZone   = Zone::where('zones.active', 1)->whereNull('zone_id')->pluck('id');
        $query          = Zone::select('zones.id', 'zones.name', 'alias', 'is_main', 'is_saleable', 'zones.active')->where('zones.active', 1)->whereIn('zone_id', $stadiumsZone);
        if ($match_event_id) {
            $query = $query->with(['match_event_stage' => function ($q) use ($match_event_id) {
                $q->where('match_event_id', $match_event_id)
                    ->whereIn('stage_type_id', [StageTypesEnum::BLOCK_TRIBUNE, StageTypesEnum::EXCLUSIVE_TRIBUNE]);
            }]);
        }
        $data = $query->get();
        if (Auth::user()) {
            $userId = Auth::user()->id;
            foreach ($data as $zone) {
                if (count($zone->match_event_stage)) {
                    foreach ($zone->match_event_stage as $key => $stage) {
                        if ($stage->stage_type_id == StageTypesEnum::EXCLUSIVE_TRIBUNE) {
                            $stageUser = DB::table('match_event_stages')
                                ->leftJoin('match_event_stage_tags', 'match_event_stage_tags.match_event_stage_id', '=', 'match_event_stages.id')
                                ->leftJoin('user_tags', 'user_tags.tag_id', '=', 'match_event_stage_tags.tag_id')
                                ->leftjoin('tags', function ($join) {
                                    $join->on('tags.id', '=', 'user_tags.tag_id')->where('tags.active', 1);
                                })
                                ->where('match_event_stages.id', $stage->id)
                                ->where(function ($q) use ($userId) {
                                    $q->where('user_tags.user_id', $userId)->orWhereNull('match_event_stage_tags.id');
                                })->count();
                            if ($stageUser)
                                unset($zone->match_event_stage[$key]);
                        }
                    }
                }
            }
        }
        return $data;
    }

    public function loadStadiumZones(Request $request)
    {
        return $this->ticketsService->loadStadiumZones($request);
    }

    public function listTribunesParent($match_event_id)
    {
        try {
            $tribunesParent = $this->getTribunesParent($match_event_id);
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $tribunesParent));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "listTribunesParen", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function getTribunesByZone($parent_zone_id)
    {
        try {
            $zones = Zone::where('zone_id', $parent_zone_id)->where('active', true)->get();
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $zones));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "getTribunesByZone", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function getSeatByZone($zone_id)
    {
        try {
            $seats = Seat::where('zone_id', $zone_id)->with('letter')->get();
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $seats));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "getSeatByZone", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function getSeatFreeByZone($zone_id, $match_event_id)
    {
        try {
            $matchEvent = MatchEvent::with('season')->where('id', $match_event_id)->first();
            $parameters = Parameter::select('presuscription')->first();
            $presubscriptionActive = $parameters->presuscription && $matchEvent->season->is_suscription;

            $seats = Seat::with('letter')
                ->where('zone_id', $zone_id)
                ->whereNotIn('id', function ($query) use ($match_event_id) {
                    $query->select('seat_id')->from('ticket_user_blocks')->where('match_event_id', $match_event_id);
                }) // Sin bloqueos
                ->whereNotIn('id', function ($query) use ($match_event_id) {
                    $query->select('seat_id')->from('tickets')->where('match_event_id', $match_event_id)->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED]);
                }) // Que no este vendida
                ->whereNotIn('id', function ($query) use ($match_event_id) {
                    $query->select('seat_id')->from('match_event_stages')->where('match_event_id', $match_event_id)->where('stage_type_id', StageTypesEnum::BLOCK_SEAT);
                }) // Que no este bloqueada para el evento
                ->when($presubscriptionActive, function ($query) {
                    $query->whereNotIn('id', function ($query) {
                        $query->select('seat_id')->from('pre_subscribers')->where(function ($query1) {
                            $query1->where('payment', 1)->orWhere('is_credit', 1);
                        });
                    });
                }) // Que no este reservada para un abonado
                ->get();

            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $seats));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "getSeatFreeByZone", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function getParentZones($zone_id)
    {
        try {
            $controller = new ZonesController;
            $zoneChilds = $controller->getZonesChilds($zone_id)->toArray();
            $zones = Zone::select('id', 'name', 'zone_id')->with('zone')->whereIn('id', $zoneChilds)->get();
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $zones));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "getZones", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function getChildZones($zone_id)
    {
        try {
            $controller = new ZonesController;
            $zones = $controller->getChildZones($zone_id);
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $zones));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "getZones", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function getSubZones($zone_id, $event_id)
    {
        try {
            $zones = DB::table('zones as z')
                ->select(
                    'z.id',
                    'z.name',
                    'z.alias',
                    'z.active',
                    'z.is_saleable',
                    'z.zone_id',
                    'z.salable_capacity',
                    'z.total_capacity',
                    DB::raw('(z.salable_capacity - SUM(IF(t.id, 1, 0) + IF(tu.id, 1, 0) + IF(me.id, 1, 0))) AS available_seats')
                )
                ->leftJoin('seats as s', 's.zone_id', '=', 'z.id')
                ->leftJoin('tickets as t', function ($join) use ($event_id) {
                    $join->on('t.seat_id', '=', 's.id')
                        ->where('t.match_event_id', $event_id)
                        ->whereIn('t.ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED]);
                })
                ->leftJoin('ticket_user_blocks as tu', function ($join) use ($event_id) {
                    $join->on('tu.seat_id', '=', 's.id')
                        ->where('tu.match_event_id', $event_id);
                })
                ->leftJoin('match_event_stages as me', function ($join) use ($event_id) {
                    $join->on('me.seat_id', '=', 's.id')
                        ->where('me.match_event_id', $event_id);
                })
                ->where('z.zone_id', $zone_id)
                ->where('z.active', true)
                ->groupBy('z.id')
                ->get();
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $zones));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "getZones", "m" => __('messages.error_creating'), "data" => $th->getMessage()));
        }
    }

    public function getSeatsCount($zone_id, $event_id)
    {
        try {
            $count = 0;
            // se valida la capacidad de la localidad no este superada
            if (!$this->salableCapacityZone($zone_id, $event_id)) {
                return 0;
            }
            $seats = Seat::select('seats.id', DB::raw('IF(t.id, 1, 0) AS ticket'), DB::raw('IF(tu.id, 1, 0) AS ticket_user_block'))
                ->where([['seats.zone_id', $zone_id], ['active', true]])
                ->leftJoin('tickets AS t', function ($join) use ($event_id) {
                    $join->on('seats.id', '=', 't.seat_id')->where('t.match_event_id', $event_id)
                        ->whereIn('t.ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED]);
                })
                ->leftJoin('ticket_user_blocks AS tu', function ($join) use ($event_id) {
                    $join->on('seats.id', '=', 'tu.seat_id')->where('tu.match_event_id', $event_id);
                })
                ->get();

            foreach ($seats as $seat) {
                if ($this->isAvailable($seat)) {
                    $count++;
                }
            }
            return $count;
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "getSeats", "m" => __('messages.error_creating'), "data" => $th->getMessage()));
        }
    }

    public function isAvailable($seat)
    {
        $flag = true;
        if ($seat->ticket || $seat->ticket_user_block) {
            $flag = false;
        }
        return $flag;
    }

    public function getSeats($zone_id, $event_id, $is_reassign = false)
    {
        try {
            // se valida la capacidad de la localidad no este superada
            if (!$this->salableCapacityZone($zone_id, $event_id, 0, null, $validateRules = false)) {
                if ($is_reassign) {
                    $response = json_decode($this->responseCapacityZone->getContent());
                    return response(array("r" => true, "type" => "error", "title" => "", "m" => $response->m, "data" => []));
                }
                return $this->responseCapacityZone;
            }
            $parameters = Parameter::select('presuscription')->first();
            $presubscriptionActive = $parameters->presuscription;
            $event = MatchEvent::with('season')->where('id', $event_id)->first();
            $user = Auth::user();
            $seats = Seat::select(
                'seats.id',
                'seats.code',
                'seats.letter_id',
                'seats.zone_id',
                DB::raw('IF(t.id, 1, 0) AS ticket'),
                DB::raw('IF(tu.id, 1, 0) AS ticket_user_block'),
                't.ticket_type_id',
                'tu.is_social_distancing',
                DB::raw('IF(presub.id, 1, 0) AS presubscription')
            )
                ->with(['letter' => function ($q) {
                    $q->select('id', 'name');
                }])
                ->with(['match_event_stage' => function ($q) use ($event_id) {
                    $q->where('match_event_id', $event_id);
                }])
                ->leftJoin('tickets AS t', function ($join) use ($event_id) {
                    $join->on('seats.id', '=', 't.seat_id')->where('t.match_event_id', $event_id)
                        ->whereIn('t.ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED]);
                })
                ->leftJoin('ticket_user_blocks AS tu', function ($join) use ($event_id) {
                    $join->on('seats.id', '=', 'tu.seat_id')->where('tu.match_event_id', $event_id);
                })
                ->leftJoin('pre_subscribers AS presub', function ($join) use ($presubscriptionActive, $user, $event) {
                    $join->on('seats.id', '=', 'presub.seat_id');
                    if (!$presubscriptionActive || !$event->season->is_suscription) {
                        $join->whereNull('presub.seat_id');
                    }
                    // TODO: Se comenta por el momento, para reestringir la compra de silla abonada desde boleta suelta.
                    // if ($user) {
                    //     $join->where('presub.email', '!=', $user->email);
                    // }
                })
                ->where('seats.zone_id', $zone_id)
                ->where('seats.active', 1)
                ->orderBy('seats.letter_id', 'desc')
                ->orderBy('seats.code', 'asc')
                ->get();
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $seats));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "getSeats", "m" => __('messages.error_creating'), "data" => $th->getMessage()));
        }
    }

    public function isPreabonado($document)
    {
        try {
            if (!User::where([['document', $document], ['active', true]])->first()) {
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "isPreabonado", "m" => "Debes ingresar todos los datos en tu perfil.", "data" => null));
            }
            $listPreSubcriber = PreSubscriber::where('document', $document)->where('payment', false)->get();
            if (count($listPreSubcriber) <= 0) {
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "isPreabonado", "m" => $this->parameters->presuscription_msj, "data" => null));
            }
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $listPreSubcriber));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "isPreabonado", "m" => __('messages.error_creating'), "data" => $th->getMessage()));
        }
    }

    public function isPreabonadoByEmail(Request $request)
    {
        try {
            $listPreSubcriber = PreSubscriber::where('email', $request->email)->get();
            if (count($listPreSubcriber) <= 0) {
                $message = $this->parameters->is_exclusive_subscriber_login ? $this->parameters->msj_exclusive_subscriber_login : null;
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "isPreabonadoByEmail", "m" => $message, "data" => null));
            }
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => null));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "isPreabonadoByEmail", "m" => __('messages.error_creating'), "data" => $th->getMessage()));
        }
    }

    public function isPreabonadoByDocSuscription(Request $request)
    {
        try {
            $listPreSubcriber = PreSubscriber::where('document', $request->suscriptionDoc)->get();
            if (count($listPreSubcriber) <= 0) {
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "isPreabonadoByEmail", "m" => $this->parameters->presuscription_msj, "data" => null));
            }
            foreach ($listPreSubcriber as $item) {
                $item->email = $request->email;
                $item->update();
            }
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => null));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "isPreabonadoByEmail", "m" => __('messages.error_creating'), "data" => $th->getMessage()));
        }
    }

    public function getSeatPrice($zone_id, $event_id)
    {
        try {
            $matchEventPrice = MatchEventZonePrice::select('id', 'match_event_id', 'price', 'price_suscription', 'zone_id')
                ->where([['zone_id', $zone_id], ['match_event_id', $event_id]])->first();
            if (!$matchEventPrice) {
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "validateSell", "m" => __('messages.error_validation_tickets.zone_no_saleable'), "data" => null));
            }

            $parameters = Parameter::select('presuscription')->first();
            $presubscriptionActive = $parameters->presuscription;
            if (!$presubscriptionActive) {
                $matchEventPrice->price_suscription = 0;
                $matchEventPrice->subscriberPrices = [];
            } else {
                $user = Auth::user();
                $subscriberPrices = PreSubscriber::select('s.id AS seat_id', 'pre_subscribers.price AS price_suscription')
                    ->join('seats as s', 's.id', '=', 'pre_subscribers.seat_id')
                    ->join('zones as z', 'z.id', '=', 's.zone_id')
                    ->where('z.id', $zone_id)
                    ->where(function ($q) use ($user) {
                        if ($user) {
                            $q->where('pre_subscribers.email', $user->email);
                        }
                    })
                    ->groupBy('s.id', 'pre_subscribers.price')
                    ->get();
                $matchEventPrice->subscriberPrices = $subscriberPrices;
            }

            $controller = new ServiceChargeController();
            if ($matchEventPrice && $controller->validateServiceCharge()) {
                $zone = Zone::select('zone_id')->where('id', $zone_id)->first();
                $request = new Request([
                    'services'      => 'ticket',
                    'match_events'  => $event_id,
                    'zones'         => [$zone_id, $zone->zone_id],
                ]);
                $serviceCharge = $controller->calculateServiceCharge($request);
                $matchEventPrice->service_charge = $serviceCharge;
            }

            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $matchEventPrice));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "getSeatPrice", "m" => __('messages.error_creating'), "data" => $th->getMessage()));
        }
    }

    public function searchUser(Request $request, $document, $match_event_id = null, $ticket_type_id = null)
    {
        try {
            $user = new UserController($request);
            $search = $user->searchUser($document);

            $isPreabonado = null;
            if ($this->parameters->presuscription) {
                $isPreabonado = $this->isPreabonado($document);
            }
            if ($match_event_id && $search) {
                $tickets = Ticket::where('match_event_id', $match_event_id)
                    ->where('user_id', $search->id)
                    ->where('ticket_type_id', $ticket_type_id)
                    ->count();

                return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $search, 'tickets' => $tickets, "isPreabonado" => $isPreabonado));
            }

            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $search, "isPreabonado" => $isPreabonado));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "searchUser", "m" => __('messages.error_creating'), "data" => $th->getMessage()));
        }
    }


    public function exchangeTicketsToUsers(Request $request, $document, $match_event_id = null, $ticket_type_id = null)
    {
        try {
            $user = new UserController($request);
            $search = $user->searchUser($document);
            $isPreabonado = null;
            if ($this->parameters->presuscription) {
                $isPreabonado = $this->isPreabonado($document);
            }
            if ($search->document) {
                $searchUser = User::where('document', '=', $search->document)->get();
                return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $searchUser, 'tickets' => $searchUser, "isPreabonado" => $isPreabonado));
            }
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => $searchUser, "isPreabonado" => $isPreabonado));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "searchUser", "m" => __('messages.error_creating'), "data" => $th->getMessage()));
        }
    }

    public function createBlockTicket($seat_id, $match_event_id, $user_id, $ticket_type_id, $ticket_main_id, $zone_id, $pin = false, $is_social_distancing = false, $price = false)
    {
        try {
            $minutesToBlock = 0;

            // Se procesa el bloqueo
            $minutesToBlock = $this->parameters->maximum_sale_blocking_time;
            $this->processBlockGeneralTicket($seat_id, $match_event_id, $user_id, $minutesToBlock, $ticket_type_id, $ticket_main_id, $zone_id, $is_social_distancing, $price);

            // mensaje mostrando el tiempo limite que tiene para efectuar la compra
            $messageBlockMinutes = Carbon::now()->addMinutes($minutesToBlock)->format('h:i:s A');
            $message = __($this->parameters->msj_waiting_time_for_seat_blocking ?? 'messages.create_block', ['dateblock' => $messageBlockMinutes]);

            if ($pin) {
                $message = $message . "\n" . __('messages.create_block_2') . $pin;
            } else {
                $message = $message . __('messages.create_block_3');
            }
            return array("r" => true, "type" => "success", "title" => "", "origin" => "createBlockTicket", "m" => $message, "data" => null);
        } catch (\Throwable $th) {
            return array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "createBlockTicket", "m" => __('messages.error_global'), "data" => $th->getMessage());
        }
    }

    public function getSeatBlockdistancing_x($index_init, $array_search)
    {
        // definimos el index de inicio de bloqueo a la izquierda y derecha deacuerdo al parametro de numero de sillas a bloquear
        $init_block_left = $index_init - $this->parameters->social_distancing_number_seat_x;
        $init_block_right = $index_init + $this->parameters->social_distancing_number_seat_x;

        $list_block_distancing = [];

        foreach ($array_search as $key2 => $id) {
            if ($this->parameters->social_distancing_left) {
                if ($key2 >= $init_block_left && $key2 < $index_init) {
                    $list_block_distancing[] = $id;
                }
            }

            if ($this->parameters->social_distancing_right) {
                if ($key2 > $index_init && $key2 <= $init_block_right) {
                    $list_block_distancing[] = $id;
                }
            }
        }

        return $list_block_distancing;
    }

    public function getSeatBlockdistancing_y($index_init, $array_search, $array_file_origin)
    {
        $number_differente = 0;
        // definimos el index de inicio de bloqueo de arriba y abajo deacuerdo al parametro de numero de sillas a bloquear
        if (count($array_file_origin) != count($array_search)) {
            $number_differente = count($array_search) - count($array_file_origin);
        }
        if ($number_differente) {
            $index_init = $index_init + ($number_differente / 2);
        }

        $init_block_left = $index_init - $this->parameters->social_distancing_number_seat_y;
        $init_block_right = $index_init + $this->parameters->social_distancing_number_seat_y;

        $list_block_distancing = [];

        foreach ($array_search as $key2 => $id) {
            if ($key2 == $index_init) {
                $list_block_distancing[] = $id;
            }

            if ($key2 >= $init_block_left && $key2 < $index_init) {
                $list_block_distancing[] = $id;
            }

            if ($key2 > $index_init && $key2 <= $init_block_right) {
                $list_block_distancing[] = $id;
            }
        }

        return $list_block_distancing;
    }

    public function getGroupSeatByLetter($zone_id, $letter_id)
    {
        $resp = [];
        // $c = Seat::where([['zone_id',$zone_id],['letter_id', $letter_id]])->pluck('code')->toArray();
        $c = Seat::where([['zone_id', $zone_id], ['letter_id', $letter_id]])->pluck('id')->toArray();
        if ($c) {
            $resp = $c;
        }
        return $resp;
    }

    public function searchNeighbour($seat_id, $zone_id)
    {
        $list_block_distancing = [];
        $seat = Seat::where('id', $seat_id)->first();
        if ($seat) {
            $seats_group = Seat::where('zone_id', $zone_id)->distinct()->pluck('letter_id')->toArray();
            $ids_x_group = $this->getGroupSeatByLetter($zone_id, $seat->letter_id);

            // buscamos la fila vecina de arriba y la de abajo
            $letter_id_top = 0;
            $letter_id_bottom = 0;
            foreach ($seats_group as $key => $letter) {
                if ($letter == $seat->letter_id) {
                    if (isset($seats_group[$key + 1]) && $this->parameters->social_distancing_top) {
                        $letter_id_top = $seats_group[$key + 1];
                    }
                    if (isset($seats_group[$key - 1]) && $this->parameters->social_distancing_bottom) {
                        $letter_id_bottom = $seats_group[$key - 1];
                    }
                }
            }

            // buscamos el index de la silla de la fila origen a comprar por el usuario
            // $index_seat_buy = array_search($seat->code, $ids_x_group);
            $index_seat_buy = array_search($seat->id, $ids_x_group);

            // Consultamos la sillas a bloquear en el eje x basado en el index de la silla a comprar por el cliente
            $list_block_distancing = array_merge($this->getSeatBlockdistancing_x($index_seat_buy, $ids_x_group), $list_block_distancing);

            // Consultamos la sillas a bloquear en el eje y basado en el index de la silla a comprar por el cliente
            if ($letter_id_top != 0 && $this->parameters->social_distancing_top) {
                $ids_top_group = $this->getGroupSeatByLetter($zone_id, $letter_id_top);
                $list_block_distancing = array_merge($this->getSeatBlockdistancing_y($index_seat_buy, $ids_top_group, $ids_x_group), $list_block_distancing);
            }

            if ($letter_id_bottom != 0 && $this->parameters->social_distancing_bottom) {
                $ids_bottom_group = $this->getGroupSeatByLetter($zone_id, $letter_id_bottom);
                $list_block_distancing = array_merge($this->getSeatBlockdistancing_y($index_seat_buy, $ids_bottom_group, $ids_x_group), $list_block_distancing);
            }
        }
        return $list_block_distancing;
    }


    public function deleteBlock($seat_id, $match_event_id, $user_id)
    {
        try {
            TicketUserBlock::where([['seat_id', $seat_id], ['match_event_id', $match_event_id], ['user_id', $user_id]])->delete();
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "deleteBlock", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function deleteBlockBackup($seat_id, $match_event_id, $user_id)
    {
        try {
            TicketUserBlockBackup::where([['seat_id', $seat_id], ['match_event_id', $match_event_id], ['user_id', $user_id]])->delete();
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "deleteBlockBackup", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    private function createNewBlock($data)
    {
        TicketUserBlock::create($data);
    }

    private function processBlockGeneralTicket($seat_id, $match_event_id, $user_id, $minutesToBlock, $ticket_type_id, $ticket_main_id, $zone_id, $is_social_distancing, $custom_price)
    {
        $price = 0;
        if ($custom_price) {
            $price = $custom_price;
        } else {
            if (!$is_social_distancing && $ticket_type_id != TicketTypesEnum::COMPLIMENTARY) {
                $zonePrice = MatchEventZonePrice::where([['zone_id', $zone_id], ['match_event_id', $match_event_id]])->first();
                if ($zonePrice && $ticket_type_id != TicketTypesEnum::SUBSCRIBER) {
                    $price = $zonePrice->price;
                } else if ($zonePrice && $ticket_type_id == TicketTypesEnum::SUBSCRIBER) {
                    $price = $zonePrice->price_suscription;
                }
            }
        }
        $data = [
            'seat_id'               =>  $seat_id,
            'match_event_id'        =>  $match_event_id,
            'user_id'               =>  $user_id,
            'zone_id'               =>  $zone_id,
            'start_block'           =>  Carbon::now(),
            'end_block'             =>  Carbon::now()->addMinutes($minutesToBlock),
            'is_social_distancing'  =>  $is_social_distancing,
            'price'                 =>  $price,
            'ticket_type_id'        =>  $ticket_type_id,
            'ticket_main_id'        =>  $ticket_main_id,
        ];
        $this->createNewBlock($data);
    }

    public function getEventsSubscription($seasonId = null, $matchEventId = null)
    {
        $listMatchEvents = [];
        if (!$seasonId && !$matchEventId) {
            $tournaments = Tournament::where('active', true)->get();
            foreach ($tournaments as $tournament) {
                $listSeasons = Season::where([['tournament_id', $tournament->id], ['is_suscription', true], ['active', true]])->orderBy('start', 'asc')->get();
                foreach ($listSeasons as $season) {
                    $events = MatchEvent::where('season_id', $season->id)->where('event_start', '>', Carbon::now())->with('team')->orderBy('event_start', 'asc')->get();
                    if ($events) {
                        $listMatchEvents[] = $events;
                    }
                }
            }
        } else if ($seasonId) {
            $events = MatchEvent::where([['season_id', $seasonId], ['event_start', '>', Carbon::now()]])->with('team')->orderBy('event_start', 'asc')->get();
            if ($events) {
                $listMatchEvents[] = $events;
            }
        } else if ($matchEventId) {
            $matchEvent = MatchEvent::find($matchEventId);
            $events = MatchEvent::where([['season_id', $matchEvent->season_id], ['event_start', '>', Carbon::now()]])->with('team')->orderBy('event_start', 'asc')->get();
            if ($events) {
                $listMatchEvents[] = $events;
            }
        }
        $result = array_flatten($listMatchEvents);
        return collect($result)->sortBy('event_start')->values();
    }

    // Genera Pin aleatorio gane.
    public function generatepin($seat_id = 1)
    {
        $date = Carbon::now();
        $date->addSeconds($seat_id);
        return intval($date->getPreciseTimestamp(3));
    }

    public function createTicket(array $params)
    {
        $seat_id = $params['seat_id'];
        $match_event_id = $params['match_event_id'];
        $user_id = $params['user_id'];
        $ticket_type_id = $params['ticket_type_id'];
        $ticket_main_id = $params['ticket_main_id'];
        $price = $params['price'];
        $is_from_massive = $params['is_from_massive'] ?? false;
        $special_text = $params['special_text'] ?? null;
        $is_an_email_sent = $params['is_an_email_sent'] ?? false;

        try {
            $current_seat = Seat::select('code', 'zone_id', 'letter_id')->with('letter')->where('id', $seat_id)->first();
            $zone = Zone::select('id', 'name', 'door_id', 'zone_id')->where('id', $current_seat->zone_id)->first();
            $event = MatchEvent::select('code')->where('id', $match_event_id)->first();
            $door_name = null;
            if ($zone && $zone->door_id) {
                $c_q = Door::select('name')->where('id', $zone->door_id)->first();
                if ($c_q) {
                    $door_name = $c_q->name;
                }
            }
            if (!$special_text) {
                $stage = MatchEventStage::where([['match_event_id', $match_event_id], ['stage_type_id', StageTypesEnum::TICKET_LABEL]])->whereIn('zone_id', [$zone->id, $zone->zone_id])->first();
                if ($stage) {
                    $special_text = $stage->special_text;
                }
            }

            if (Ticket::where([['seat_id', $seat_id], ['match_event_id', $match_event_id], ['ticket_status_id', TicketStatusEnum::PURCHASED]])->first()) {
                return;
            }

            $ticket = Ticket::create([
                'code_ticket'       => config('app.client') . $this->generatepin($seat_id),
                'seat_id'           => $seat_id,
                'match_event_id'    => $match_event_id,
                'user_id'           => $user_id,
                'ticket_type_id'    => $ticket_type_id,
                'ticket_status_id'  => 1,
                'price'             => $price,
                'zone'              => $zone->name,
                'letter_seat'       => $current_seat->letter->name,
                'code_seat'         => $current_seat->code,
                'code_event'        => $event->code,
                'door'              => $door_name,
                'ticket_main_id'    => $ticket_main_id,
                'special_text'      => $special_text,
                'is_an_email_sent'  => $is_an_email_sent
            ]);


            if ($ticket && !$is_from_massive) {
                if (Auth::user()) {
                    $this->registerLog(Auth::user()->id, 'Se creo boleta', json_encode($ticket), "Create", 'Boleteria');
                } else {
                    $this->registerLog($user_id, 'Se creo boleta', json_encode($ticket), "Create", 'Boleteria');
                }
                $this->createLogTicket(TicketStatusEnum::PURCHASED, $ticket->id);
                $message = __('messages.create_ticket');
                return array("r" => true, "type" => "success", "title" => "", "origin" => "createTicket", "m" => $message, "data" => null);
            }

            if ($is_from_massive) {
                if (Auth::user()) {
                    $this->registerLog(Auth::user()->id, 'Se creo boleta desde masivo', json_encode($ticket), "Create", 'Boleteria');
                }
                $this->createLogTicket(TicketStatusEnum::PURCHASED, $ticket->id);
                return $ticket;
            }

            return array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "createTicket", "m" => __('messages.error_global'), "data" => null);
        } catch (\Throwable $th) {
            return array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "createTicket", "m" => __('messages.error_global'), "data" => $th->getMessage());
        }
    }

    public function existsTicket($seat_id, $event_id, $user_id)
    {
        if ($this->parameters->is_social_distancing) {
            return Ticket::where([['seat_id', $seat_id], ['match_event_id', $event_id], ['user_id', '=', $user_id]])->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])->exists();
        } else {
            return Ticket::where([['seat_id', $seat_id], ['match_event_id', $event_id]])->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])->exists();
        }
    }

    public function existsBlock($seat_id, $event_id, $user_id)
    {
        if ($this->parameters->is_social_distancing) {
            return TicketUserBlock::where([['seat_id', $seat_id], ['match_event_id', $event_id], ['is_social_distancing', false], ['user_id', '!=', $user_id]])->exists();
        } else {
            return TicketUserBlock::where([['seat_id', $seat_id], ['match_event_id', $event_id]])->exists();
        }
    }

    public function infoSeat($seat_id)
    {
        return Seat::where('id', $seat_id)->with('letter')->first();
    }

    public function validateBlockDistancing($ticket_main_id)
    {
        $distancing = TicketUserBlock::where([['ticket_main_id', $ticket_main_id], ['is_social_distancing', true]])->get();
        foreach ($distancing as $item) {
            $item->end_block = null;
            $item->update();
        }
    }

    // Retorna la cantidad de sillas vendibles de una tribuna
    // $currentTickets = el numero de boletas que se van a comprar en la transaccion actual
    public function salableCapacityZone($zone_id, $event_id, $currentTickets = 0, $userId = null, $validateRules = true)
    {
        $zone = Zone::where('id', $zone_id)
            ->with(['match_event_stage' => function ($q) use ($event_id) {
                $q->where('match_event_id', $event_id);
            }])
            ->first();

        $salable_capacity = $zone->salable_capacity;
        $zoneActive = $zone->active;
        if ($validateRules && $zone && count($zone->match_event_stage)) {
            $stage = $zone->match_event_stage->last();
            if ($stage->stage_type_id == StageTypesEnum::BLOCK_TRIBUNE) {
                $zoneActive = $stage->active;
            }
            if ($stage->stage_type_id == StageTypesEnum::LIMIT_TRIBUNE_CAPACITY) {
                $salable_capacity = $stage->salable_capacity;
            }
            if ($stage->stage_type_id == StageTypesEnum::EXCLUSIVE_TRIBUNE) {
                $validExclusiveTribuneStage = false;
                if (Auth::user() || $userId) {
                    $userId = Auth::user() ? Auth::user()->id : $userId;
                    $stageUser = DB::table('match_event_stages')
                        ->leftJoin('match_event_stage_tags', 'match_event_stage_tags.match_event_stage_id', '=', 'match_event_stages.id')
                        ->leftJoin('user_tags', 'user_tags.tag_id', '=', 'match_event_stage_tags.tag_id')
                        ->leftjoin('tags', function ($join) {
                            $join->on('tags.id', '=', 'user_tags.tag_id')->where('tags.active', 1);
                        })
                        ->where('match_event_stages.id', $stage->id)
                        ->where(function ($q) use ($userId) {
                            $q->where('user_tags.user_id', $userId)->orWhereNull('match_event_stage_tags.id');
                        })->count();
                    if ($stageUser) {
                        $validExclusiveTribuneStage = true;
                    }
                }
                if (!$validExclusiveTribuneStage) {
                    $this->responseCapacityZone = response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "salableCapacityZone", "m" => __('messages.error_validation_10'), "data" => null));
                    return false;
                }
            }
        }

        if ($salable_capacity == 0 || !$zoneActive) {
            $this->responseCapacityZone = response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "salableCapacityZone", "m" => __('messages.error_validation_10'), "data" => null));
            return false;
        }
        $tickets = Ticket::where('match_event_id', $event_id)
            ->whereHas('seat', function (Builder $query) use ($zone_id) {
                $query->where('zone_id', $zone_id)->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED]);
            })->count();
        $blocks = TicketUserBlock::where('match_event_id', $event_id)
            ->whereHas('seat', function (Builder $query) use ($zone_id) {
                $query->where('zone_id', $zone_id);
            })->count();

        if ($tickets + $blocks >= $salable_capacity) {
            $this->responseCapacityZone = response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "salableCapacityZone", "m" => __('messages.error_validation_8'), "data" => null));
            return false;
        }

        if ($currentTickets !== 0 && $currentTickets + $tickets + $blocks > $salable_capacity) {
            $available = $salable_capacity - ($tickets + $blocks);
            $this->responseCapacityZone = response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "salableCapacityZone", "m" => __('messages.error_validation_11', ['number' => $available]), "data" => null));
            return false;
        }

        return true;
    }

    // Retorna la suma actual de bloqueos y tickets que tiene un usuario para un evento
    public function getSumBlocksAndTicketsByUser($ticket_type_id, $user_id, $event_id)
    {
        $countTickets = Ticket::where([['ticket_type_id', $ticket_type_id], ['match_event_id', $event_id], ['user_id', $user_id]])->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])->count();
        $countBlocks = TicketUserBlock::where([['ticket_type_id', $ticket_type_id], ['match_event_id', $event_id], ['user_id', $user_id], ['is_social_distancing', false]])->count();
        return $countTickets + $countBlocks;
    }

    public function getSumTicketsByUserFlashConfiguration($match_event_id, $user_id)
    {
        $availableTickets = FlashTicketConfiguration::select('flash_ticket_configuration.zone_id', 'flash_ticket_configuration.id', DB::raw('flash_ticket_configuration.maximum_number_ballots - COUNT(ob1.id) AS available_tickets'))
            ->leftJoin(
                DB::raw('(SELECT t.id, zones.zone_id FROM tickets t JOIN seats ON t.seat_id = seats.id JOIN zones ON zones.id = seats.zone_id WHERE t.user_id = ' . $user_id . ' AND t.match_event_id = ' . $match_event_id . ' AND ticket_status_id IN (' . TicketStatusEnum::PURCHASED . ', ' . TicketStatusEnum::CREATED . ') AND t.ticket_type_id != ' . TicketTypesEnum::COMPLIMENTARY . ') as ob1'),
                function ($join) {
                    $join->on('ob1.zone_id', '=', 'flash_ticket_configuration.zone_id');
                }
            )
            ->where('flash_ticket_configuration.match_event_id', '=', $match_event_id)
            ->where('flash_ticket_configuration.active', 1)
            ->groupBy('flash_ticket_configuration.zone_id', 'flash_ticket_configuration.id', 'flash_ticket_configuration.maximum_number_ballots')
            ->get();

        return $availableTickets;
    }

    public function validateSell($zone_id, $event_id, $seat_id, $user_id, $ticket_type_id, $ticket_main_id, $type_process, $price, $pin = false, $is_transaction = false)
    {
        if ($is_transaction) {
            DB::beginTransaction();
        }
        try {
            // se valida la capacidad de la localidad no este superada
            if (!$this->salableCapacityZone($zone_id, $event_id, 0, $user_id)) {
                return $this->responseCapacityZone;
            }

            // se consulta y valida si existe un ticket o un bloqueo para esa silla
            $ticket_current = $this->existsTicket($seat_id, $event_id, $user_id);
            $ticket_block = $this->existsBlock($seat_id, $event_id, $user_id);

            if ($ticket_current) {
                $seat = $this->infoSeat($seat_id);
                $name_seat = "";
                if ($seat) {
                    $name_seat = $seat->letter->name . $seat->code;
                }
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "validateSell", "m" => __('messages.error_validation_3', ['seat' => $name_seat]), "data" => null));
            }

            if ($ticket_block) {
                $seat = $this->infoSeat($seat_id);
                $name_seat = "";
                if ($seat) {
                    $name_seat = $seat->letter->name . $seat->code;
                }
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "validateSell", "m" => __('messages.error_validation_4', ['seat' => $name_seat]), "data" => null));
            }

            // si esta activo la logica de compra con distanciamiento social
            if ($this->parameters->is_social_distancing) {
                // buscamos los vecinos de la silla origen, para validar si pueden ser bloqueadas
                $list_block_distancing = $this->searchNeighbour($seat_id, $zone_id);
                foreach ($list_block_distancing as $item) {
                    $current_block = $this->existsBlock($item, $event_id, $user_id);
                    $current_ticket = $this->existsTicket($item, $event_id, $user_id);
                    if ($current_block || $current_ticket) {
                        $seat = $this->infoSeat($seat_id);
                        $name_seat = "";
                        if ($seat) {
                            $name_seat = $seat->letter->name . $seat->code;
                        }
                        return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "validateSell", "m" => __('messages.error_validation_9', ['seat' => $name_seat]), "data" => $item));
                        break;
                    }
                }
            }

            if ($type_process == "ticket") {
                $transaction = $this->createTicket(
                    [
                        'seat_id' =>  $seat_id,
                        'match_event_id' => $event_id,
                        'user_id' => $user_id,
                        'ticket_type_id' => $ticket_type_id,
                        'ticket_main_id' => $ticket_main_id,
                        'price' => $price
                    ]
                );
                if ($this->parameters->is_social_distancing) {
                    $this->validateBlockDistancing($ticket_main_id);
                }
                if ($is_transaction) {
                    if ($transaction["r"]) {
                        DB::commit();
                    } else {
                        DB::rollback();
                    }
                }
                return response($transaction);
            } else {
                $transaction = $this->createBlockTicket($seat_id, $event_id, $user_id, $ticket_type_id, $ticket_main_id, $zone_id, $pin, false, $price);
                if ($this->parameters->is_social_distancing) {
                    // se realiza el bloqueo de las sillas vecinas por distanciamiento
                    foreach ($list_block_distancing as $item) {
                        // se consulta si la silla vecina actual en el ciclo es una silla de las que se va a comprar, para no realizar el bloqueo
                        $is_buy_seat = TicketUserBlock::where([['seat_id', $item], ['user_id', $user_id], ['match_event_id', $event_id], ['is_social_distancing', false]])->first();
                        if (!$is_buy_seat) {
                            $this->createBlockTicket($item, $event_id, $user_id, $ticket_type_id, $ticket_main_id, $zone_id, $pin, true, $price);
                        }
                    }
                    // se elimina cualquier bloqueo de la silla a comprar si es del mismo usuario y tiene bloqueo por distanciamiento
                    $list_distancing = TicketUserBlock::where([
                        ['seat_id', $seat_id],
                        ['user_id', $user_id],
                        ['match_event_id', $event_id],
                        ['is_social_distancing', true]
                    ])->get();
                    foreach ($list_distancing as $d_seat) {
                        $d_seat->delete();
                    }
                }
                if ($is_transaction) {
                    if ($transaction["r"]) {
                        DB::commit();
                    } else {
                        DB::rollback();
                    }
                }
                return response($transaction);
            }
        } catch (\Throwable $th) {
            if ($is_transaction) {
                DB::rollback();
            }
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "validateSell", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function createBlock(Request $request, $origin)
    {
        DB::beginTransaction();
        try {
            // se valida la capacidad de la localidad no este superada
            if (!$this->salableCapacityZone($request->input('tickets')[0]["seat"]["zone_id"], $request->input('tickets')[0]["match_event_id"], count($request->input('tickets')))) {
                DB::rollback();
                return $this->responseCapacityZone;
            }

            $userController = new UserController($request);
            $user = $userController->searchUser($request->document, $request->email, $request->first_name, $request->last_name, $request->phone);
            if (!$user) {
                $current_user = $userController->createClient($request, $is_ticket = true, $validateByDocument = true);
                if ($current_user["r"]) {
                    $user = $current_user["d"];
                } else {
                    DB::rollback();
                    return response($current_user);
                }
            }
            $user_id = $user->id;

            $sumTicketsBlocks = $this->getSumBlocksAndTicketsByUser($request->input('ticket_type_id'), $user_id, $request->input('tickets')[0]["match_event_id"]) + count($request->input('tickets'));
            $flashController = new FlashTicketController;
            $matchEventsController = new MatchEventsController;
            $maximum = !$matchEventsController->validateSaleByCapacity($request->input('tickets')[0]["match_event_id"]) ? $this->parameters->maximum_number_ballots : $flashController->getMaximumTicketsToBuy($request->input('tickets')[0]["match_event_id"]);
            // Valida el numero maximo de boletas que puede comprar el usuario.
            if ($request->input('ticket_type_id') == 1 && $sumTicketsBlocks > $maximum) {
                DB::rollback();
                $available = $maximum - ($sumTicketsBlocks - count($request->input('tickets')));
                if ($available < 0) $available = 0;
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "createBlock", "m" => __('messages.error_validation_5', ['number' => $available]), "data" => null));
            }

            // Valida el numero máximo de abonos.
            if ($request->input('ticket_type_id') == TicketTypesEnum::SUBSCRIBER && $sumTicketsBlocks > $this->parameters->maximum_number_suscription) {
                DB::rollback();
                $available = $this->parameters->maximum_number_suscription - ($sumTicketsBlocks - count($request->input('tickets')));
                if ($available < 0) $available = 0;
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "createBlock", "m" => __('messages.error_validation_6', ['number' => $available]), "data" => null));
            }

            $pin = null;
            $pin_tercero = null;
            $pin_internal = null;
            if ($origin == 'external') {
                $pin_tercero = $this->generatepin();
                $pin = $pin_tercero;
            }

            if ($origin == 'internal') {
                $pin_internal = $this->generatepin();
                $pin = $pin_internal;
            }
            $seller_id = null;
            if (Auth::user()->rol_id != 4) {
                $seller_id = Auth::user()->id;
            }
            $subtotal = $request->input('subtotal') ?? 0;
            $serviceCharge = $request->input('serviceCharge') ?? 0;
            $total = $request->input('amount') ?? $request->input('total') ?? 0;

            $main = TicketMain::create([
                'subtotal'          => $subtotal,
                'service_charge'    => $serviceCharge,
                'total'             => $total,
                'pin_internal'      => $pin_internal,
                'pin_tercero'       => $pin_tercero,
                'user_id_log'       => $user_id,
                'seller_user_id'    => $seller_id,
                'origin'            => 'web',
            ]);

            $log_tickets_main = "";

            if ($request->input('ticket_type_id') != TicketTypesEnum::SUBSCRIBER) {
                foreach ($request->input('tickets') as $ticket) {
                    $zone_id    = $ticket["seat"]["zone_id"];
                    $event_id   = $ticket["match_event_id"];
                    $seat_id    = $ticket["seat"]["id"];

                    $log_tickets_main = $log_tickets_main . "zone: " . $zone_id . "event: " . $event_id . "seat: " . $seat_id . "\n";

                    // creamos los bloqueos
                    $data = $this->validateSell($zone_id, $event_id, $seat_id, $user_id, $ticket["ticket_type_id"], $main->id, $request->input('type_process'), 0, $pin);
                    $response = json_decode($data->getContent());
                    if (!$response->r) {
                        DB::rollback();
                        return $data;
                        break;
                    }
                }
            } else {
                $log_tickets_main = 'Abonado, user_id: ' . $user_id;
                $listEvents = $this->getEventsSubscription($request->input('season_id'), $request->input('match_event_id'));
                if ($listEvents && count($listEvents) > 0) {
                    foreach ($request->input('tickets') as $ticket) {
                        foreach ($listEvents as $event) {
                            $zone_id    = $ticket["seat"]["zone_id"];
                            $event_id   = $event->id;
                            $seat_id    = $ticket["seat"]["id"];

                            if (isset($ticket["dataTicket"]) && !$ticket["dataTicket"]["checkedCtrl"]) {
                                if (!$user_id) {
                                    $user = $userController->searchUser($ticket["dataTicket"]["document"], $ticket["dataTicket"]["email_user"], $ticket["dataTicket"]["first_name"], $ticket["dataTicket"]["last_name"], $ticket["dataTicket"]["phone"], true);
                                    if (!$user) {
                                        $custom_request = new Request([
                                            'first_name'    => $ticket["dataTicket"]["first_name"],
                                            'last_name'     => $ticket["dataTicket"]["last_name"],
                                            'phone'         => $ticket["dataTicket"]["phone"],
                                            'email'         => $ticket["dataTicket"]["email_user"],
                                            'password'      => $ticket["dataTicket"]["phone"] + $ticket["dataTicket"]["document"],
                                            'document'      => $ticket["dataTicket"]["document"],
                                        ]);
                                        $current_user = $userController->createClient($custom_request, $is_ticket = true, $validateByDocument = true);
                                        if ($current_user["r"]) {
                                            $user = $current_user["d"];
                                            $user_id = $user->id;
                                        } else {
                                            DB::rollback();
                                            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "validateUserByTicket", "m" => __('messages.error_global'), "data" => $current_user));
                                            break;
                                        }
                                    }
                                }
                                $ticket["dataTicket"]["checkedCtrl"] = true;
                            }

                            // creamos los bloqueos
                            $data = $this->validateSell($zone_id, $event_id, $seat_id, $user_id, $ticket["ticket_type_id"], $main->id, $request->input('type_process'), 0, $pin);
                            $response = json_decode($data->getContent());
                            if (!$response->r) {
                                DB::rollback();
                                return $data;
                                break;
                            }
                        }
                    }
                }
            }

            $main->comment_purchase_log = $log_tickets_main;
            $main->update();

            DB::commit();
            return $data;
        } catch (\Throwable $th) {
            DB::rollback();
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "createBlock", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function getMatchEventsSuscription(Request $request)
    {
        try {
            $list_match_events = $this->getEventsSubscription($request->input('season_id'), $request->input('match_event_id'));
            $team_main = Team::where([['is_main', true], ['active', true]])->first();
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => array('list_match_events' => $list_match_events, 'team_main' => $team_main)));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "getMatchEventsSuscription", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    /*
        @tickets Type TicketUserBlock listado de bloqueos.
        @ticket_main_id Type int id de la cabecera de ticketes.
    */
    public function generateTickets($tickets, $ticket_main_id, $isBackup = false)
    {
        DB::beginTransaction();
        try {
            // Validar reserva de abonos para fijar que ya estan pagos y tiene asociados los tiquetes
            $parameters = Parameter::select('presuscription', 'web_presuscription')->first();
            if ($parameters->presuscription || $parameters->web_presuscription) {
                $seats = $tickets->where('ticket_type_id', TicketTypesEnum::SUBSCRIBER)->pluck('seat_id');
                if (count($seats) > 0) {
                    try {
                        $user = User::where('id', $tickets[0]->user_id)->first();
                        PreSubscriber::where('payment', false)->where('email', $user->email)->whereIn('seat_id', $seats)->update(['payment' => true]);
                        Mail::to($user->email)->send(new NewSuscriptorMail($user->first_name . " " . $user->last_name));
                    } catch (\Exception $e) {
                        $error = [
                            'tickets'               => $tickets,
                            'ticket_main_id'        => $ticket_main_id,
                            'isBackup'              => $isBackup,
                            'message'               => $e->getMessage(),
                            'getFile'               => $e->getFile(),
                            'getLine'               => $e->getLine(),
                        ];
                        $this->util->logFile(json_encode($error), 'sendListMail');
                    }
                }
            }

            $data = response(array("r" => false, "type" => "", "title" => "", "m" => "No se ha podido generar las boletas.", "data" => ""));
            foreach ($tickets as $key => $t) {
                // eliminamos el bloqueo.
                if (!$isBackup) {
                    $this->deleteBlock($t->seat_id, $t->match_event_id, $t->user_id);
                } else {
                    $this->deleteBlockBackup($t->seat_id, $t->match_event_id, $t->user_id);
                }

                // Validamos la silla y creamos el ticket
                $data = $this->validateSell($t->zone_id, $t->match_event_id, $t->seat_id, $t->user_id, $t->ticket_type_id, $ticket_main_id, 'ticket', $t->price);
                $response = json_decode($data->getContent());
                if (!$response->r) {
                    if ($isBackup) {
                        // Validar si hay alguna silla disponible, caso contrario hacer ROLLBACK
                        $dataOptional = $this->validateOptionalSeatForSell($t);
                        $responseOptional = json_decode($dataOptional->getContent());
                        if ($responseOptional->r) {
                            $data = $dataOptional;
                            continue;
                        }
                        DB::rollback();
                        return $data;
                        break;
                    }
                    DB::rollback();
                    return false;
                    break;
                }
            }
            DB::commit();

            $this->dispatchTicketProcesses($ticket_main_id);

            if ($isBackup) {
                return $data;
            }
            return true;
        } catch (\Throwable $th) {
            DB::rollback();
            return false;
        }
    }

    public function createLogTicket($state_id, $ticket_id)
    {
        try {
            $ticketLog = TicketLog::create(['ticket_id' => $ticket_id, 'ticket_status_id' => $state_id]);
            if (Auth::user()) {
                $this->registerLog(Auth::user()->id, 'Actualizó estado boleta', json_encode($ticketLog), "Update", 'Boleteria');
            }
            return response(array("r" => true, "type" => "success", "title" => "", "m" => "", "data" => null));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "createLogTicket", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function changeStateTicket(Request $request)
    {
        try {
            if ($request->state_id != 3 && $request->state_id != 4) {
                return response(array("r" => false, "type" => "error", "title" => "Oops...", "m" => __('messages.state_invalid'), "data" => null));
            }

            $ticket = Ticket::where('id', $request->ticket_id)->with('seat')->first();

            if ($ticket->update(['ticket_status_id' => $request->state_id])) {
                $this->createLogTicket($request->state_id, $request->ticket_id);
            }
            return response(array("r" => true, "type" => "success", "title" => "Ok", "m" => __('messages.updated_successfully'), "data" => null));
        } catch (\Throwable $th) {
            return response(array("r" => false, "type" => "error", "title" => "Oops...", "m" => __('messages.error_global'), "data" => $th->getMessage()));
        }
    }

    public function massBallotStatusChange(Request $request)
    {
        try {
            if (!$request->hasFile('archivo') || !$request->file('archivo')->isValid()) {
                return ['r' => false, 'm' => 'Archivo inválido o no recibido.'];
            }

            ini_set('memory_limit', '2048M');
            $file = new CancelTicketsImport;
            $file->request = $request;
            Excel::import($file, $request->archivo);
            return response(array("r" => true, 'd' => $file->answer, "m" => __('messages.match_event_tickets.title_24'), "data" => null));
        } catch (\Exception $e) {
            return response(array('r' => false, 'd' => null, 'm' => trans('messages.match_event_tickets.title_25') . $request->name_file . "  " . $e->getMessage()));
        }
    }

    /**
     * Update the specified resource in storage.
     *
     */
    public function update(Request $request)
    {
        $user = User::find($request["user_id"]);
        $user->first_name = $request["first_name"];
        $user->last_name = $request["last_name"];
        $user->document = $request["document"];
        $user->phone = $request["phone"];
        $user->email = $request["email"];
        $user->update();

        if ($user) {
            return array('r' => true, 'd' => array('id' => $user->id), 'm' => trans('messages.updated_successfully'));
        } else {
            return array('r' => false, 'd' => null, 'm' => trans('messages.error_updating'));
        }
    }

    public function toUpdateUsersWithTickets(Request $request)
    {
        $results = Ticket::where([
            'match_event_id' => $request->id_event,
            'user_id' => $request->userIdError,
            'code_ticket' => $request->id_code,
        ])->update(['user_id' => $request['usertIdValid']]);
        if ($results) {
            return array('r' => true, 'd' => array('id' => 1), 'm' => trans('messages.updated_successfully'));
        } else {
            return array('r' => false, 'd' => null, 'm' => trans('messages.error_updating'));
        }
    }

    public function sendSingleEmailTicket($userId, $code)
    {
        $user = User::find($userId);
        try {
            Mail::to($user->email)->send(new TicketPurchaseMail($user, $code));
            $this->updateSentEmailIndicatorInTicket($code);
            return array('r' => true, 'm' => 'Mail enviado');
        } catch (\Exception $err) {
            $log = array(
                'error'         => $err->getMessage(),
                'user'          => $user,
                'code'          => $code
            );
            $this->util->logFile(json_encode($log), 'sendSingleEmailTicket');
            return array('r' => false, 'm' => 'Mail no enviado');
        }
    }

    public function sendEmailMultipleTickets($userId, $ticketsToSendByMail, $ticketMainId, $matchEventId)
    {
        $user = User::find($userId);
        try {
            Mail::to($user->email)->send(new TicketPurchaseEmailList($ticketsToSendByMail, $ticketMainId, $matchEventId, $user));
            $this->updateSentEmailIndicatorInTickets($ticketsToSendByMail);
            return array('r' => true, 'm' => 'Mail enviado');
        } catch (\Exception $err) {
            $log = array(
                'error'                     => $err->getMessage(),
                'user'                      => $user,
                'ticketsToSendByMail'       => $ticketsToSendByMail,
                'ticket_main'               => $ticketMainId,
                'match_event'               => $matchEventId
            );
            $this->util->logFile(json_encode($log), 'sendEmailMultipleTickets');
            return array('r' => false, 'm' => 'Mail no enviado');
        }
    }

    public function sendEmailMultipleLinksTickets($userId, $ticketsToSendByMail, $ticketTypeId, $matchEventId)
    {
        $user = User::find($userId);
        try {
            Mail::to($user->email)->send(new TicketPurchaseEmailListMultiple($ticketsToSendByMail, $ticketTypeId, $matchEventId, $user));
            $this->updateSentEmailIndicatorInTickets($ticketsToSendByMail);
            return array('r' => true, 'm' => 'Mail enviado');
        } catch (\Exception $err) {
            $log = array(
                'error'                     => $err->getMessage(),
                'user'                      => $user,
                'ticketsToSendByMail'       => $ticketsToSendByMail,
                'ticket_type'               => $ticketTypeId,
                'match_event'               => $matchEventId
            );
            $this->util->logFile(json_encode($log), 'sendEmailMultipleLinksTickets');
            return array('r' => false, 'm' => 'Mail no enviado');
        }
    }

    private function updateSentEmailIndicatorInTicket($codeTicket)
    {
        $ticket = Ticket::where('code_ticket', $codeTicket)->first();
        if (!$ticket || $ticket->is_an_email_sent == 1) {
            return;
        }
        $ticket->is_an_email_sent = 1;
        $ticket->update();
    }

    private function updateSentEmailIndicatorInTickets($tickets)
    {
        foreach ($tickets as $ticket) {
            $this->updateSentEmailIndicatorInTicket($ticket->code_ticket);
        }
    }

    public function updateTicketNotification($ticketMain, $ticketNotification)
    {
        if (!$ticketMain || !$ticketNotification) {
            return;
        }
        $ticketMain->ticket_notification = $ticketNotification;
        $ticketMain->update();
    }

    public function isCompletedTicketNotification($ticketMain)
    {
        return in_array($ticketMain->ticket_notification, [TicketNotificationEnum::COMPLETED, TicketNotificationEnum::NOTIFICATION_COMPLETED, TicketNotificationEnum::BILLING_COMPLETED]);
    }

    public function validateMails()
    {
        $ticketMains = DB::table('tickets as t')
            ->select(
                'tm.id'
            )
            ->join('ticket_mains as tm', 'tm.id', '=', 't.ticket_main_id')
            ->join('match_events as me', 'me.id', '=', 't.match_event_id')
            ->where(function ($query) {
                $query->where('t.is_an_email_sent', 0)
                    ->orWhere(function ($query1) {
                        $query1->where('tm.ticket_notification', '=', TicketNotificationEnum::PENDING)->whereNull('tm.cufe');
                    });
            })
            ->whereIn('t.ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
            ->where('me.event_end_sale', '>', DB::raw("CONVERT_TZ(NOW(), 'system', 'America/Bogota')"))
            ->where('t.created_at', '>', DB::raw("DATE_SUB(CONVERT_TZ(NOW(), 'system', 'America/Bogota'), INTERVAL 24 HOUR)"))
            ->groupBy('tm.id')
            ->get();

        if (count($ticketMains) == 0) {
            return array(
                'r' => false,
                'm' => 'No se encontraron transacciones pendientes de validacion de procesos.'
            );
        }

        foreach ($ticketMains as $ticketMain) {
            $this->dispatchTicketProcesses($ticketMain->id);
        }

        return array(
            'r' => true,
            'm' => 'Se validaron ' . count($ticketMains) . ' transaciones pendientes de validacion de procesos.'
        );
    }

    public function sendMassSmsNotifications($userId, $code)
    {
        try {
            $dataUser = User::select('id', 'first_name', 'phone')->find($userId);
            event(new SmsNotificationEvent($dataUser, $code));
            return array('r' => true, 'm' => trans('SMS enviado'));
        } catch (\Exception $e) {
            return array('r' => false, 'm' => trans('SMS no enviado'));
        }
    }

    public function getPin($url_key)
    {
        $corporateIdentity = CorporateIdentity::first();
        return view("tickets.getPin", compact('url_key', 'corporateIdentity'));
    }

    public function getAttachmentFromPublic(Request $request)
    {
        $decrypted  = "";
        $url_key    = $request->url_key;
        $key        = $request->key;
        if (!$key) {
            return array('Debes ingresar el pin enviado a tu correo');
        }

        try {
            $decrypted = Crypt::decryptString($url_key);
        } catch (\Exception $exx) {
            return array('Error ' . $exx->getMessage());
        }

        if (!$decrypted) {
            return array('Error de descifrado');
        }

        $decrypted = explode('|', $decrypted);

        if ($decrypted[0] != $key) {
            return array('Pin no válido. Revisa el pin enviado a tu correo');
        }

        if ($decrypted[3] == 'lista') {
            $user_id        = $decrypted[1];
            $match_event_id = $decrypted[2];
            $ticket_type_id = $decrypted[4];

            $tickets = Ticket::select('tickets.*')
                ->where('user_id', $user_id)
                ->where('match_event_id', $match_event_id)
                ->where('ticket_type_id', $ticket_type_id)
                ->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
                ->get();
            return $this->downloadZipTickets($tickets, $user_id, $match_event_id);
        }

        if ($decrypted[3] == 'cortesia') {
            $user_id = $decrypted[1];
            $match_event_id = $decrypted[2];

            $tickets = Ticket::select('tickets.*')
                ->where('user_id', $user_id)
                ->where('match_event_id', $match_event_id)
                ->where('ticket_type_id', TicketTypesEnum::COMPLIMENTARY)
                ->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
                ->get();
            return $this->downloadZipTickets($tickets, $user_id, $match_event_id);
        }

        if ($decrypted[3] == 'ticket') {
            $code = $decrypted[2];
            return $this->printTicket($code);
        }
    }

    public function downloadTicketForUser(Request $request)
    {
        $decrypted  = "";
        $data = $request->data;
        try {
            $decrypted = Crypt::decryptString($data);
        } catch (\Exception $exx) {
            return array('Error de peticion, detalle: ' . $exx->getMessage());
        }
        if (!$decrypted) {
            return array('Error de peticion, detalle: ' . 'Error de descifrado');
        }

        if (str_contains($decrypted, 'type=pdf')) {
            if (str_contains($decrypted, 'codes=')) {
                parse_str($decrypted, $params);
                $codes = $params['codes'] ?? null;
                if (!$codes) {
                    return array('No se encontraron tickets');
                }

                return $this->printTickets($codes);
            } else {
                parse_str($decrypted, $params);
                $userId = $params['user_id'] ?? null;
                $matchEventId = $params['match_event_id'] ?? null;
                $ticketMainId = $params['ticket_main_id'] ?? null;

                $tickets = Ticket::select('tickets.code_ticket')
                    ->where('user_id', $userId)
                    ->where('match_event_id', $matchEventId)
                    ->where('ticket_main_id', $ticketMainId)
                    ->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
                    ->pluck('code_ticket')
                    ->toArray();
                if (!count($tickets)) {
                    return array('No se encontraron tickets');
                }

                $codes = implode(',', $tickets);
                return $this->printTickets($codes);
            }
        } else if (str_contains($decrypted, 'type=zip')) {
            if (str_contains($decrypted, 'codes=')) {
                parse_str($decrypted, $params);
                $codes = $params['codes'] ?? null;
                $tickets = Ticket::select('tickets.*')
                    ->whereIn('code_ticket', explode(',', $codes))
                    ->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
                    ->get();
                if (!count($tickets)) {
                    return array('No se encontraron tickets');
                }

                return $this->downloadZipTickets($tickets, $tickets->first()->user_id, $tickets->first()->match_event_id);
            } else {
                parse_str($decrypted, $params);
                $userId = $params['user_id'] ?? null;
                $matchEventId = $params['match_event_id'] ?? null;
                $ticketMainId = $params['ticket_main_id'] ?? null;

                $tickets = Ticket::select('tickets.*')
                    ->where('user_id', $userId)
                    ->where('match_event_id', $matchEventId)
                    ->where('ticket_main_id', $ticketMainId)
                    ->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
                    ->get();
                if (!count($tickets)) {
                    return array('No se encontraron tickets');
                }

                return $this->downloadZipTickets($tickets, $userId, $matchEventId);
            }
        } else if (str_contains($decrypted, ',')) {
            return $this->printTickets($decrypted);
        } else {
            return $this->printTicket($decrypted);
        }
    }

    public function printTicket($code, $type = "base64")
    {
        $printTicketController = new PrintTicketController;
        return $printTicketController->printTicketForMassMail($code, $type);
    }


    public function printTickets($codes)
    {
        $printTicketController = new PrintTicketController;
        return $printTicketController->printTickets($codes);
    }

    public function viewTicket($code)
    {
        return $this->printTicket($code);
    }

    public function viewTickets($tickets)
    {
        return $this->printTickets($tickets);
    }

    public function downloadZipTickets($tickets, $user_id, $match_event_id, $fileName = "")
    {
        $codes = $tickets->pluck('code_ticket')->toArray();
        return $this->renderTicket(implode(',', $codes), 'file');
    }

    public function getPinMultiple($url_key)
    {
        $corporateIdentity = CorporateIdentity::first();
        return view("tickets.getPinMultiple", compact('url_key', 'corporateIdentity'));
    }

    function countTicketsAndGetLinks(Request $request)
    {
        $decrypted = "";
        $url_key  = $request->url_key;
        $key = $request->key;
        if (!$key) {
            return array('Debes ingresar el pin enviado a tu correo');
        }

        try {
            $decrypted = Crypt::decryptString($url_key);
        } catch (\Exception $exx) {
            return array('Error ' . $exx->getMessage());
        }

        if (!$decrypted) {
            return array('Error de descifrado');
        }

        $decrypted = explode('|', $decrypted);

        if ($decrypted[0] != $key) {
            return array('Pin no válido. Revisa el pin enviado a tu correo');
        }

        if ($decrypted[3] == 'multiple') {
            $user_id = $decrypted[1];
            $match_event_id = $decrypted[2];
            $ticket_type_id = $decrypted[4];

            $user = User::find($user_id);
            $match = MatchEvent::find($match_event_id);
            $ticket_type = TicketType::find($ticket_type_id);

            if (!$user) {
                return array('Error' => 'Revise datos usuario');
            }

            if (!$match) {
                return array('Error' => 'Revise datos evento');
            }

            if (!$ticket_type) {
                return array('Error' => 'Revise datos tipo ticket');
            }

            $total = Ticket::select('id', 'code_ticket', 'user_id')
                ->where('user_id', $user_id)
                ->where('match_event_id', $match_event_id)
                ->where('ticket_type_id', $ticket_type_id)
                ->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
                ->count();

            $limitPerPage = 100;
            $pages = ceil($total /  $limitPerPage);
            $skip = 0;

            $arrayLinks = array();
            for ($i = 0; $i < $pages; $i++) {
                $arrayLinks[] = "/download_ticket_for_user/links/$user_id/$match_event_id/$ticket_type_id/$limitPerPage/$skip";
                $skip = $skip + $limitPerPage;
            }

            return view('tickets.links')
                ->with('total', $total)
                ->with('links', $arrayLinks)
                ->with('user', $user)
                ->with('match', $match)
                ->with('ticket_type', $ticket_type);
        }
        return array('Error');
    }

    function downloadLinks($user_id, $match_event_id, $ticket_type_id, $take, $skip)
    {
        $tickets = Ticket::select('id', 'code_ticket', 'user_id')
            ->where('user_id', $user_id)
            ->where('match_event_id', $match_event_id)
            ->where('ticket_type_id', $ticket_type_id)
            ->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
            ->skip($skip)
            ->take($take)
            ->get();
        return $this->downloadZipTickets($tickets, $user_id, $match_event_id, (($skip / 100) + 1));
    }

    function validateDownloadPanelTickets($email, $match_event_id, $from_date = null, $to_date = null, $type = null)
    {
        $user = User::select('id')->where('email', $email)->first();
        if (!$user) {
            $error_message = "No se ha encontrado usuario para este mail.";
            return response()->json(['success' => false, 'message' => $error_message]);
        }
        if ($from_date && is_numeric($from_date)) {
            $type = $from_date;
            $from_date = null;
        }
        $tickets = DB::table('tickets')
            ->select(['tickets.id', 'tickets.code_ticket', 'tickets.user_id'])
            ->where('tickets.user_id', $user->id)
            ->where('tickets.match_event_id', $match_event_id)
            ->whereIn('tickets.ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
            ->where(function ($query) use ($from_date, $to_date, $type) {
                if ($from_date && $to_date) {
                    $query->whereBetween('tickets.created_at', [$from_date, $to_date]);
                }
                if ($type) {
                    $query->where('tickets.ticket_type_id', $type);
                }
            })
            ->count();
        if ($tickets == 0) {
            return response()->json(['success' => false, 'message' => 'No existen boletas a generar para el usuario']);
        }
        return response()->json(['success' => true, 'message' => 'Validación OK', 'data' => $tickets]);
    }

    function downloadPanelTickets($email, $match_event_id, $from_date = null, $to_date = null, $type = null)
    {
        $user = User::select('id')->where('email', $email)->first();
        if ($from_date && is_numeric($from_date)) {
            $type = $from_date;
            $from_date = null;
        }
        $tickets = DB::table('tickets')
            ->select(['tickets.id', 'tickets.code_ticket', 'tickets.user_id'])
            ->where('tickets.user_id', $user->id)
            ->where('tickets.match_event_id', $match_event_id)
            ->whereIn('tickets.ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
            ->where(function ($query) use ($from_date, $to_date, $type) {
                if ($from_date && $to_date) {
                    $query->whereBetween('tickets.created_at', [$from_date, $to_date]);
                }
                if ($type) {
                    $query->where('tickets.ticket_type_id', $type);
                }
            })
            ->get();
        $fecha = new DateTime();
        return $this->downloadZipTickets($tickets, $user->id, $match_event_id, $fecha->getTimestamp());
    }

    public function deleteTicketTemplate()
    {
        return Excel::download(new CancelTicketsTemplate, trans('messages.match_event_tickets.title_22') . '.xlsx');
    }

    public function ticketTypeName($ticket)
    {
        if ($ticket->ticket_type_id != TicketTypesEnum::COMPLIMENTARY) {
            return 'Boleta';
        } else {
            return 'Cortesia';
        }
    }

    public function ticketSeatLocationFullText($ticket)
    {
        $seat = '';
        if ($ticket) {
            // Construir array con los partes del nombre
            $parts = [
                $ticket->seat->zone->zone->name,
                $ticket->seat->zone->name,
                $ticket->seat->letter->name . $ticket->seat->code
            ];

            // Eliminar duplicados
            $uniqueParts = [];
            foreach ($parts as $part) {
                if (!in_array($part, $uniqueParts)) {
                    $uniqueParts[] = $part;
                }
            }

            // Unir con separador
            $seat = implode(' - ', $uniqueParts);
        }
        return $seat;
    }

    public function validateOptionalSeatForSell($ticket)
    {
        $mainZone = null;
        if ($ticket->seat && $ticket->seat->zone)
            $mainZone = $ticket->seat->zone->zone_id;
        $secondaryZone = $ticket->zone_id;

        $zoneController = new ZonesController();
        $zones = $zoneController->getAvailableZones($mainZone, $secondaryZone, $ticket->match_event_id);
        foreach ($zones as $zone) {
            $massiveFansController = new MassiveFansController();
            $seats = $massiveFansController->getSeatsAvailableFromLocationAndEvent(
                [
                    'zone_id' => $zone,
                    'quantity' => 1,
                    'match_event_id' => $ticket->match_event_id,
                    'validate_rules' => false
                ]
            );
            if (count($seats) > 0) {
                $seat_id = $seats[0]->id;
                $data = $this->validateSell($zone, $ticket->match_event_id, $seat_id, $ticket->user_id, $ticket->ticket_type_id, $ticket->ticket_main_id, 'ticket', $ticket->price);
                $response = json_decode($data->getContent());
                if ($response->r) {
                    return $data;
                }
            }
        }
        return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "validateOptionalSeatForSell", "data" => $ticket));
    }

    public function getPendingMatchesTickets($ticket_id_origin, $tribune_id_final, $zone_id_final, $seat_id_final)
    {
        $userTicket = Ticket::with("match_event:id,season_id")->select("id", "user_id", "match_event_id", "seat_id", "ticket_type_id")->where('id', $ticket_id_origin)->first();
        $pendingTickets = [];

        if ($userTicket->ticket_type_id == TicketTypesEnum::SUBSCRIBER) {
            $pendingTickets = Ticket::select("id", "code_ticket", "seat_id", "match_event_id", "door", "zone", "letter_seat", "code_seat")
                ->with("match_event:id,event_start,date_name,name")
                ->whereHas('match_event', function ($match_event) use ($userTicket) {
                    $match_event->where('event_start', '>=', Carbon::now());
                    $match_event->where('season_id', $userTicket->match_event->season_id);
                })
                ->where('seat_id', $userTicket->seat_id)
                ->where('user_id', $userTicket->user_id)
                ->where('ticket_type_id', TicketTypesEnum::SUBSCRIBER)
                ->get();
        } else {
            $pendingTickets = Ticket::select("id", "code_ticket", "seat_id", "match_event_id", "door", "zone", "letter_seat", "code_seat")
                ->with("match_event:id,date_name,name")
                ->where('id', $userTicket->id)
                ->get();
        }

        return $pendingTickets;
    }

    public function postChangeSeat(Request $request)
    {

        $current_seat = Seat::select('code', 'zone_id', 'letter_id')->with('letter')->where('id', $request->seat_id_final)->first();
        $name_seat = $current_seat->letter->name . $current_seat->code;
        $zone = Zone::select('name', 'door_id')->where('id', $current_seat->zone_id)->first();

        $door_name = null;
        if ($zone && $zone->door_id) {
            $c_q = Door::select('name')->where('id', $zone->door_id)->first();
            if ($c_q) {
                $door_name = $c_q->name;
            }
        }

        $userTicket = Ticket::with("match_event:id,season_id")->select("id", "user_id", "match_event_id", "seat_id", "ticket_type_id")->where('id', $request->ticket_id_origin)->first();

        // Abonados
        if ($userTicket->ticket_type_id == TicketTypesEnum::SUBSCRIBER) {
            $pendingTickets = Ticket::select("id", "code_ticket", "seat_id", "match_event_id", "door", "zone", "letter_seat", "code_seat")->with("match_event:id,event_start,date_name,name")
                ->whereHas('match_event', function ($match_event) use ($userTicket) {
                    $match_event->where('event_start', '>=', Carbon::now());
                    $match_event->where('season_id', $userTicket->match_event->season_id);
                })
                ->where('seat_id', $userTicket->seat_id)
                ->where('user_id', $userTicket->user_id)
                ->where('ticket_type_id', TicketTypesEnum::SUBSCRIBER)
                ->get();
        } else {
            $pendingTickets = Ticket::select("id", "code_ticket", "seat_id", "match_event_id", "door", "zone", "letter_seat", "code_seat")
                ->where('id', $userTicket->id)
                ->get();
        }


        try {
            DB::beginTransaction();
            foreach ($pendingTickets as $p) {
                $ticket_current = $this->existsTicket($request->seat_id_final, $p->match_event_id, $userTicket->user_id);
                $ticket_block = $this->existsBlock($request->seat_id_final, $p->match_event_id, $userTicket->user_id);

                if ($ticket_current) {
                    DB::rollback();
                    return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "postChangeSeat", "m" => __('messages.error_validation_3', ['seat' => $name_seat]), "data" => null, 't' => $ticket_current));
                }

                if ($ticket_block) {
                    DB::rollback();
                    return response(array("r" => false, "type" => "error", "title" => "Oops...", "origin" => "postChangeSeat", "m" => __('messages.error_validation_4', ['seat' => $name_seat]), "data" => null, 't' => $ticket_block));
                }

                // Buscar ticket y actualizar.
                $ticketToChange = Ticket::find($p->id);

                $ticketToChange->seat_id = $request->seat_id_final;
                $ticketToChange->zone = $zone->name;
                $ticketToChange->letter_seat = $current_seat->letter->name;
                $ticketToChange->code_seat = $current_seat->code;
                $ticketToChange->door = $door_name;

                $ticketToChange->update();
            }
            DB::commit();
        } catch (\Exception $exx) {
            DB::rollback();
            return array('r' => false, 'm' => $exx->getMessage());
        }


        return array('r' => true, 'm' => 'Proceso exitoso');
    }

    public function getTotalByMatchCode($match_code)
    {
        $m = MatchEvent::select('id', 'name', 'event_start')->where('code', $match_code)->first();

        if (!$m) {
            return array('error' => 'El evento no existe');
        }

        $ticketsVendidos = Ticket::where('match_event_id', $m->id)
            ->where('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
            ->count();

        $ticketsAnulados = Ticket::where('match_event_id', $m->id)
            ->where('ticket_status_id', TicketStatusEnum::CANCELLED)
            ->count();

        return array(
            'Evento' => $m->name,
            'Hora inicio evento' => $m->event_start,
            'Total vendidos - anulados' => $ticketsVendidos,
            'Total anulados' => $ticketsAnulados,
            'Total tickets vendidos + anulados' => ($ticketsVendidos + $ticketsAnulados)
        );
    }

    public function exportMatchEventSeatsTemplate()
    {
        return Excel::download(new MatchEventSeatsTemplate, trans('messages.match_event_tickets.title_31') . '.xlsx');
    }

    public function importMatchEventSeats(Request $request)
    {
        try {
            if (!$request->hasFile('archivo') || !$request->file('archivo')->isValid()) {
                return ['r' => false, 'm' => 'Archivo inválido o no recibido.'];
            }

            ini_set('memory_limit', '2048M');
            $file = new MatchEventSeatsImport($request->matchEventId);
            $file->request = $request;
            Excel::import($file, $request->archivo);
            return array('r' => true, 'd' => $file->answer, 'm' => trans('messages.match_event_tickets.title_33') . ' ' . $file->edit['actualizados'] . ' actualizados.');
        } catch (\Exception $e) {
            return array('r' => false, 'd' => null, 'm' => trans('messages.match_event_tickets.title_34') . $request->name_file . "  " . $e->getMessage());
        }
    }

    public function exportMatchEventSpecialTextTemplate()
    {
        return Excel::download(new MatchEventSpecialTextTemplate, trans('messages.match_event_tickets.title_37') . '.xlsx');
    }

    public function importMatchEventSpecialText(Request $request)
    {
        try {
            if (!$request->hasFile('archivo') || !$request->file('archivo')->isValid()) {
                return ['r' => false, 'm' => 'Archivo inválido o no recibido.'];
            }

            ini_set('memory_limit', '2048M');
            $file = new MatchEventSpecialTextImport($request->matchEventId);
            $file->request = $request;
            Excel::import($file, $request->archivo);
            return array('r' => true, 'd' => $file->answer, 'm' => trans('messages.match_event_tickets.title_33') . ' ' . $file->edit['actualizados'] . ' actualizados.');
        } catch (\Exception $e) {
            return array('r' => false, 'd' => null, 'm' => trans('messages.match_event_tickets.title_34') . $request->name_file . "  " . $e->getMessage());
        }
    }

    public function getSeatFreeByZonesOrSeat($match_event_id, $zones, $seat = null)
    {
        $matchEvent = MatchEvent::with('season')->where('id', $match_event_id)->first();
        $parameters = Parameter::select('presuscription')->first();
        $presubscriptionActive = $parameters->presuscription && $matchEvent->season->is_suscription;

        $freeSeat = null;
        if ($seat) {
            $freeSeat = Seat::with('letter')
                ->where('id', $seat)
                ->whereNotIn('id', function ($query) use ($match_event_id) {
                    $query->select('seat_id')->from('ticket_user_blocks')->where('match_event_id', $match_event_id);
                }) // Sin bloqueos
                ->whereNotIn('id', function ($query) use ($match_event_id) {
                    $query->select('seat_id')->from('tickets')->where('match_event_id', $match_event_id)->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED]);
                }) // Que no este vendida
                ->whereNotIn('id', function ($query) use ($match_event_id) {
                    $query->select('seat_id')->from('match_event_stages')->where('match_event_id', $match_event_id)->where('stage_type_id', StageTypesEnum::BLOCK_SEAT);
                }) // Que no este bloqueada para el evento
                ->when($presubscriptionActive, function ($query) {
                    $query->whereNotIn('id', function ($query) {
                        $query->select('seat_id')->from('pre_subscribers')->where(function ($query1) {
                            $query1->where('payment', 1)->orWhere('is_credit', 1);
                        });
                    });
                }) // Que no este reservada para un abonado
                ->first();
        }
        if (!$freeSeat) {
            $freeSeat = Seat::with('letter')
                ->whereIn('zone_id', $zones)
                ->whereNotIn('id', function ($query) use ($match_event_id) {
                    $query->select('seat_id')->from('ticket_user_blocks')->where('match_event_id', $match_event_id);
                }) // Sin bloqueos
                ->whereNotIn('id', function ($query) use ($match_event_id) {
                    $query->select('seat_id')->from('tickets')->where('match_event_id', $match_event_id)->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED]);
                }) // Que no este vendida
                ->whereNotIn('id', function ($query) use ($match_event_id) {
                    $query->select('seat_id')->from('match_event_stages')->where('match_event_id', $match_event_id)->where('stage_type_id', StageTypesEnum::BLOCK_SEAT);
                }) // Que no este bloqueada para el evento
                ->when($presubscriptionActive, function ($query) {
                    $query->whereNotIn('id', function ($query) {
                        $query->select('seat_id')->from('pre_subscribers')->where(function ($query1) {
                            $query1->where('payment', 1)->orWhere('is_credit', 1);
                        });
                    });
                }) // Que no este reservada para un abonado
                ->first();
        }
        return $freeSeat;
    }

    public function changeFreeSeatToTicket($ticket, $freeSeat, $specialTicket = null)
    {
        $current_seat = Seat::select('code', 'zone_id', 'letter_id')->with('letter')->where('id', $freeSeat)->first();
        $name_seat = $current_seat->letter->name . $current_seat->code;
        $zone = Zone::select('name', 'door_id')->where('id', $current_seat->zone_id)->first();

        $door_name = null;
        if ($zone && $zone->door_id) {
            $c_q = Door::select('name')->where('id', $zone->door_id)->first();
            if ($c_q) {
                $door_name = $c_q->name;
            }
        }

        $userTicket = Ticket::with("match_event:id,season_id")->select("id", "user_id", "match_event_id", "seat_id", "ticket_type_id")->where('id', $ticket)->first();

        $pendingTickets = array();
        // Abonados
        if ($userTicket->ticket_type_id == TicketTypesEnum::SUBSCRIBER) {
            $pendingTickets = Ticket::select("id", "code_ticket", "seat_id", "match_event_id", "door", "zone", "letter_seat", "code_seat")->with("match_event:id,event_start,date_name,name")
                ->whereHas('match_event', function ($match_event) use ($userTicket) {
                    $match_event->where('event_start', '>=', Carbon::now());
                    $match_event->where('season_id', $userTicket->match_event->season_id);
                })
                ->where('seat_id', $userTicket->seat_id)
                ->where('user_id', $userTicket->user_id)
                ->where('ticket_type_id', TicketTypesEnum::SUBSCRIBER)
                ->get();
        } else if ($userTicket->ticket_type_id == TicketTypesEnum::FREE_SALE) {
            $pendingTickets = Ticket::select("id", "code_ticket", "seat_id", "match_event_id", "door", "zone", "letter_seat", "code_seat")
                ->where('id', $userTicket->id)
                ->get();
        }

        if (count($pendingTickets) == 0) {
            $pendingTickets[] = $userTicket;
        }

        try {
            foreach ($pendingTickets as $p) {
                $ticket_current = $this->existsTicket($freeSeat, $p->match_event_id, $userTicket->user_id);
                $ticket_block = $this->existsBlock($freeSeat, $p->match_event_id, $userTicket->user_id);

                if ($ticket_current) {
                    return array("r" => false, "m" => __('messages.error_validation_3', ['seat' => $name_seat]));
                }

                if ($ticket_block) {
                    return array("r" => false, "m" => __('messages.error_validation_4', ['seat' => $name_seat]));
                }

                // Buscar ticket y actualizar.
                $ticketToChange = Ticket::find($p->id);

                $ticketToChange->seat_id = $freeSeat;
                $ticketToChange->zone = $zone->name;
                $ticketToChange->letter_seat = $current_seat->letter->name;
                $ticketToChange->code_seat = $current_seat->code;
                $ticketToChange->door = $door_name;
                if ($specialTicket != null)
                    $ticketToChange->special_text = $specialTicket;

                $ticketToChange->update();
            }
        } catch (\Exception $exx) {
            return array('r' => false, 'm' => $exx->getMessage());
        }

        return array('r' => true, 'm' => 'Proceso exitoso');
    }

    public function parameterViewTicket()
    {
        $parameters = $this->ticketParametersService->getParameterObject();

        if (property_exists($parameters, 'qrcode_size')) {
            $parameters->qrcode_size = round($parameters->qrcode_size / 37.7952755906, 1);
        } else {
            $parameters->qrcode_size = null;
        }

        return view('tickets.parameters', compact('parameters'));
    }

    public function saveParameters(Request $request)
    {
        return $this->ticketParametersService->saveParameters($request);
    }

    public function tableFilterTicketUserLogs($events = null, $types = null, $from_date = null, $to_date = null)
    {
        DB::statement("SET sql_mode = ''");
        $obj = $obj = DB::table('ticket_user_logs')
            ->select(
                'ticket_user_logs.id',
                'ticket_user_logs.ticket_id',
                'ticket_user_logs.previous_user_id AS previousUser',
                'ticket_user_logs.new_user_id AS newUser',
                'ticket_user_logs.payment_reference',
                'ticket_user_logs.number_transfers',
                'tickets.code_ticket AS codeTicket',
                'previous_user.email AS previousUserEmail',
                'new_user.email AS newUserEmail',
                DB::raw('CONCAT(match_events.name, " - ",DATE_FORMAT(match_events.event_start, "%Y-%m-%d %h:%i %p")) AS event_'),
                DB::raw('DATE_FORMAT(ticket_user_logs.created_at, "%Y-%m-%d %h:%i %p") AS date_'),
                'ticket_types.name AS type'
            )
            ->leftjoin('tickets', 'tickets.id', '=', 'ticket_user_logs.ticket_id')
            ->leftjoin('ticket_types', 'ticket_types.id', '=', 'tickets.ticket_type_id')
            ->leftjoin('users AS previous_user', 'previous_user.id', '=', 'ticket_user_logs.previous_user_id')
            ->leftjoin('users AS new_user', 'new_user.id', '=', 'ticket_user_logs.new_user_id')
            ->leftjoin('match_events', 'match_events.code', '=', 'tickets.code_event');
        if ($events && $events != 'null') {
            $obj->whereIn('match_events.id', explode(',', $events));
        }
        if ($types && $types != 'null') {
            $obj->whereIn('tickets.ticket_type_id', explode(',', $types));
        }
        if ($from_date && $from_date != 'null') {
            $obj->whereDate('ticket_user_logs.created_at', '>=', $from_date);
        }
        if ($to_date && $to_date != 'null') {
            $obj->whereDate('ticket_user_logs.created_at', '<=', $to_date);
        }

        DB::statement("SET sql_mode = 'STRICT_TRANS_TABLES,ERROR_FOR_DIVISION_BY_ZERO,NO_ENGINE_SUBSTITUTION'");
        \DB::enableQueryLog();
        $dataTable = DataTables::of($obj)
            ->addColumn('actions', function ($obj) {
                return '
                    <i class="fa fa-pencil iconMini" onClick="clickEdit(' . $obj->id . ')" data-id="' . $obj->id . '" data-toggle="tooltip" data-placement="bottom"  style="cursor:pointer;"></i>
                    <i class="fa fa-trash iconMini" onClick="clickDelete(' . $obj->id . ')" data-id="' . $obj->id . '" data-toggle="tooltip" data-placement="bottom"  style="cursor:pointer;"></i>
                ';
            })
            ->rawColumns(['actions']);

        $response = $dataTable->make(true);
        $data = $response->getData();
        $data = json_decode(json_encode($data), true);
        $queries = \DB::getQueryLog();
        $data['queries'] = $queries;
        return $data;
    }

    public function listTicketUserLogs()
    {
        $events = MatchEvent::select('id', 'name', DB::raw('DATE_FORMAT(event_start, "%Y-%m-%d %h:%i %p") as event_start'), 'active')
            ->orderBy('name', 'ASC')
            ->get();
        $types = TicketType::select('id', 'name')->where('active', true)->get();

        return view('tickets.listTicketUserLog', compact('events', 'types'));
    }


    public function createTicketsMatchByQuery($matchEventReferenceId, $type = 2, $matchEventCopyId)
    {
        $matchEventId = $matchEventCopyId;
        try {
            if (in_array(Auth::user()->rol->id, [$this->__SUPERADMIN_ROL])) {
                $tickets = DB::table('tickets as t')
                    ->select('t.*')
                    ->where('t.match_event_id', $matchEventReferenceId)
                    ->where('t.ticket_type_id', $type)
                    ->get();
                $response = [];
                foreach ($tickets as $ticket) {
                    $response[] = $this->createTicket(
                        [
                            'seat_id' => $ticket->seat_id,
                            'match_event_id' => $matchEventId,
                            'user_id' => $ticket->user_id,
                            'ticket_type_id' => $ticket->ticket_type_id,
                            'ticket_main_id' => $ticket->ticket_main_id,
                            'price' => $ticket->price
                        ]
                    );
                }
                return 'Proceso ejecutado exitosamente: Total boletas generadas => ' . count($response);
            }
            return 'Proceso no ejecutado por permisos';
        } catch (\Throwable $th) {
            return $th->getMessage();
        }
    }

    public function generateTicketsByReferenceOrTicketMain(Request $request, $reference = null, $ticketMainId = null)
    {
        if ($reference && $reference == 'null') {
            $reference = null;
        }

        if (Auth::user()) {
            $data = [
                'reference' => $reference,
                'ticketMainId' => $ticketMainId
            ];
            $this->registerLog(Auth::user()->id, 'Crear boletas manualmente por referencia', json_encode($data), "Create", $this->getModule($request));
        }

        $ticketMain = TicketMain::with(['ticket_user_block_backups' => function ($q) {
            $q->where('ticket_user_block_backups.is_social_distancing', false);
        }])
            ->when($reference, function ($q) use ($reference) {
                $q->where('payment_reference', $reference);
            })
            ->when($ticketMainId, function ($q) use ($ticketMainId) {
                $q->where('id', $ticketMainId);
            })
            ->first();

        if (!$ticketMain) {
            return array('r' => false, 'm' => 'Proceso no ejecutado, debido a que no existe la reserva');
        }

        if (!$ticketMain->ticket_user_block_backups->isEmpty()) {
            $statusGenerateTickets = $this->generateTickets($ticketMain->ticket_user_block_backups, $ticketMain->id, true);
            $response = json_decode($statusGenerateTickets->getContent());
            if ($response->r) {
                $ticketMain->payment_state = "CONFIRMED";
                $ticketMain->payment_comment = 'APPROVED';
                $ticketMain->update();
                return array('r' => true, 'm' => 'Proceso ejecutado exitosamente: ' . json_encode($response));
            }
            return array('r' => false, 'm' => 'Proceso no ejecutado, debido a: ' . json_encode($response));
        }

        return array('r' => false, 'm' => 'Proceso no ejecutado, debido a que no existen bloqueos de sillas');
    }

    public function getDetailNameZonesEvent($eventIdOrCode)
    {
        $data = DB::table('tickets as t')
            ->select(DB::raw('CONCAT(z1.name, IF(t.special_text IS NOT NULL, CONCAT("_", t.special_text), "")) AS tags'), DB::raw('COUNT(*) AS total'))
            ->join('seats as s', 's.id', '=', 't.seat_id')
            ->join('zones as z', 'z.id', '=', 's.zone_id')
            ->join('zones as z1', 'z1.id', '=', 'z.zone_id')
            ->where('t.ticket_status_id', TicketStatusEnum::PURCHASED)
            ->when($eventIdOrCode, function ($query) use ($eventIdOrCode) {
                $query->where('t.code_event', $eventIdOrCode);
            })
            ->groupBy('tags')
            ->orderBy('total', 'ASC')
            ->get();

        $table = '<table>
        <tr>
          <th>Tribuna</th>
          <th></th>
          <th>Boletas</th>
        </tr>';
        $totalTickets = 0;
        foreach ($data as $item) {
            $table .= '<tr>' .
                '<td>' . $item->tags . '</td>' .
                '<td>' . '</td>' .
                '<td>' . $item->total . '</td>' .
                '</tr>';
            $totalTickets += $item->total;
        }
        $table .= '<tr>
                        <th>Total</th>
                        <th></th>
                        <th>' . $totalTickets . '</th>
                    </tr>';
        $table .= '</table>';
        return $table;
    }

    public function getEventCapacity($eventIdOrCode)
    {
        $soldTickets = DB::table('tickets')
            ->select(
                'zsub.name AS tribune',
                DB::raw("z.name AS sector"),
                'z.total_capacity AS total_capacity',
                DB::raw('IF(MAX(mea.id), mea.salable_capacity, z.salable_capacity) AS capacity'),
                DB::raw('COUNT(tickets.id) AS sold'),
                DB::raw('(IF(MAX(mea.id), mea.salable_capacity, z.salable_capacity) - COUNT(tickets.id)) AS available')
            )
            ->join('ticket_mains', 'tickets.ticket_main_id', '=', 'ticket_mains.id')
            ->join('match_events', 'tickets.match_event_id', '=', 'match_events.id')
            ->join('seats as s', 'tickets.seat_id', '=', 's.id')
            ->join('zones as z', 's.zone_id', '=', 'z.id')
            ->join('zones as zsub', 'z.zone_id', '=', 'zsub.id')
            ->leftJoin('match_event_stages as mea', function ($join) {
                $join->on('mea.zone_id', '=', 'z.id')
                    ->on('mea.match_event_id', '=', 'match_events.id')
                    ->where('mea.stage_type_id', StageTypesEnum::LIMIT_TRIBUNE_CAPACITY);
            })
            ->where(function ($query) use ($eventIdOrCode) {
                $query->where('tickets.code_event', $eventIdOrCode)
                    ->orWhere('tickets.match_event_id', $eventIdOrCode);
            }) // Del evento
            ->where(function ($query) {
                $query->where('tickets.ticket_status_id', TicketStatusEnum::PURCHASED)    // Comprado
                    ->orWhere('tickets.ticket_status_id', TicketStatusEnum::CREATED);   // Ingresado
            })
            ->groupBy([
                'tribune',
                'sector',
                'z.total_capacity',
                'z.salable_capacity',
                'mea.salable_capacity'
            ])
            ->orderBy('tribune', 'ASC')
            ->orderBy('sector', 'ASC')
            ->get();

        $table = '<table>
        <tr>
            <th>Tribuna</th>
            <th>Sector</th>
            <th>Capacidad Total</th>
            <th>Capacidad Vendible</th>
            <th>Boletas vendidas</th>
            <th>Boletas disponibles</th>
        </tr>';
        $totalCapacity = 0;
        $totalSold = 0;
        $totalAvailable = 0;
        foreach ($soldTickets as $item) {
            $table .= '<tr>' .
                '<td>' . $item->tribune . '</td>' .
                '<td>' . $item->sector . '</td>' .
                '<td>' . $item->total_capacity . '</td>' .
                '<td>' . $item->capacity . '</td>' .
                '<td>' . $item->sold . '</td>' .
                '<td>' . $item->available . '</td>' .
                '</tr>';
            $totalCapacity += $item->capacity;
            $totalSold += $item->sold;
            $totalAvailable += $item->available;
        }
        $table .= '<tr>
                        <th>Total</th>
                        <th></th>
                        <th>' . $totalCapacity . '</th>
                        <th>' . $totalSold . '</th>
                        <th>' . $totalAvailable . '</th>
                    </tr>';
        $table .= '</table>';
        return $table;
    }

    public function validateExport(Request $request)
    {
        if ($request['query']) {
            $results = $this->util->getGenericData($request["query"], $request["bindings"]);
            if (count($results) > 0) {
                $name = 'ReporteRepositorioDocumental' . time() . '.xlsx';
                Excel::store(new ListTickeLogsExport($results), $name, 'public');
                return response()->json(['success' => true, 'message' => 'Validación OK', 'data' => $name]);
            }
        }

        return response()->json(['success' => false, 'message' => 'No existen datos a exportar']);
    }

    public function export($name)
    {
        return $this->util->export($name);
    }

    public function dispatchTicketProcesses($ticketMainId)
    {
        $ticketMain = $this->ticketService->find($ticketMainId);
        if (!$ticketMain || $this->isCompletedTicketNotification($ticketMain)) {
            return;
        }
        $this->executeTicketProcesses($ticketMain);
    }

    // Ejecución de procesos alternos (facturación electronica o envio de correo)
    public function executeTicketProcesses($ticketMain)
    {
        $enableElectronicInvoiceCreation = $this->ticketParametersService->validateElectronicInvoiceCreation();
        $sendNotificationTickets = $this->ticketParametersService->validateSendingEmailTickets($ticketMain->origin);
        $isValidatePurchaseType = $this->validatePurchaseType($ticketMain);
        $isValidateStatusSendingTicketEmailsOnTickets = $this->validateStatusSendingTicketEmailsOnTickets($ticketMain);

        if ($sendNotificationTickets && $isValidateStatusSendingTicketEmailsOnTickets) {
            $this->notificationTickets($ticketMain->id);
        } else if ($enableElectronicInvoiceCreation && !$ticketMain->cufe && $isValidatePurchaseType) {
            $this->generateInvoice($ticketMain->id);
        } else if ($sendNotificationTickets && $enableElectronicInvoiceCreation) {
            $this->updateTicketNotification($ticketMain, TicketNotificationEnum::COMPLETED);
        } else if ($sendNotificationTickets) {
            $this->updateTicketNotification($ticketMain, TicketNotificationEnum::NOTIFICATION_COMPLETED);
        } else if ($enableElectronicInvoiceCreation && $isValidatePurchaseType) {
            $this->updateTicketNotification($ticketMain, TicketNotificationEnum::BILLING_COMPLETED);
        } else {
            $this->updateTicketNotification($ticketMain, TicketNotificationEnum::SKIP);
        }
    }

    public function generateInvoice($ticketMainId)
    {
        try {
            event(new TicketBillingEvent($ticketMainId));
        } catch (\Exception $th) {
            $data = [
                'function'              => 'generateInvoice',
                'ticketMainId'          => $ticketMainId,
                'message'               => $th->getMessage(),
                'getFile'               => $th->getFile(),
                'getLine'               => $th->getLine(),
            ];
            $this->util->logFile(json_encode($data));
        }
    }

    public function notificationTickets($ticketMainId, $validateSendingStatus = true, $userId = null)
    {
        try {
            NotificationTicketEvent::dispatch($ticketMainId, $validateSendingStatus, $userId);
        } catch (\Exception $th) {
            $data = [
                'function'              => 'notificationTickets',
                'ticketMainId'          => $ticketMainId,
                'message'               => $th->getMessage(),
                'getFile'               => $th->getFile(),
                'getLine'               => $th->getLine(),
            ];
            $this->util->logFile(json_encode($data));
        }
    }

    public function ticketDoor($ticket)
    {
        return $ticket->door;
    }

    public function ticketCodeEvent($ticket)
    {
        return $ticket->code_event;
    }

    private function validatePurchaseType($ticketMain)
    {
        if ($this->ticketParametersService->enableElectronicComplimentaryBilling()) {
            return true;
        }
        return Ticket::where('ticket_main_id', $ticketMain->id)->where('ticket_type_id', '!=', TicketTypesEnum::COMPLIMENTARY)->exists();
    }

    private function validateStatusSendingTicketEmailsOnTickets($ticketMain)
    {
        return Ticket::where('ticket_main_id', $ticketMain->id)->where('is_an_email_sent', 0)->exists();
    }

    public function subscribersTicketEvent($eventIdOrCode)
    {
        $data = DB::table('tickets as t')
            ->selectRaw('
                    COUNT(*) AS TOTAL,
                    CAST(SUM(IF(p.id IS NULL, 1, 0)) AS UNSIGNED) AS NUEVOS,
                    CAST(SUM(IF(p.id IS NULL, 0, 1)) AS UNSIGNED) AS ANTIGUOS
            ')
            ->leftJoin('pre_subscribers as p', 'p.seat_id', '=', 't.seat_id')
            ->where(function ($query) use ($eventIdOrCode) {
                $query->where('t.code_event', $eventIdOrCode)
                    ->orWhere('t.match_event_id', $eventIdOrCode);
            }) // Del evento
            ->first();

        return response()->json($data);
    }

    public function dataSubscribers($eventIdOrCode)
    {
        $matchEvent = MatchEvent::where('code', $eventIdOrCode)->first();
        if (!$matchEvent) {
            return response()->json('Evento no existe');
        }
        $matchEventSeasons = MatchEvent::where('season_id', $matchEvent->season_id)
            ->count();

        $data = TicketMain::join('tickets as t', 't.ticket_main_id', '=', 'ticket_mains.id')
            ->selectRaw('COUNT(DISTINCT t.seat_id) AS subscribers, ROUND((SUM(t.price)*' . $matchEventSeasons . '), 2) AS total')
            ->where('t.ticket_type_id', TicketTypesEnum::SUBSCRIBER)
            ->whereIn('t.ticket_status_id', [TicketStatusEnum::CREATED, TicketStatusEnum::PURCHASED])
            ->where('t.match_event_id', '=', $matchEvent->id)
            ->get();

        if (!$data) {
            return response()->json('No existen datos a mostrar');
        }

        $table = '<table>
        <tr>
          <th>Abonos</th>
          <th></th>
          <th>Total</th>
        </tr>';
        foreach ($data as $item) {
            $table .= '<tr>' .
                '<td>' . $item->subscribers . '</td>' .
                '<td>' . '</td>' .
                '<td>' . $this->formatCurrency($item->total) . '</td>' .
                '</tr>';
        }
        $table .= '</table>';

        return $table;
    }

    public function generateDynamicQr(Request $request)
    {
        return $this->ticketService->generateDynamicQr($request);
    }

    public function billingOnDemand(Request $request)
    {
        $email = $request->email;
        $matchEventId = $request->matchEventId;
        $type = $request->type;

        $ticketMains = DB::table('tickets as t')
            ->select(
                'tm.id'
            )
            ->join('ticket_mains as tm', 'tm.id', '=', 't.ticket_main_id')
            ->join('users as u', 'u.id', '=', 'tm.user_id_log')
            ->whereNull('tm.cufe')
            ->whereIn('t.ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
            ->where('t.match_event_id', $matchEventId)
            ->when($email, function ($query) use ($email) {
                $query->where('u.email', $email);
            })
            ->when($type, function ($query) use ($type) {
                $query->where('t.ticket_type_id', $type);
            })
            ->groupBy('tm.id')
            ->get();

        if (count($ticketMains) == 0) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a facturar a demanda.'
            );
        }

        $data = array(
            'email'         => $email,
            'matchEventId'  => $matchEventId,
            'type'          => $type,
            'ticketMains'   => $ticketMains
        );
        $module = Module::where('route', 'ticket-office')->first();
        $this->registerLog(Auth::user()->id, 'Facturación a demanda', json_encode($data), "Create", $module->id);

        foreach ($ticketMains as $ticketMain) {
            $this->dispatchTicketProcesses($ticketMain->id);
        }

        return array(
            'r' => true,
            'm' => 'Se validaron ' . count($ticketMains) . ' pagos a facturar a demanda.'
        );
    }

    public function appNotificationTickets($ticketMainId, $userId)
    {
        $tickets = $this->ticketService->getTicketsByTicketMainIdAndUserId($ticketMainId, $userId);
        if (!count($tickets)) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a notificar.'
            );
        }

        $tickets = $tickets->whereIn('ticket_status_id', [TicketStatusEnum::CREATED, TicketStatusEnum::PURCHASED]);
        if (!count($tickets)) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a notificar.'
            );
        }

        $userPnsId = $tickets[0]->user->pns_id;
        if (!$userPnsId) {
            return array(
                'r' => false,
                'm' => 'No existe identificador de notificaciones para el usuario.'
            );
        }

        $totalTickets = count($tickets);
        $zoneTickets = $tickets[0]->zone;
        $eventName = $tickets[0]->match_event->name;
        $ticketType = $tickets[0]->ticket_type_id;
        if ($ticketType == TicketTypesEnum::COMPLIMENTARY) {
            $message = 'Tienes ' . $totalTickets . ' cortesías en proceso de aceptación: sector "' . $zoneTickets . '" para el partido "' . $eventName . '"';
        } else {
            $message = 'Tienes ' . $totalTickets . ' nuevas boletas: sector "' . $zoneTickets . '" para el partido "' . $eventName . '"';
        }
        $push = new PushNotificationController();
        $push->sendToUser($message, $userPnsId, null, null, null, null, 'U');
    }

    public function notifyTicketCancellation($ticketMainId, $userId)
    {
        $tickets = $this->ticketService->getTicketsByTicketMainIdAndUserId($ticketMainId, $userId);
        if (!count($tickets)) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a notificar.'
            );
        }

        $tickets = $tickets->where('ticket_status_id', TicketStatusEnum::CANCELLED);
        if (!count($tickets)) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a notificar.'
            );
        }

        $totalTickets = count($tickets);
        $ticketType = $tickets[0]->ticket_type_id == TicketTypesEnum::COMPLIMENTARY ? 'cortesías' : 'boletas';
        $zoneTickets = $tickets[0]->zone;
        $eventTickets = $tickets[0]->match_event->name;
        Mail::to($tickets[0]->user->email)->send(new TicketNotificationCancelled(new TicketNotification($totalTickets, $ticketType, $zoneTickets, $eventTickets)));
    }

    public function appNotificationTicketCancellation($ticketMainId, $userId)
    {
        $tickets = $this->ticketService->getTicketsByTicketMainIdAndUserId($ticketMainId, $userId);
        if (!count($tickets)) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a notificar.'
            );
        }

        $tickets = $tickets->where('ticket_status_id', TicketStatusEnum::CANCELLED);
        if (!count($tickets)) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a notificar.'
            );
        }

        $userPnsId = $tickets[0]->user->pns_id;
        if (!$userPnsId) {
            return array(
                'r' => false,
                'm' => 'No existe identificador de notificaciones para el usuario.'
            );
        }

        $totalTickets = count($tickets);
        $zoneTickets = $tickets[0]->zone;
        $eventName = $tickets[0]->match_event->name;
        $ticketType = $tickets[0]->ticket_type_id;
        if ($ticketType == TicketTypesEnum::COMPLIMENTARY) {
            $message = 'Se han anulado ' . $totalTickets . ' cortesías, sector "' . $zoneTickets . '" para el partido "' . $eventName . '"';
        } else {
            $message = 'Se han anulado ' . $totalTickets . ' boletas: sector "' . $zoneTickets . '" para el partido "' . $eventName . '"';
        }
        $push = new PushNotificationController();
        $push->sendToUser($message, $userPnsId, null, null, null, null, 'U');
    }

    public function notifyTicketUnavailable($ticketMainId, $userId)
    {
        $tickets = $this->ticketService->getTicketsByTicketMainIdAndUserId($ticketMainId, $userId);
        if (!count($tickets)) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a notificar.'
            );
        }

        $tickets = $tickets->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED]);
        if (!count($tickets)) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a notificar.'
            );
        }

        $totalTickets = count($tickets);
        $ticketType = $tickets[0]->ticket_type_id == TicketTypesEnum::COMPLIMENTARY ? 'cortesías' : 'boletas';
        $zoneTickets = $tickets[0]->zone;
        $eventTickets = $tickets[0]->match_event->name;
        Mail::to($tickets[0]->user->email)->send(new TicketNotificationUnavailable(new TicketNotification($totalTickets, $ticketType, $zoneTickets, $eventTickets)));
    }

    public function appNotificationTicketUnavailable($ticketMainId, $userId)
    {
        $tickets = $this->ticketService->getTicketsByTicketMainIdAndUserId($ticketMainId, $userId);
        if (!count($tickets)) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a notificar.'
            );
        }

        $tickets = $tickets->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED]);
        if (!count($tickets)) {
            return array(
                'r' => false,
                'm' => 'No se encontraron boletas a notificar.'
            );
        }

        $userPnsId = $tickets[0]->user->pns_id;
        if (!$userPnsId) {
            return array(
                'r' => false,
                'm' => 'No existe identificador de notificaciones para el usuario.'
            );
        }

        $totalTickets = count($tickets);
        $zoneTickets = $tickets[0]->zone;
        $eventName = $tickets[0]->match_event->name;
        $ticketType = $tickets[0]->ticket_type_id;
        if ($ticketType == TicketTypesEnum::COMPLIMENTARY) {
            $message = 'Tus ' . $totalTickets . ' cortesías, sector "' . $zoneTickets . '" para el partido "' . $eventName . '" ya no estan disponibles';
        } else {
            $message = 'Tus ' . $totalTickets . ' boletas, sector "' . $zoneTickets . '" para el partido "' . $eventName . '" ya no estan disponibles';
        }
        $push = new PushNotificationController();
        $push->sendToUser($message, $userPnsId, null, null, null, null, 'U');
    }

    public function sendToBilling($matchEventId)
    {
        $ticketMains = DB::table('tickets as t')
            ->select(
                'tm.id'
            )
            ->join('ticket_mains as tm', 'tm.id', '=', 't.ticket_main_id')
            ->join('match_events as me', 'me.id', '=', 't.match_event_id')
            ->where('me.id', $matchEventId)
            ->where(function ($query) {
                $query->whereNull('tm.cufe');
            })
            ->whereIn('t.ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
            ->groupBy('tm.id')
            ->get();

        if (count($ticketMains) == 0) {
            return array(
                'r' => false,
                'm' => 'No se encontraron transacciones pendientes de validacion de procesos.'
            );
        }

        foreach ($ticketMains as $ticketMain) {
            $this->dispatchTicketProcesses($ticketMain->id);
        }

        return array(
            'r' => true,
            'm' => 'Se validaron ' . count($ticketMains) . ' transaciones pendientes de validacion de procesos.'
        );
    }
}