mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-19 04:23:55 +00:00
E-Invoice - New business rule, transfer now has duration limit (Payment attempt duration limit)
This commit is contained in:
@@ -24,6 +24,7 @@ use App\Classes\Modules\Transactions\Processors\CreateCashBackTransactionProcess
|
||||
use App\Classes\Modules\Vouchers\Processors\Voucherify\BookingToVoucherifyProcessor;
|
||||
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\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\PaymentMethodType;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
@@ -131,6 +132,7 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic
|
||||
{
|
||||
$dto = new ConfirmBookingDTO($request->all());
|
||||
$result = $this->ruleEvaluator->evaluate([
|
||||
App()->make(CanPassOrderDurationLimitRule::class),
|
||||
App()->make(CanPassEInvoicePromptedRule::class),
|
||||
App()->make(CanPassTINRule::class),
|
||||
App()->make(CanPassPurchaseOrderRule::class),
|
||||
|
||||
@@ -8,6 +8,7 @@ use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Modules\Rules\DataTransferObjects\CheckPurchaseOrderRuleDTO;
|
||||
use App\Classes\Modules\Rules\Services\RuleEvaluator;
|
||||
use App\Classes\Modules\Rules\Standards\Rules\CanPassEInvoicePromptedRule;
|
||||
use App\Classes\Modules\Rules\Standards\Rules\CanPassOrderDurationLimitRule;
|
||||
use App\Classes\Modules\Rules\Standards\Rules\CanPassPurchaseOrderRule;
|
||||
use App\Http\Resources\RuleResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
@@ -49,6 +50,7 @@ class CheckPurchaseOrderRuleLogic extends AbstractControllerLogic
|
||||
$dto = new CheckPurchaseOrderRuleDTO($request->all());
|
||||
|
||||
$result = $this->ruleEvaluator->evaluate([
|
||||
App()->make(CanPassOrderDurationLimitRule::class),
|
||||
App()->make(CanPassEInvoicePromptedRule::class),
|
||||
App()->make(CanPassPurchaseOrderRule::class),
|
||||
], $dto);
|
||||
|
||||
@@ -0,0 +1,60 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Rules\ControllersLogic;
|
||||
|
||||
|
||||
use App\Classes\Exceptions\CriteriaNotFulfilledException;
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Modules\Rules\DataTransferObjects\CheckTransferRuleDTO;
|
||||
use App\Classes\Modules\Rules\Services\RuleEvaluator;
|
||||
use App\Classes\Modules\Rules\Standards\Rules\CanPassOrderDurationLimitRule;
|
||||
use App\Http\Resources\RuleResource;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class CheckTransferRuleLogic extends AbstractControllerLogic
|
||||
{
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function notification():array {
|
||||
return [
|
||||
'title' => 'Rule Check Transfer',
|
||||
'message' => 'You have successfully passed all rules evaluated'
|
||||
];
|
||||
}
|
||||
|
||||
/** @var RuleEvaluator */
|
||||
private $ruleEvaluator;
|
||||
|
||||
/**
|
||||
* CheckTransferRuleLogic constructor.
|
||||
*/
|
||||
public function __construct(RuleEvaluator $ruleEvaluator)
|
||||
{
|
||||
$this->ruleEvaluator = $ruleEvaluator;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
* @throws \App\Classes\Exceptions\AccessForbiddenException
|
||||
* @throws \App\Classes\Exceptions\MalformedRequestException
|
||||
* @throws \App\Classes\Exceptions\RequestValidationException
|
||||
* @throws \App\Classes\Exceptions\CriteriaNotFulfilledException
|
||||
*/
|
||||
public function logic(Request $request) : JsonResponse
|
||||
{
|
||||
$dto = new CheckTransferRuleDTO($request->all());
|
||||
|
||||
$result = $this->ruleEvaluator->evaluate([
|
||||
App()->make(CanPassOrderDurationLimitRule::class),
|
||||
], $dto);
|
||||
|
||||
if ($result->failed()) {
|
||||
throw new CriteriaNotFulfilledException("- " . implode("<br>- ", $result->messages()));
|
||||
}
|
||||
|
||||
return $this->resourceResponse(new RuleResource((object)$result));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Rules\DataTransferObjects;
|
||||
|
||||
use App\Classes\General\Interfaces\DataTransferObject;
|
||||
|
||||
class CheckTransferRuleDTO implements DataTransferObject
|
||||
{
|
||||
public int $bookingId;
|
||||
public int $companyId;
|
||||
|
||||
public function __construct(array $data)
|
||||
{
|
||||
$this->bookingId = $data['booking_id'];
|
||||
$this->companyId = $data['company_id'];
|
||||
}
|
||||
|
||||
public function toArray(): array
|
||||
{
|
||||
return [
|
||||
'booking_id' => $this->bookingId,
|
||||
'company_id' => $this->companyId,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,113 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Rules\Standards\Rules;
|
||||
|
||||
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 Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class CanPassOrderDurationLimitRule extends AbstractRule
|
||||
{
|
||||
|
||||
/** @var FetchesBooking */
|
||||
private $fetchesBooking;
|
||||
|
||||
/** @var FetchesCompanyPaymentAttemptLimit */
|
||||
private $fetchesCompanyPaymentAttemptLimit;
|
||||
|
||||
/**
|
||||
* CanPassOrderDurationLimitRule constructor.
|
||||
* @param FetchesBooking $fetchesBooking
|
||||
* @param FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit
|
||||
*/
|
||||
public function __construct(FetchesBooking $fetchesBooking, FetchesCompanyPaymentAttemptLimit $fetchesCompanyPaymentAttemptLimit)
|
||||
{
|
||||
$this->fetchesBooking = $fetchesBooking;
|
||||
$this->fetchesCompanyPaymentAttemptLimit = $fetchesCompanyPaymentAttemptLimit;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function authorized($object): bool
|
||||
{
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
protected function validators($object): bool
|
||||
{
|
||||
return true;
|
||||
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return bool
|
||||
*/
|
||||
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}");
|
||||
}
|
||||
}
|
||||
|
||||
if($isExpired){
|
||||
throw new CriteriaNotFulfilledException("Transfer has already expired.");
|
||||
}
|
||||
return true;
|
||||
}
|
||||
}
|
||||
@@ -4,6 +4,7 @@ namespace App\Http\Controllers\Rules;
|
||||
|
||||
use App\Classes\Modules\Rules\ControllersLogic\CheckEInvoiceRuleLogic;
|
||||
use App\Classes\Modules\Rules\ControllersLogic\CheckPurchaseOrderRuleLogic;
|
||||
use App\Classes\Modules\Rules\ControllersLogic\CheckTransferRuleLogic;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@@ -26,4 +27,13 @@ class CheckRuleController
|
||||
public function checkPurchaseOrderRule(Request $request, CheckPurchaseOrderRuleLogic $logic): JsonResponse {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param CheckTransferRuleLogic $logic
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function checkTransferRule(Request $request, CheckTransferRuleLogic $logic): JsonResponse {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -53,15 +53,19 @@ class BookingV2Resource extends JsonResource
|
||||
'created_at' => Carbon::parse($this->created_at)->format('d-m-Y'),
|
||||
'created_at_with_time' => Carbon::parse($this->created_at)->format('d-m-Y h:i:s A'),
|
||||
$this->mergeWhen($this->relationLoaded('transactions'), [
|
||||
'purchase_order' => new V2\TransactionV2Resource($this->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first()),
|
||||
'purchase_order' => new V2\TransactionV2Resource(
|
||||
$this->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first()),
|
||||
'payment_attempts' => V2\TransactionV2Resource::collection(
|
||||
$this->transactions()
|
||||
->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)
|
||||
->whereDate('expires_on', '>=', Carbon::now())
|
||||
->get()
|
||||
),
|
||||
'expired_payment_attempts' => V2\TransactionV2Resource::collection($this->transactions()->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString())->get()),
|
||||
'payment_history' => V2\TransactionV2Resource::collection($this->transactions()->where(function($query){
|
||||
'expired_payment_attempts' => V2\TransactionV2Resource::collection(
|
||||
$this->transactions()->payments()->where('status', ApprovalStatus::PENDING_SUBMISSION)->whereDate('expires_on', '>=', Carbon::now())->where('expires_on', '>', Carbon::now()->toTimeString())->get()
|
||||
),
|
||||
'payment_history' => V2\TransactionV2Resource::collection(
|
||||
$this->transactions()->where(function($query){
|
||||
$query->where(function($query){
|
||||
$query->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::REJECTED]);
|
||||
})->orWhere(function($query){
|
||||
|
||||
+14
-3
@@ -708,7 +708,10 @@
|
||||
this.calculation = null;
|
||||
},
|
||||
successHandler(response, section){ //E-Invoice
|
||||
if(section === this.section + 'CheckEInvoiceRule'){
|
||||
if(section === this.section + 'CheckTransferRule'){
|
||||
this.checkEInvoiceRule();
|
||||
}
|
||||
else if(section === this.section + 'CheckEInvoiceRule'){
|
||||
if(response.payload.data.isPassed){
|
||||
this.amount = (Math.round((this.data.outstanding_amount + Number.EPSILON) * 100) / 100).toFixed(2);
|
||||
this.expandPayment = true;
|
||||
@@ -751,7 +754,8 @@
|
||||
$('#modal-einvoice-request').modal('show');
|
||||
}
|
||||
else{
|
||||
this.checkEInvoiceRule();
|
||||
this.checkTransferRule();
|
||||
// this.checkEInvoiceRule();
|
||||
}
|
||||
},
|
||||
cancelQuotation(){
|
||||
@@ -799,6 +803,14 @@
|
||||
}
|
||||
},
|
||||
//E-Invoice - Starts
|
||||
checkTransferRule(){
|
||||
this.error = '';
|
||||
this.parameters = {
|
||||
booking_id: this.data.id,
|
||||
company_id: this.data.company.id,
|
||||
};
|
||||
this.submit(route('api.rule.check.transfer'), 'post', this.section + 'CheckTransferRule', false, true);
|
||||
},
|
||||
checkEInvoiceRule(){
|
||||
this.error = '';
|
||||
this.parameters = {
|
||||
@@ -807,7 +819,6 @@
|
||||
this.submit(route('api.rule.check.einvoice'), 'post', this.section + 'CheckEInvoiceRule', false, true);
|
||||
},
|
||||
checkPurchaseOrderRule(){
|
||||
this.error = '';
|
||||
this.error = '';
|
||||
this.parameters = {
|
||||
booking_id: this.data.id,
|
||||
|
||||
@@ -194,6 +194,7 @@
|
||||
</div>
|
||||
</div>
|
||||
<button class="btn btn-xs all-caps b-rad-none btn-default bg-master-lightest w-100" @click="submitted = false" v-if="(Math.round((data.paid_amount + Number.EPSILON) * 100) / 100) === 0">Edit Purchase Order</button>
|
||||
<!-- <button class="btn btn-xs all-caps b-rad-none btn-default bg-master-lightest w-100" @click="submitted = false" >Edit Purchase Order</button> -->
|
||||
<button class="btn btn-xs all-caps b-rad-none btn-complete w-100 m-t-5" v-if="!data.documents.proforma_invoice && data.outstanding_amount != 0" @click="submit(route('api.booking.proforma.create', data.id), 'post', section, true, true)">Generate Proforma Invoice</button>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -8,4 +8,5 @@ Route::prefix('rule')
|
||||
->group(function () {
|
||||
Route::post('/check/eInvoice', [CheckRuleController::class, 'checkEInvoiceRule'])->name('check.einvoice');
|
||||
Route::post('/check/purchase-order', [CheckRuleController::class, 'checkPurchaseOrderRule'])->name('check.purchase.order');
|
||||
Route::post('/check/tranfer', [CheckRuleController::class, 'checkTransferRule'])->name('check.transfer');
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user