File: /var/www/vhost/disk-apps/qas.sports-crowd.com/app/Core/Ticket/Application/TransferService.php
<?php
declare(strict_types=1);
namespace App\Core\Ticket\Application;
use App\Core\Ticket\Entities\TransferStatusEnum;
use App\Core\Ticket\TicketStatusEnum;
use App\Mail\TransferTicket;
use App\Services\TicketParametersService;
use App\Ticket;
use App\TicketUserLog;
use App\User;
use Carbon\Carbon;
use Exception;
use Illuminate\Support\Facades\DB;
use Illuminate\Support\Facades\Mail;
use Illuminate\Support\Str;
class TransferService
{
private $ticketParameterService;
public function __construct()
{
$this->ticketParameterService = new TicketParametersService();
}
public function batchTransfer(
$userId,
$ticketCount,
$recipientEmail,
$matchEventId,
$zone,
$ticketIds = []
) {
$recipient = User::where('email', $recipientEmail)->first();
$availableTickets = Ticket::where('user_id', $userId)
->where('match_event_id', $matchEventId)
->where('zone', $zone)
->whereIn('ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
->whereNotIn('id', TicketUserLog::where('status', TransferStatusEnum::PENDING)->pluck('ticket_id'))
->limit($ticketCount);
if (!empty($ticketIds)) {
$availableTickets = $availableTickets->whereIn('id', $ticketIds);
}
$availableTickets = $availableTickets->get();
if ($availableTickets->count() < $ticketCount) {
throw new Exception(__('transfer_tickets.not_enough_tickets'), 400);
}
$transferGroup = Str::uuid();
$timeToAcceptComplimentaryTickets = $this->ticketParameterService->timeToAcceptComplimentaryTickets();
DB::transaction(function () use ($availableTickets, $userId, $recipient, $transferGroup, $recipientEmail, $timeToAcceptComplimentaryTickets) {
foreach ($availableTickets as $ticket) {
TicketUserLog::create([
'ticket_id' => $ticket->id,
'previous_user_id' => $userId,
'new_user_id' => $recipient->id ?? null,
'email' => $recipientEmail,
'expires_at' => Carbon::now()->addMinutes($timeToAcceptComplimentaryTickets),
'status' => TransferStatusEnum::PENDING,
'transfer_group' => $transferGroup,
'number_transfers' => ++$ticket->number_transfers ?? 1,
'payment_reference' => $ticket->ticket_main->payment_reference
]);
}
});
try {
Mail::send(new TransferTicket($transferGroup));
} catch (Exception $e) {
throw new Exception(__('transfer_tickets.email_not_sent'), 500);
}
return ['transfer_group' => $transferGroup];
}
public function acceptTransfer($user, $transferGroup)
{
$transfers = TicketUserLog::where('transfer_group', $transferGroup)
->where(function ($query) use ($user) {
$query->where('new_user_id', $user->id)->orWhere('email', $user->email);
})
->where('status', TransferStatusEnum::PENDING)
->where('expires_at', '>', Carbon::now())
->get();
if ($transfers->isEmpty()) {
throw new Exception(__('transfer_tickets.transfer_not_found_expired'), 404);
}
DB::transaction(function () use ($user, $transfers) {
foreach ($transfers as $transfer) {
if (in_array($transfer->ticket->ticket_status_id, [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])) {
$transfer->ticket->update(['user_id' => $user->id, 'number_transfers' => $transfer->number_transfers]);
$transfer->update(['status' => TransferStatusEnum::ACCEPTED, 'new_user_id' => $user->id]);
} else {
$transfer->update(['status' => TransferStatusEnum::DECLINED]);
}
}
});
}
public function declineTransfer($userId, $transferGroup)
{
$transfers = TicketUserLog::where('transfer_group', $transferGroup)
->where('previous_user_id', $userId)
->where('status', TransferStatusEnum::PENDING)
->get();
if ($transfers->isEmpty()) {
throw new Exception(__('transfer_tickets.transfer_not_found'), 404);
}
DB::transaction(function () use ($transfers) {
foreach ($transfers as $transfer) {
$transfer->update(['status' => TransferStatusEnum::DECLINED]);
}
});
}
public function reassignTransfer($userId, $transferGroup, $newUserEmail)
{
$transfers = TicketUserLog::where('transfer_group', $transferGroup)
->where('previous_user_id', $userId)
->where('expires_at', '<', Carbon::now())
->whereIn('status', [TransferStatusEnum::PENDING, TransferStatusEnum::DECLINED, TransferStatusEnum::EXPIRED])
->get();
if ($transfers->isEmpty()) {
throw new Exception(__('transfer_tickets.transfer_cannot_be_reassigned'), 403);
}
$newUser = User::where('email', $newUserEmail)->firstOrFail();
DB::transaction(function () use ($transfers, $newUser, $newUserEmail) {
foreach ($transfers as $transfer) {
$transfer->update([
'new_user_id' => $newUser->id ?? null,
'email' => $newUserEmail,
'expires_at' => Carbon::now()->addMinutes(30),
'status' => TransferStatusEnum::PENDING
]);
}
});
Mail::send(new TransferTicket($transferGroup));
}
public function reverseTransfer($userId, $transferGroup)
{
$transfers = TicketUserLog::where('transfer_group', $transferGroup)
->where('previous_user_id', $userId)
->whereIn('status', [TransferStatusEnum::PENDING, TransferStatusEnum::DECLINED, TransferStatusEnum::EXPIRED])
->get();
if ($transfers->isEmpty()) {
throw new Exception(__('transfer_tickets.transfer_cannot_be_reversed'), 403);
}
DB::transaction(function () use ($transfers) {
foreach ($transfers as $transfer) {
$transfer->update(['status' => TransferStatusEnum::EXPIRED]);
}
});
}
public function expireTransfers()
{
DB::transaction(function () {
$expiredTransfers = TicketUserLog::where('status', TransferStatusEnum::PENDING)
->where('expires_at', '<', Carbon::now())
->get();
foreach ($expiredTransfers as $transfer) {
$transfer->update(['status' => TransferStatusEnum::EXPIRED]);
}
});
}
public function getPendingTransfersByUser($user)
{
return TicketUserLog::select([
'transfer_group',
'previous_user_id',
'new_user_id',
DB::raw('COUNT(ticket_id) as ticket_count'),
DB::raw('MAX(expires_at) as expires_at'),
])
->join('tickets', 'tickets.id', '=', 'ticket_user_logs.ticket_id')
->whereIn('tickets.ticket_status_id', [TicketStatusEnum::PURCHASED, TicketStatusEnum::CREATED])
->where('status', TransferStatusEnum::PENDING)
->where(function ($query) use ($user) {
$query->where('new_user_id', $user->id)->orWhere('email', $user->email);
})
->groupBy('transfer_group', 'previous_user_id', 'new_user_id')
->get();
}
public function getPendingBatchTransfersByUser($userId)
{
return TicketUserLog::select([
'id',
'ticket_id',
'previous_user_id',
'new_user_id',
'payment_reference',
'number_transfers',
'status',
'expires_at',
'transfer_group',
])
->where('previous_user_id', $userId)
->orWhere('new_user_id', $userId)
->with('ticket:id,code_ticket,zone,match_event_id')
->get();
}
public function getMatchEventByTransferGroupId($transferGroupId)
{
return TicketUserLog::distinct()->select([
'match_events.id',
'match_events.name',
'match_events.event_start',
'match_events.stadium_to_play',
'tickets.zone',
])
->join('tickets', 'tickets.id', '=', 'ticket_user_logs.ticket_id')
->join('match_events', 'match_events.id', '=', 'tickets.match_event_id')
->where('transfer_group', $transferGroupId)
->groupBy('match_events.id', 'tickets.zone')
->first();
}
public function countTicketsTransferByTransferGroup($transferGroup)
{
return TicketUserLog::where('transfer_group', $transferGroup)->count();
}
}