diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php index 3b00f11a..2efcd3fb 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php @@ -27,6 +27,7 @@ use App\Classes\Modules\Wallets\Services\RecalculatesWalletBalance; use App\Classes\Modules\Rules\Services\RuleEvaluator; use App\Classes\Modules\Rules\Standards\Rules\CanPassOrderDurationLimitRule; use App\Classes\Modules\Transactions\Processors\CreateReceiptVoucherTransactionProcessor; +use App\Classes\Modules\Transactions\Services\CalculatesTransactionExpiryDateTime; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\PaymentMethodType; use App\Classes\ValueObjects\Constants\TransactionType; @@ -103,6 +104,9 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic /** @var CanPassPurchaseOrderRule */ protected $canPassPurchaseOrderRule; + /** @var CalculatesTransactionExpiryDateTime */ + protected $calculatesTransactionExpiryDateTime; + /** * @param FetchesBookingQuotation $fetchBookingQuotation * @param FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit @@ -121,8 +125,9 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic * @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) + 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; @@ -141,6 +146,7 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic $this->canPassEInvoicePromptedRule = $canPassEInvoicePromptedRule; $this->canPassTINRule = $canPassTINRule; $this->canPassPurchaseOrderRule = $canPassPurchaseOrderRule; + $this->calculatesTransactionExpiryDateTime = $calculatesTransactionExpiryDateTime; } /** @@ -269,6 +275,9 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic 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, @@ -283,7 +292,7 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic $configurations->getConfigurations()->getRate(), $configurations->getTax(), $configurations->getServiceCharge(), - Carbon::now()->addMinutes($this->fetchesCompanyPaymentAttemptLimit->execute($booking->company)), + $expiresOn, ApprovalStatus::PENDING_SUBMISSION, [], $paymentReference diff --git a/app/Classes/Modules/Bookings/DataTransferObjects/CreatePaymentVerificationDocumentDTO.php b/app/Classes/Modules/Bookings/DataTransferObjects/CreatePaymentVerificationDocumentDTO.php index ab0b7c96..c1140bbe 100644 --- a/app/Classes/Modules/Bookings/DataTransferObjects/CreatePaymentVerificationDocumentDTO.php +++ b/app/Classes/Modules/Bookings/DataTransferObjects/CreatePaymentVerificationDocumentDTO.php @@ -8,11 +8,13 @@ class CreatePaymentVerificationDocumentDTO implements DataTransferObject { public int $bookingId; public int $companyId; + public int $paymentId; public function __construct(array $data) { $this->bookingId = $data['booking_id']; $this->companyId = $data['company_id']; + $this->paymentId = $data['payment_id']; } public function toArray(): array @@ -20,6 +22,7 @@ class CreatePaymentVerificationDocumentDTO implements DataTransferObject return [ 'booking_id' => $this->bookingId, 'company_id' => $this->companyId, + 'payment_id' => $this->paymentId, ]; } } diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanPassOrderDurationLimitRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassOrderDurationLimitRule.php index 46739d2b..c5a7a8d1 100644 --- a/app/Classes/Modules/Rules/Standards/Rules/CanPassOrderDurationLimitRule.php +++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassOrderDurationLimitRule.php @@ -6,6 +6,7 @@ use App\Classes\Exceptions\CriteriaNotFulfilledException; use App\Classes\General\Abstracts\AbstractRule; use App\Classes\Modules\Bookings\Services\FetchesBooking; use App\Classes\Modules\Companies\Services\FetchesCompanyPaymentAttemptLimit; +use App\Classes\Modules\Transactions\Services\CalculatesTransactionExpiryDateTime; use Carbon\Carbon; use Illuminate\Support\Facades\Log; @@ -18,15 +19,20 @@ class CanPassOrderDurationLimitRule extends AbstractRule /** @var FetchesCompanyPaymentAttemptLimit */ private $fetchesCompanyPaymentAttemptLimit; + /** @var CalculatesTransactionExpiryDateTime */ + private $calculatesTransactionExpiryDateTime; + /** * CanPassOrderDurationLimitRule constructor. * @param FetchesBooking $fetchesBooking * @param FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit + * @param CalculatesTransactionExpiryDateTime $calculatesTransactionExpiryDateTime */ - public function __construct(FetchesBooking $fetchesBooking, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit) + public function __construct(FetchesBooking $fetchesBooking, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit, CalculatesTransactionExpiryDateTime $calculatesTransactionExpiryDateTime) { $this->fetchesBooking = $fetchesBooking; $this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit; + $this->calculatesTransactionExpiryDateTime = $calculatesTransactionExpiryDateTime; } /** @@ -54,57 +60,8 @@ class CanPassOrderDurationLimitRule extends AbstractRule protected function criteria($object): bool { //Check if order is still valid (within duration limit, reused PAYMENT_ATTEMPT_DURATION_LIMIT) - - $isExpired = false; - $booking = $this->fetchesBooking->execute(['id' => $object->bookingId]); - $paymentAttemptLimit = $this->fetchesCompanyPaymentAttemptLimit->execute($booking->company); - // $paymentAttemptLimit = 5; //Manual testing must pay in minutes - - $createdAt = Carbon::parse($booking->created_at); - $bookingExpiresAt = $createdAt->addMinutes($paymentAttemptLimit); - $now = Carbon::now(); - - if ($now->greaterThan($bookingExpiresAt)) { - $isExpired = true; - } - - $allPayments = $booking->transactions() - ->payments() - ->get(); - - if ($isExpired) { - $filteredPayments = $allPayments->filter(function ($payment) use ($bookingExpiresAt) { - return Carbon::parse($payment->created_at)->lessThanOrEqualTo($bookingExpiresAt); - }); - - if ($filteredPayments->isNotEmpty()) { - // Use the earlier payment to recalculate bookingExpiresAt - $earliestPayment = $filteredPayments->sortBy('created_at')->first(); - $newBookingExpiresAt = Carbon::parse($earliestPayment->created_at)->addMinutes($paymentAttemptLimit); - - $logDetails = [ - 'booking_id' => $booking->id, - 'initial_created_at' => $booking->created_at, - 'original_expiry' => $bookingExpiresAt->toDateTimeString(), - 'new_expiry' => $newBookingExpiresAt->toDateTimeString(), - 'valid_payments' => [] - ]; - foreach ($filteredPayments as $payment) { - $logDetails['valid_payments'][] = [ - 'payment_id' => $payment->id, - 'created_at' => $payment->created_at, - 'amount' => $payment->amount, - ]; - } - Log::info("Booking initially expired, but found valid pending payment(s).", $logDetails); - - $bookingExpiresAt = $newBookingExpiresAt; - $isExpired = Carbon::now()->greaterThan($bookingExpiresAt); - } else { - Log::info("Booking expired and no valid pending payments for booking ID: {$booking->id}"); - } - } - + $expiresOn = $this->calculatesTransactionExpiryDateTime->execute($object->bookingId); + $isExpired = Carbon::now()->greaterThan($expiresOn); if($isExpired){ throw new CriteriaNotFulfilledException("Transfer has already expired."); } diff --git a/app/Classes/Modules/Transactions/Services/CalculatesTransactionExpiryDateTime.php b/app/Classes/Modules/Transactions/Services/CalculatesTransactionExpiryDateTime.php new file mode 100644 index 00000000..bf4e42d7 --- /dev/null +++ b/app/Classes/Modules/Transactions/Services/CalculatesTransactionExpiryDateTime.php @@ -0,0 +1,91 @@ +fetchesBooking = $fetchesBooking; + $this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit; + } + + + /** + * @param int $bookingId + * @return Carbon|null $returnDateTime + */ + public function execute(int $bookingId) + { + $isExpired = false; + $booking = $this->fetchesBooking->execute(['id' => $bookingId]); + $paymentAttemptLimit = $this->fetchesCompanyPaymentAttemptLimit->execute($booking->company); + + $createdAt = Carbon::parse($booking->created_at); + Log::info("1. Booking created at {$createdAt}."); + $bookingExpiresAt = $createdAt->addMinutes($paymentAttemptLimit); + Log::info("1. Booking expires at {$bookingExpiresAt}. (original)"); + $newBookingExpiresAt = null; + $now = Carbon::now(); + + if ($now->greaterThan($bookingExpiresAt)) { + $isExpired = true; + } + + $allPayments = $booking->transactions() + ->payments() + ->get(); + + // if ($isExpired) { + $filteredPayments = $allPayments->filter(function ($payment) use ($bookingExpiresAt) { + return Carbon::parse($payment->created_at)->lessThanOrEqualTo($bookingExpiresAt); + }); + + if ($filteredPayments->isNotEmpty()) { + // Use the earlier payment to recalculate bookingExpiresAt + $earliestPayment = $filteredPayments->sortBy('created_at')->first(); + Log::info("2. Booking earliest payment : {$earliestPayment->id}, {$earliestPayment->created_at}"); + $newBookingExpiresAt = Carbon::parse($earliestPayment->created_at)->addMinutes($paymentAttemptLimit); + Log::info("2. Booking expires at : {$newBookingExpiresAt}. (new)"); + $logDetails = [ + 'booking_id' => $booking->id, + 'initial_created_at' => $booking->created_at, + 'original_expiry' => $bookingExpiresAt->toDateTimeString(), + 'new_expiry' => $newBookingExpiresAt->toDateTimeString(), + 'valid_payments' => [] + ]; + foreach ($filteredPayments as $payment) { + $logDetails['valid_payments'][] = [ + 'payment_id' => $payment->id, + 'created_at' => $payment->created_at, + 'amount' => $payment->amount, + ]; + } + Log::info("2. Booking initially expired, but found valid pending payment(s).", $logDetails); + + $isExpired = Carbon::now()->greaterThan($newBookingExpiresAt); + Log::info("2. Booking expired: {$isExpired}"); + } else { + Log::info("Booking expired and no valid pending payments for booking ID: {$booking->id}"); + } + // } + $returnDateTime = $newBookingExpiresAt ? $newBookingExpiresAt : $bookingExpiresAt; + return $returnDateTime; + } +} diff --git a/resources/assets/vue/components/bookings/forms/PaymentVerificationFormComponent.vue b/resources/assets/vue/components/bookings/forms/PaymentVerificationFormComponent.vue index abb3c07c..1e5af3c3 100644 --- a/resources/assets/vue/components/bookings/forms/PaymentVerificationFormComponent.vue +++ b/resources/assets/vue/components/bookings/forms/PaymentVerificationFormComponent.vue @@ -118,11 +118,11 @@ }, methods: { submitForm(){ - this.parameters = { files: this.files, booking_id: this.id, company_id: this.data.booking.company.id, + payment_id: this.data.id, }; this.submit(this.route('api.booking.payment.verification.create', this.id, this.data.id), 'post', this.section, true, true); diff --git a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue index 8658ed59..18e91784 100644 --- a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue @@ -395,8 +395,8 @@ -
- +
+
@@ -538,6 +538,7 @@ attention: false, bearShowing: false, oneSixEightEightServiceIds: [4, 10], + parameters: {} } }, computed: { @@ -580,13 +581,24 @@ this.isLoading = true; this.submit(route('api.booking.show', this.marking), 'get', this.section, false, false) }, - successHandler(response){ - this.$store.dispatch('completeList', {'name': this.section, 'data': []}); - this.isLoading = false; - this.booking = response.payload.data; + successHandler(response, section, payload){ + if(section === this.section + 'CheckTransferRule'){ + window.location.href = route('billplz.bill', payload.payment_reference); + } + else + { + this.$store.dispatch('completeList', {'name': this.section, 'data': []}); + this.isLoading = false; + this.booking = response.payload.data; + } }, - errorHandler(){ - window.location.href = this.route('dashboard') + errorHandler(response, statusCode, section){ + if(section === this.section + 'CheckTransferRule' && statusCode === 422){ + console.log('Transfer expired, please create new transfer'); + } + else{ + window.location.href = this.route('dashboard'); + } }, updateDefaultAddress(){ this.addressEdit = false; @@ -594,7 +606,15 @@ }, selectedID(id){ this.selected_id = id; - } + }, + checkTransferRule(item){ + this.parameters = { + booking_id: item.booking.id, + company_id: item.booking.company.id, + payment_reference: item.payment_reference, + }; + this.submit(route('api.rule.check.transfer'), 'post', this.section + 'CheckTransferRule', false, true); + }, } } diff --git a/resources/assets/vue/general/mixins/request.js b/resources/assets/vue/general/mixins/request.js index f8348b8a..2b388524 100644 --- a/resources/assets/vue/general/mixins/request.js +++ b/resources/assets/vue/general/mixins/request.js @@ -41,7 +41,7 @@ export default { } successNotification ? this.$store.dispatch('createNotification', { title: response.title, message: response.message, type: 'success' }) : null; - this.successHandler(response, section) + this.successHandler(response, section, this.parameters); });