File: /var/www/vhost/disk-apps/demo.sports-crowd.com/app/Http/Controllers/PaymentController.php
<?php
namespace App\Http\Controllers;
use App\Core\Academy\Application\AcademyPurchaseService;
use App\Core\Academy\Application\AcademyTournamentPaymentService;
use App\Core\Academy\Application\ExperiencePaymentService;
use App\Core\Academy\Application\MembershipOrderService;
use App\Core\CorporateIdentity\Application\CorporateIdentityService;
use App\Core\Order\Application\OrderService;
use App\Core\Order\OrderStatusEnum;
use App\Core\Payment\Application\PaymentGatewayService;
use App\Core\Payment\Application\PaymentTransactionService;
use App\Core\Payment\Entities\PaymentIntentResponse;
use App\Core\Payment\PaymentMethodContext;
use App\Core\Payment\PaymentStatusEnum;
use App\Core\Ticket\Application\TicketService;
use App\Parameter;
use Illuminate\Http\Request;
class PaymentController extends Controller
{
private $paymentGateway;
private $paymentGatewayData;
private $paymentContext;
private $paymentGatewayService;
private $orderService;
private $ticketService;
private $paymentTransactionService;
private $academyPurchaseService;
private $academyTournamentPaymentService;
private $membershipOrderService;
private $experiencePaymentService;
private $postPurchaseTeamImage;
private $appOrigin;
public function __construct(Request $request)
{
$this->paymentGatewayService = new PaymentGatewayService();
$this->orderService = new OrderService();
$this->ticketService = new TicketService();
$this->paymentTransactionService = new PaymentTransactionService();
$this->academyPurchaseService = new AcademyPurchaseService();
$this->academyTournamentPaymentService = new AcademyTournamentPaymentService();
$this->membershipOrderService = new MembershipOrderService();
$this->experiencePaymentService = new ExperiencePaymentService();
if ($request->paymentGatewayId || $request->paymentgatewayid) {
$this->initGateway($request);
// TODO: move to a service, check if we can use a singleton pattern here
$parameters = Parameter::first();
$this->postPurchaseTeamImage = $parameters->image_url_finish_payment ? $parameters->image_url_finish_payment . ('?dc=' . \Carbon\Carbon::now()->getTimestamp()) : '';
}
}
public function webcheckout(Request $request)
{
$this->appOrigin = $request->appOrigin;
if ($request->has("uid")) {
$this->payOrder($request->uid);
}
if ($request->has("ticketId")) {
$this->payTicket($request->ticketId);
}
if ($request->has("academyPurchaseId")) {
$this->payAcademyPurchase($request->academyPurchaseId);
}
if ($request->has("academyTournamentPaymentId")) {
$this->payAcademyTournament($request->academyTournamentPaymentId);
}
if ($request->has("membershipId")) {
$this->payMembership($request->membershipId);
}
if ($request->has("experiencePaymentId")) {
$this->payExperience($request->experiencePaymentId);
}
}
public function payment(Request $request)
{
$origin = null;
$orderPaymentTransaction = $this->orderService->getByReference($request->reference);
$ticketPaymentTransaction = $this->ticketService->getByReference($request->reference);
$genericPaymentTransaction = $this->paymentTransactionService->getByReference($request->reference);
$paymentTransaction = $orderPaymentTransaction ?? $ticketPaymentTransaction ?? $genericPaymentTransaction;
$paymentData = null;
if (!is_null($paymentTransaction)) {
if ($paymentTransaction === $orderPaymentTransaction) {
$paymentData = $this->orderService->validatePayment($paymentTransaction);
$origin = "order";
}
if ($paymentTransaction === $ticketPaymentTransaction) {
$paymentData = $this->ticketService->validatePayment($paymentTransaction);
$origin = "ticket";
}
if ($paymentTransaction === $genericPaymentTransaction) {
$paymentData = $this->paymentTransactionService->validatePayment($paymentTransaction);
$origin = "generic";
}
}
if (!$paymentData) {
return response()->json([
'r' => false,
'm' => 'Payment not found'
]);
}
if ($paymentData->status() == PaymentStatusEnum::CONFIRMED) {
$webcheckoutConfirmData = [
'state' => $paymentData->status(),
'comment' => 'Venta exitosa',
'origin' => $origin,
'appOrigin' => $request->appOrigin
];
} else {
$webcheckoutConfirmData = [
'state' => $paymentData->status(),
'comment' => $paymentData->status(),
'origin' => $origin,
'appOrigin' => $request->appOrigin
];
}
return $this->webcheckoutConfirm($webcheckoutConfirmData, $paymentTransaction, $paymentData);
}
public function webcheckoutConfirm($data, $paymentTransaction, $paymentData)
{
$is_url_image = $this->postPurchaseTeamImage;
switch ($data['origin']) {
case 'ticket':
$data['message'] = 'messages.paymentResponse.webcheckout_confirm_2';
break;
case 'order':
$data['message'] = 'messages.paymentResponse.webcheckout_confirm_3';
break;
default:
$data['message'] = 'messages.paymentResponse.webcheckout_confirm_7';
sleep(2); // To wait for finishPayment
$paymentTransaction = $this->paymentTransactionService->getById($paymentTransaction->id);
break;
}
$corporateIdentity = CorporateIdentityService::get();
return view('paymentResponse.webcheckout-confirm', compact('is_url_image', 'data', 'corporateIdentity'))
->with("paymentTransaction", $paymentTransaction)
->with("paymentData", $paymentData);
}
public function webhooksListener(Request $request)
{
return $this->paymentGateway->webhooksListener($request);
}
public function getTransactionByReference(Request $request)
{
$origin = null;
$orderPaymentTransaction = $this->orderService->getByReference($request->reference);
$ticketPaymentTransaction = $this->ticketService->getByReference($request->reference);
$genericPaymentTransaction = $this->paymentTransactionService->getByReference($request->reference);
$paymentTransaction = $orderPaymentTransaction ?? $ticketPaymentTransaction ?? $genericPaymentTransaction;
if (!is_null($paymentTransaction)) {
try {
if ($paymentTransaction === $orderPaymentTransaction) {
$paymentData = $this->orderService->validatePayment($paymentTransaction);
$origin = "order";
}
if ($paymentTransaction === $ticketPaymentTransaction) {
$paymentData = $this->ticketService->validatePayment($paymentTransaction);
$origin = "ticket";
}
if ($paymentTransaction === $genericPaymentTransaction) {
$paymentData = $this->paymentTransactionService->validatePayment($paymentTransaction);
$origin = "generic";
}
return response()->json([
'r' => true,
'd' => [
'data' => array_merge(['origin' => $origin], $paymentData->toArray())
]
]);
} catch (\Throwable $th) {
return response()->json([
'r' => false,
'm' => $th->getMessage()
]);
}
} else {
return response()->json([
'r' => false,
'm' => 'Payment not found'
]);
}
}
public function confirmTransaction(Request $request)
{
return $this->paymentGateway->confirmTransaction($request);
}
public function validatePayment($paymentGatewayId, $transactionId, $reference)
{
$this->paymentGateway->validatePayment($transactionId, $reference);
}
public function responseTransaction(Request $request)
{
return $this->paymentGateway->responseTransaction($request);
}
private function initGateway($request): void
{
$this->paymentGatewayData = $this->paymentGatewayService->find(
(int) ($request->paymentGatewayId ?? $request->paymentgatewayid)
);
$this->paymentGatewayData->appOrigin = $request->appOrigin;
$this->paymentContext = PaymentMethodContext::init($this->paymentGatewayData->id);
$this->paymentContext->setExtraConfirmUrlData(['appOrigin' => $request->appOrigin]);
$this->paymentGateway = new $this->paymentGatewayData->class;
}
private function payOrder($orderId)
{
$order = $this->orderService->find((int) $orderId);
$isPending = $this->orderService->isProcessingPayment($order);
if ($isPending) {
return $this->paymentAlreadyDone(__('messages.paymentResponse.payment_pending'));
}
// check confirmed order before go to processor
if ($this->orderService->isPaymentConfirmed($order)) {
return $this->paymentAlreadyDone("La orden ya registra un pago.");
}
$currentPaymentStatus = $this->paymentContext->retrieveOrderPayment($order);
if ($currentPaymentStatus->status() && $currentPaymentStatus->status() == OrderStatusEnum::CONFIRMED) {
$this->orderService->setOrderAsConfirmed($order);
return $this->paymentAlreadyDone("La orden ya registra un pago.");
}
$this->orderService->setPaymentGatewayId($order, $this->paymentGatewayData->id);
$this->orderService->setOrderAsPending($order);
$paymentProcessorResponse = $this->paymentContext->payOrder($order);
$this->orderService->setPaymentGatewayTxId($order, $paymentProcessorResponse->paymentGatewayTxId());
return $this->processResponse($paymentProcessorResponse);
}
private function payTicket($ticketId)
{
$ticket = $this->ticketService->find((int) $ticketId);
$isPending = $this->ticketService->isProcessingPayment($ticket);
if ($isPending) {
return $this->paymentAlreadyDone(__('messages.paymentResponse.payment_pending'));
}
if ($ticket->payment_state == PaymentStatusEnum::CONFIRMED) {
return $this->paymentAlreadyDone("El ticket ya registra un pago.");
}
$this->ticketService->setTicketAsPending($ticket);
$this->ticketService->setPaymentGatewayId($ticket, $this->paymentGatewayData->id);
$currentPaymentStatus = $this->paymentContext->retrieveTicketPayment($ticket);
if ($currentPaymentStatus->status() == PaymentStatusEnum::CONFIRMED) {
$this->setTicketAsConfirmed($ticket);
return $this->paymentAlreadyDone("El ticket ya registra un pago.");
}
$paymentProcessorResponse = $this->paymentContext->payTicket($ticket);
$this->ticketService->setPaymentGatewayTxId($ticket, $paymentProcessorResponse->paymentGatewayTxId());
return $this->processResponse($paymentProcessorResponse);
}
private function payAcademyPurchase($academyPurchasePaymentId)
{
$academyPurchase = $this->academyPurchaseService->find($academyPurchasePaymentId);
$isPending = $this->academyPurchaseService->isProcessingPayment($academyPurchase);
if ($isPending) {
return $this->paymentAlreadyDone(__('messages.paymentResponse.payment_pending'));
}
$paymentTransaction = $this->academyPurchaseService->getPaymentTransaction(
$academyPurchase,
$this->paymentGatewayData->id
);
if ($paymentTransaction->state == PaymentStatusEnum::CONFIRMED) {
return $this->paymentAlreadyDone("Ya existe un pago registrado para este concepto.");
}
$this->paymentContext->setMarketplaceId(
$academyPurchase->academy_user->academy_category->academy_location->marketplace_id ?? null
);
$this->paymentTransactionService->setPaymentGatewayId(
$academyPurchase->payment_transaction,
$this->paymentGatewayData->id
);
$paymentProcessorResponse = $this->paymentContext->payAcademyPurchase($academyPurchase);
$this->paymentTransactionService->setPaymentGatewayTxId(
$academyPurchase->payment_transaction,
$paymentProcessorResponse->paymentGatewayTxId()
);
return $this->processResponse($paymentProcessorResponse);
}
private function payAcademyTournament($academyTournamentPaymentId)
{
$academyTournamentPayment = $this->academyTournamentPaymentService->find($academyTournamentPaymentId);
$isPending = $this->academyTournamentPaymentService->isProcessingPayment($academyTournamentPayment);
if ($isPending) {
return $this->paymentAlreadyDone(__('messages.paymentResponse.payment_pending'));
}
$paymentTransaction = $this->academyTournamentPaymentService->getPaymentTransaction(
$academyTournamentPayment,
$this->paymentGatewayData->id
);
if ($paymentTransaction->state == PaymentStatusEnum::CONFIRMED) {
return $this->paymentAlreadyDone("Ya existe un pago registrado para este concepto.");
}
$this->paymentContext->setMarketplaceId(
$academyTournamentPayment->academy_user->academy_category->academy_location->marketplace_id ?? null
);
$this->paymentTransactionService->setPaymentGatewayId(
$academyTournamentPayment->payment_transaction,
$this->paymentGatewayData->id
);
$paymentProcessorResponse = $this->paymentContext->payAcademyTournament($academyTournamentPayment);
$this->paymentTransactionService->setPaymentGatewayTxId(
$academyTournamentPayment->payment_transaction,
$paymentProcessorResponse->paymentGatewayTxId()
);
return $this->processResponse($paymentProcessorResponse);
}
private function payMembership($membershipId)
{
try {
$membershipPayment = $this->membershipOrderService->find($membershipId);
} catch (\Throwable $th) {
return $this->paymentAlreadyDone($th->getMessage());
}
$isPending = $this->membershipOrderService->isProcessingPayment($membershipPayment);
if ($isPending) {
return $this->paymentAlreadyDone(__('messages.paymentResponse.payment_pending'));
}
$paymentTransaction = $this->membershipOrderService->getPaymentTransaction($membershipPayment);
if ($paymentTransaction->state == PaymentStatusEnum::CONFIRMED) {
return $this->paymentAlreadyDone("Ya existe un pago registrado para este concepto.");
}
$this->paymentTransactionService->setPaymentGatewayId(
$membershipPayment->paymentTransaction,
$this->paymentGatewayData->id
);
$paymentProcessorResponse = $this->paymentContext->payMembership($membershipPayment);
$this->paymentTransactionService->setPaymentGatewayTxId(
$membershipPayment->paymentTransaction,
$paymentProcessorResponse->paymentGatewayTxId()
);
return $this->processResponse($paymentProcessorResponse);
}
private function payExperience($experiencePaymentId)
{
$experiencePayment = $this->experiencePaymentService->find($experiencePaymentId);
$isPending = $this->experiencePaymentService->isProcessingPayment($experiencePayment);
if ($isPending) {
return $this->paymentAlreadyDone(__('messages.paymentResponse.payment_pending'));
}
$paymentTransaction = $this->experiencePaymentService->getPaymentTransaction($experiencePayment);
if ($paymentTransaction->state == PaymentStatusEnum::CONFIRMED) {
return $this->paymentAlreadyDone("Ya existe un pago registrado para este concepto.");
}
$this->paymentTransactionService->setPaymentGatewayId(
$experiencePayment->payment_transaction,
$this->paymentGatewayData->id
);
$paymentProcessorResponse = $this->paymentContext->payExperience($experiencePayment);
$this->paymentTransactionService->setPaymentGatewayTxId(
$experiencePayment->payment_transaction,
$paymentProcessorResponse->paymentGatewayTxId()
);
return $this->processResponse($paymentProcessorResponse);
}
private function processResponse(PaymentIntentResponse $response)
{
if ($response->action() == PaymentIntentResponse::ACTION_SHOW) {
return response()->view($response->view(), $response->data())->send();
}
if ($response->action() == PaymentIntentResponse::ACTION_REDIRECT) {
return redirect()->to($response->redirectUrl(), 302)->send();
}
if ($response->action() == PaymentIntentResponse::ACTION_FAILED) {
$message = $response->message();
$is_url_image = $this->postPurchaseTeamImage;
return response()->view($response->redirectUrl(), compact('message', 'is_url_image'))->send();
}
}
private function paymentAlreadyDone($message)
{
$is_url_image = $this->postPurchaseTeamImage;
$appOrigin = $this->appOrigin;
return response()->view("paymentResponse.webcheckout-done", compact('message', 'is_url_image', 'appOrigin'))->send();
}
public function getAuthorizationCode($paymentTransaction)
{
return $this->paymentGateway->getAuthorizationCode($paymentTransaction->gateway_response);
}
public function validatePaymentAvailability(Request $request)
{
if ($request->has("academyPurchaseId")) {
return $this->validatePayAcademyPurchase($request->academyPurchaseId);
}
if ($request->has("academyTournamentPaymentId")) {
return $this->validatePayAcademyTournament($request->academyTournamentPaymentId);
}
return $this->responseSuccess(__('messages.paymentResponse.payment_available'));
}
public function validatePayAcademyPurchase($academyPurchaseId)
{
$academyPurchase = $this->academyPurchaseService->find($academyPurchaseId);
if ($this->academyPurchaseService->isPaymentConfirmed($academyPurchase)) {
return $this->reponseWarning(__('messages.paymentResponse.payment_confirmed'));
} else if ($this->academyPurchaseService->isProcessingPayment($academyPurchase)) {
return $this->reponseWarning(__('messages.paymentResponse.payment_pending'));
}
return $this->responseSuccess(__('messages.paymentResponse.payment_available'));
}
private function validatePayAcademyTournament($academyTournamentPaymentId)
{
$academyTournamentPayment = $this->academyTournamentPaymentService->find($academyTournamentPaymentId);
if ($this->academyTournamentPaymentService->isPaymentConfirmed($academyTournamentPayment)) {
return $this->reponseWarning(__('messages.paymentResponse.payment_confirmed'));
} else if ($this->academyTournamentPaymentService->isProcessingPayment($academyTournamentPayment)) {
return $this->reponseWarning(__('messages.paymentResponse.payment_pending'));
}
return $this->responseSuccess(__('messages.paymentResponse.payment_available'));
}
private function reponseWarning($message)
{
return array('r' => false, 'm' => $message);
}
private function responseSuccess($message)
{
return array('r' => true, 'm' => $message);
}
public function getPaymentMethod($paymentTransaction)
{
return $this->paymentGateway->getPaymentMethod($paymentTransaction->gateway_response);
}
}