'Create Payment Booking', 'message' => 'You have successfully created a payment booking' ]; } /** @var FetchesBookingQuotation */ private $fetchBookingQuotation; /** @var FetchesCompanyPaymentAttemptLimit */ private $fetchesCompanyPaymentAttemptLimit; /** @var GeneratesTransactionBillNumber */ private $generatesTransactionBillNumber; /** @var CreatesTransaction */ private $createsTransaction; /** @var CalculatesBookingOutstanding */ private $calculatesBookingOutstanding; /** @var CreatesBillplzBill */ private $createsBillplzBill; /** @var UpdatesWalletBalance */ private $updatesWalletBalance; /** @var UpdatesTransactionStatus */ private $updatesTransactionStatus; /** @var RecalculatesWalletBalance */ private $recalculatesWalletBalance; /** @var BookingToVoucherifyProcessor */ private $bookingToVoucherifyProcessor; /** @var CalculatesBookingRefundAmount */ private $calculatesBookingRefundAmount; /** @var RuleEvaluator */ private $ruleEvaluator; /** @var CreateReceiptVoucherTransactionProcessor */ private $createReceiptVoucherTransactionProcessor; /** @var CanPassOrderDurationLimitRule */ protected $canPassOrderDurationLimitRule; /** @var CanPassEInvoicePromptedRule */ protected $canPassEInvoicePromptedRule; /** @var CanPassTINRule */ protected $canPassTINRule; /** @var CanPassPurchaseOrderRule */ protected $canPassPurchaseOrderRule; /** @var CalculatesTransactionExpiryDateTime */ protected $calculatesTransactionExpiryDateTime; /** * @param FetchesBookingQuotation $fetchBookingQuotation * @param FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber * @param CreatesTransaction $createsTransaction * @param CalculatesBookingOutstanding $calculatesBookingOutstanding * @param CreatesBillplzBill $createsBillplzBill * @param UpdatesWalletBalance $updatesWalletBalance * @param UpdatesTransactionStatus $updatesTransactionStatus * @param RecalculatesWalletBalance $recalculatesWalletBalance * @param BookingToVoucherifyProcessor $bookingToVoucherifyProcessor * @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount * @param RuleEvaluator $ruleEvaluator * @param CreateReceiptVoucherTransactionProcessor $createReceiptVoucherTransactionProcessor * @param CanPassOrderDurationLimitRule $canPassOrderDurationLimitRule * @param CanPassEInvoicePromptedRule $canPassEInvoicePromptedRule * @param CanPassTINRule $canPassTINRule * @param CanPassPurchaseOrderRule $canPassPurchaseOrderRule * @param CalculatesTransactionExpiryDateTime $calculatesTransactionExpiryDateTime */ public function __construct(FetchesBookingQuotation $fetchBookingQuotation, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, CalculatesBookingOutstanding $calculatesBookingOutstanding, CreatesBillplzBill $createsBillplzBill, UpdatesWalletBalance $updatesWalletBalance, UpdatesTransactionStatus $updatesTransactionStatus, CreateCashBackTransactionProcessor $createCashBackTransactionProcessor, RecalculatesWalletBalance $recalculatesWalletBalance, BookingToVoucherifyProcessor $bookingToVoucherifyProcessor, CalculatesBookingRefundAmount $calculatesBookingRefundAmount, RuleEvaluator $ruleEvaluator, CreateReceiptVoucherTransactionProcessor $createReceiptVoucherTransactionProcessor, CanPassOrderDurationLimitRule $canPassOrderDurationLimitRule, CanPassEInvoicePromptedRule $canPassEInvoicePromptedRule, CanPassTINRule $canPassTINRule, CanPassPurchaseOrderRule $canPassPurchaseOrderRule, CalculatesTransactionExpiryDateTime $calculatesTransactionExpiryDateTime) { $this->fetchBookingQuotation = $fetchBookingQuotation; $this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit; $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; $this->createsTransaction = $createsTransaction; $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; $this->createsBillplzBill = $createsBillplzBill; $this->updatesWalletBalance = $updatesWalletBalance; $this->updatesTransactionStatus = $updatesTransactionStatus; $this->recalculatesWalletBalance = $recalculatesWalletBalance; $this->bookingToVoucherifyProcessor = $bookingToVoucherifyProcessor; $this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount; $this->ruleEvaluator = $ruleEvaluator; $this->createReceiptVoucherTransactionProcessor = $createReceiptVoucherTransactionProcessor; $this->canPassOrderDurationLimitRule = $canPassOrderDurationLimitRule; $this->canPassEInvoicePromptedRule = $canPassEInvoicePromptedRule; $this->canPassTINRule = $canPassTINRule; $this->canPassPurchaseOrderRule = $canPassPurchaseOrderRule; $this->calculatesTransactionExpiryDateTime = $calculatesTransactionExpiryDateTime; } /** * @param Request $request * @return JsonResponse * @throws MalformedRequestException * @throws CriteriaNotFulfilledException */ public function logic(Request $request) : JsonResponse { $dto = new ConfirmBookingDTO($request->all()); $result = $this->ruleEvaluator->evaluate([ $this->canPassOrderDurationLimitRule, $this->canPassEInvoicePromptedRule, $this->canPassTINRule, $this->canPassPurchaseOrderRule, ], $dto); if ($result->failed()) { throw new CriteriaNotFulfilledException("- " . implode("
- ", $result->messages())); } $voucherCode = $request->input('voucher_code'); $booking = Booking::find($request->route('id')); $transaction = $this->createBookingPayment($booking, $request->input('amount'), $request->input('payment_method'), $voucherCode, $request->input('bank_code'), $request->user()->email); //Should move to CreateBookingPaymentProcessor.php return $this->resourceResponse(new TransactionResource($transaction)); } private function createBookingPayment(Booking $booking, string $amount, string $paymentMethod, ?string $voucherCode, ?string $bankCode, string $email){ $conversionObject = $this->createConversionObject($booking, $amount, $paymentMethod); $this->validatePayment($booking, $conversionObject); $configurations = $this->fetchBookingQuotation->execute($booking->company, $conversionObject, $voucherCode, null, $booking); $billNumber = $this->generatesTransactionBillNumber->execute('PYMT-'); $paymentReference = $this->handlePaymentMethods($booking, $configurations, $billNumber, $bankCode, $email, $paymentMethod); $billNumber = $this->generatesTransactionBillNumber->execute('PYMT-'); $object = $this->createTransactionObject($booking, $configurations, $billNumber, $paymentReference); /** @var Transaction $transaction */ $transaction = $this->createsTransaction->execute($booking, $object); $this->bookingToVoucherifyProcessor->execute($booking->company->employees()->first(), $transaction, $booking->company->id, $configurations->getSubTotal(), $configurations->getServiceCharge(), $configurations->getVoucherDiscountAmount(), $voucherCode); if(PaymentMethodType::PAYMENT_METHODS[$paymentMethod] == PaymentMethodType::PAYMENT_GATEWAY){ $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::PENDING_VERIFICATION); } if(PaymentMethodType::PAYMENT_METHODS[$paymentMethod] == PaymentMethodType::WALLET){ $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::APPROVED); $this->createReceiptVoucherTransactionProcessor->execute($booking, $transaction); } return $transaction; } private function createConversionObject(Booking $booking, string $amount, string $paymentMethod): CurrencyConversionObject { return new CurrencyConversionObject( floatval(str_replace(',', '', $amount)), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::PAYMENT_METHODS[$paymentMethod] ); } private function validatePayment(Booking $booking, CurrencyConversionObject $conversionObject): void { $outstanding = $this->calculatesBookingOutstanding->execute($booking) + $this->calculatesBookingRefundAmount->execute($booking, $booking->fix_currency_id); if($conversionObject->getAmount() > round($outstanding, 2)) throw new MalformedRequestException('Your payment must not be greater than '. $outstanding .'.'); } private function handlePaymentMethods(Booking $booking, CalculationObject $configurations, string $billNumber, ?string $bankCode, string $email, string $paymentMethod): ?string { $paymentReference = null; if(PaymentMethodType::PAYMENT_METHODS[$paymentMethod] == PaymentMethodType::PAYMENT_GATEWAY) $paymentReference = $this->handlePaymentGateway($booking, $configurations, $billNumber, $bankCode, $email); if(PaymentMethodType::PAYMENT_METHODS[$paymentMethod] == PaymentMethodType::WALLET) $paymentReference = $this->handleWalletPayment($booking, $configurations, $billNumber); return $paymentReference; } private function handlePaymentGateway(Booking $booking, CalculationObject $configurations, string $billNumber, ?string $bankCode, string $email): string { $billPlzBill = $this->createsBillplzBill->execute( $booking->company->name, $email, 'This payment is made for transfer ref. '.$booking->marking, $configurations->getTotal(), $billNumber, $bankCode ); return $billPlzBill->id; } private function handleWalletPayment( Booking $booking, CalculationObject $configurations, string $billNumber): string { $wallet = $booking->company->wallets()->first(); $amount = $configurations->getTotal(); if((float) number_format(($wallet->amount - $amount),2) < 0) throw new MalformedRequestException('Insufficient wallet balance. Please Top up your wallet.'); $transactionObject = new TransactionObject($billNumber, TransactionType::PAYMENT, 1, $booking->company->id, 1, PaymentMethodType::WALLET, $amount, $amount, 1, 1, 1, 0, 0, null, ApprovalStatus::APPROVED, [], ''); $this->createsTransaction->execute($wallet, $transactionObject); $walletBalance = $this->recalculatesWalletBalance->execute($wallet); $this->updatesWalletBalance->execute($wallet, $walletBalance); return $billNumber; } private function createTransactionObject(Booking $booking, CalculationObject $configurations, string $billNumber, ?string $paymentReference): TransactionObject { // $expiresOn = Carbon::now()->addMinutes($this->fetchesCompanyPaymentAttemptLimit->execute($booking->company)); $expiresOn = $this->calculatesTransactionExpiryDateTime->execute($booking->id); return new TransactionObject( $billNumber, TransactionType::PAYMENT, 1, $booking->company->id, $configurations->getConfigurations()->getBankId(), $configurations->getConversionObject()->getPaymentMethod(), $configurations->getTotal(), $configurations->getForeignTotal(), 1, $configurations->getConversionObject()->getCurrencyId(), $configurations->getConfigurations()->getRate(), $configurations->getTax(), $configurations->getServiceCharge(), $expiresOn, ApprovalStatus::PENDING_SUBMISSION, [], $paymentReference ); } // private function handleVoucherCode(Request $request, Booking $booking, CalculationObject $configurations, Transaction $transaction): void // { // $voucherCode = $request->input('voucher_code'); // if($voucherCode){ // $employee = $booking->company->employees()->first(); // $result = $this->redeemsVoucher->execute($voucherCode, $configurations->getSubTotal(), $employee); // $voucher = $result->voucher; // $redemptionId = $result->id; // $voucherValue = $voucher->discount->amount_off ?? ($voucher->discount->percent_off ?? 0.00); // $voucherObject = new VoucherObject($voucher->code, $voucher->metadata->name ?? "", $voucher->discount->type, $voucherValue); // $voucher = $this->createsVoucher->execute($voucherObject); // if(!$voucher) // $voucher = $this->fetchesVoucher->execute(['code' => $voucherObject->getCode()]); // $this->createsVoucherRedemption->execute($redemptionId, $voucher->id, $employee->id, $configurations->getVoucherDiscountAmount()); // } // } }