From 99f70a6127e9fdcec8fcae4827303b82a9a4b9f1 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Wed, 29 Oct 2025 15:44:38 +0800 Subject: [PATCH] Period Lock - prototype --- .../CreateBookingLockLogic.php | 83 +++++++ .../DeleteBookingLockLogic.php | 67 ++++++ .../UpdateBookingAmountLogic.php | 35 ++- .../CheckTransferPeriodLockRuleLogic.php | 66 ++++++ .../CheckTransferPeriodLockRuleDTO.php | 25 ++ ...CheckTransferPeriodLockRuleVariant2DTO.php | 22 ++ .../Rules/CanPassTransferPeriodLockRule.php | 60 +++++ .../CreatePaymentProofDocumentLogic.php | 12 + app/Classes/ValueObjects/Constants/KVPKey.php | 4 +- .../Bookings/CreateBookingLockController.php | 19 ++ .../Bookings/DeleteBookingLockController.php | 19 ++ .../Controllers/Rules/CheckRuleController.php | 10 + app/Http/Resources/TransactionResource.php | 12 +- .../BookingDetailsSectionComponent.vue | 56 ++++- .../components/settings/elements/PageLock.vue | 216 ++++++++++++++++++ routes/booking.php | 4 + routes/rule.php | 2 + 17 files changed, 695 insertions(+), 17 deletions(-) create mode 100644 app/Classes/Modules/Bookings/ControllersLogic/CreateBookingLockLogic.php create mode 100644 app/Classes/Modules/Bookings/ControllersLogic/DeleteBookingLockLogic.php create mode 100644 app/Classes/Modules/Rules/ControllersLogic/CheckTransferPeriodLockRuleLogic.php create mode 100644 app/Classes/Modules/Rules/DataTransferObjects/CheckTransferPeriodLockRuleDTO.php create mode 100644 app/Classes/Modules/Rules/DataTransferObjects/CheckTransferPeriodLockRuleVariant2DTO.php create mode 100644 app/Classes/Modules/Rules/Standards/Rules/CanPassTransferPeriodLockRule.php create mode 100644 app/Http/Controllers/Bookings/CreateBookingLockController.php create mode 100644 app/Http/Controllers/Bookings/DeleteBookingLockController.php create mode 100644 resources/assets/vue/components/settings/elements/PageLock.vue diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingLockLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingLockLogic.php new file mode 100644 index 00000000..42fb4a76 --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingLockLogic.php @@ -0,0 +1,83 @@ + 'Booking Locked', + 'message' => 'You have successfully lock Booking from editing' + ]; + } + + /** @var CanCreateBooking */ + private $canCreateBooking; + + /** @var FetchesBooking */ + private $fetchesBooking; + + + /** @var FetchesCompany */ + private $fetchesCompany; + + /** @var CreatesKeyValuePair */ + private $createsKeyValuePair; + + /** + * CreateBookingLockLogic constructor. + * @param CanCreateBooking $canCreateBooking + * @param FetchesCompany $fetchesCompany + * @param CreatesKeyValuePair $createsKeyValuePair + * @param FetchesBooking $fetchesBooking + */ + public function __construct(CanCreateBooking $canCreateBooking, FetchesCompany $fetchesCompany, CreatesKeyValuePair $createsKeyValuePair, FetchesBooking $fetchesBooking) + { + $this->canCreateBooking = $canCreateBooking; + $this->fetchesCompany = $fetchesCompany; + $this->createsKeyValuePair = $createsKeyValuePair; + $this->fetchesBooking = $fetchesBooking; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\AccessForbiddenException + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\RequestValidationException + */ + public function logic(Request $request) : JsonResponse + { + // $password = $request->input('password'); + // if($password !== 'prototype'){ + // throw new AccessForbiddenException('Incorrect Password'); + // } + + $booking = $this->fetchesBooking->execute(['id' => $request->input('booking_id')]); + $this->updateOrCreateKeyValuePair($booking, KVPKey::BOOKING_IS_LOCKED, 1); + + return $this->response([]); + } + + private function updateOrCreateKeyValuePair($booking, $key, $value) + { + $booking->attributesKVP()->updateOrCreate( + ['key' => $key], + ['value' => $value] + ); + } +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/DeleteBookingLockLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/DeleteBookingLockLogic.php new file mode 100644 index 00000000..90844ade --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/DeleteBookingLockLogic.php @@ -0,0 +1,67 @@ + 'Booking Unlock', + 'message' => 'You have successfully unlock the Booking for editing' + ]; + } + + /** @var CanDeleteBooking */ + private $canDeleteBooking; + + /** @var DeletesBooking */ + private $deletesBooking; + + /** @var FetchesBooking */ + private $fetchesBooking; + + + public function __construct( + CanDeleteBooking $canDeleteBooking, + DeletesBooking $deletesBooking, + FetchesBooking $fetchesBooking + ) + { + $this->canDeleteBooking = $canDeleteBooking; + $this->deletesBooking = $deletesBooking; + $this->fetchesBooking = $fetchesBooking; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws AccessForbiddenException + */ + public function logic(Request $request) : JsonResponse + { + $password = $request->input('password'); + if($password !== 'prototype'){ + throw new AccessForbiddenException('Incorrect Password'); + } + + $booking = $this->fetchesBooking->execute(['id' => $request->route('id')]); + $booking->attributesKVP()->where('key', KVPKey::BOOKING_IS_LOCKED)->delete(); + + return $this->response([]); + } + +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php index fd4af7f8..695aafd0 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php @@ -14,13 +14,16 @@ use App\Classes\Modules\Bookings\Services\FetchesBooking; use App\Classes\Modules\Bookings\Standards\Rules\CanUpdateBooking; use App\Classes\Modules\Bookings\DataTransferObjects\BookingObject; +use App\Classes\Modules\Rules\DataTransferObjects\CheckTransferPeriodLockRuleVariant2DTO; use App\Classes\Modules\Bookings\Services\CalculatesBookingOutstanding; - +use App\Classes\Modules\Rules\Services\RuleEvaluator; +use App\Classes\Modules\Rules\Standards\Rules\CanPassTransferPeriodLockRule; use ErrorException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; use App\Classes\Exceptions\MalformedRequestException; +use App\Classes\Exceptions\CriteriaNotFulfilledException; use Illuminate\Support\Facades\Log; class UpdateBookingAmountLogic extends AbstractControllerLogic @@ -52,6 +55,12 @@ class UpdateBookingAmountLogic extends AbstractControllerLogic /** @var UpdatesTransactionStatus */ private $updatesTransactionStatus; + /** @var RuleEvaluator */ + private $ruleEvaluator; + + /** @var CanPassTransferPeriodLockRule */ + private $canPassTransferPeriodLockRule; + /** * UpdateBookingAmountLogic constructor. * @param CanUpdateBooking $canUpdateBooking @@ -59,29 +68,47 @@ class UpdateBookingAmountLogic extends AbstractControllerLogic * @param FetchesBooking $fetchesBooking * @param CalculatesBookingOutstanding $calculatesBookingOutstanding * @param UpdatesTransactionStatus $updatesTransactionStatus + * @param RuleEvaluator $ruleEvaluator + * @param CanPassTransferPeriodLockRule $canPassTransferPeriodLockRule */ - public function __construct(CanUpdateBooking $canUpdateBooking, UpdatesBookingFixedAmount $updatesBookingFixedAmount, FetchesBooking $fetchesBooking, CalculatesBookingOutstanding $calculatesBookingOutstanding, UpdatesTransactionStatus $updatesTransactionStatus) + public function __construct(CanUpdateBooking $canUpdateBooking, UpdatesBookingFixedAmount $updatesBookingFixedAmount, FetchesBooking $fetchesBooking, CalculatesBookingOutstanding $calculatesBookingOutstanding, UpdatesTransactionStatus $updatesTransactionStatus, RuleEvaluator $ruleEvaluator, CanPassTransferPeriodLockRule $canPassTransferPeriodLockRule) { $this->canUpdateBooking = $canUpdateBooking; $this->updatesBookingFixedAmount = $updatesBookingFixedAmount; $this->fetchesBooking = $fetchesBooking; $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; $this->updatesTransactionStatus = $updatesTransactionStatus; + $this->ruleEvaluator = $ruleEvaluator; + $this->canPassTransferPeriodLockRule = $canPassTransferPeriodLockRule; } /** * @param Request $request * @return JsonResponse * @throws MalformedRequestException + * @throws CriteriaNotFulfilledException */ public function logic(Request $request) : JsonResponse { + //cief todo: Prototype Period Lock - Starts + $reqData['id'] = $request->route('id'); + $dto = new CheckTransferPeriodLockRuleVariant2DTO($reqData); + + $result = $this->ruleEvaluator->evaluate([ + $this->canPassTransferPeriodLockRule, + ], $dto); + + if ($result->failed()) { + throw new CriteriaNotFulfilledException("- " . implode("
- ", $result->messages())); + } + //cief todo: Prototype Period Lock - Ends + $booking = $this->fetchesBooking->execute(['id' => $request->route('id')]); $input_amount = number_format( floatval(str_replace(',', '', $request->input('fix_amount', $booking->fix_amount))), 5, '.', ''); $minimum_amount = $booking->fix_amount - $this->calculatesBookingOutstanding->execute($booking); - + if (((float)$input_amount + 0.01) < (float)$minimum_amount) { $input_amount = 0; // throw new MalformedRequestException('Booking Amount cannot be less than '. $minimum_amount .'.'); @@ -100,4 +127,4 @@ class UpdateBookingAmountLogic extends AbstractControllerLogic return $this->resourceResponse(new BookingResource($booking)); } -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Rules/ControllersLogic/CheckTransferPeriodLockRuleLogic.php b/app/Classes/Modules/Rules/ControllersLogic/CheckTransferPeriodLockRuleLogic.php new file mode 100644 index 00000000..b30da3da --- /dev/null +++ b/app/Classes/Modules/Rules/ControllersLogic/CheckTransferPeriodLockRuleLogic.php @@ -0,0 +1,66 @@ + 'Rule Check Transfer Period Lock', + 'message' => 'You have successfully passed all rules evaluated' + ]; + } + + /** @var RuleEvaluator */ + private $ruleEvaluator; + + /** @var CanPassTransferPeriodLockRule */ + private $canPassTransferPeriodLockRule; + + /** + * CheckTransferPeriodLockRuleLogic constructor. + * @param RuleEvaluator $ruleEvaluator + * @param CanPassTransferPeriodLockRule $canPassTransferPeriodLockRule + */ + public function __construct(RuleEvaluator $ruleEvaluator, CanPassTransferPeriodLockRule $canPassTransferPeriodLockRule) + { + $this->ruleEvaluator = $ruleEvaluator; + $this->canPassTransferPeriodLockRule = $canPassTransferPeriodLockRule; + } + + /** + * @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 CheckTransferPeriodLockRuleDTO($request->all()); + + $result = $this->ruleEvaluator->evaluate([ + $this->canPassTransferPeriodLockRule, + ], $dto); + + if ($result->failed()) { + throw new CriteriaNotFulfilledException("- " . implode("
- ", $result->messages())); + } + + return $this->resourceResponse(new RuleResource((object)$result)); + } +} diff --git a/app/Classes/Modules/Rules/DataTransferObjects/CheckTransferPeriodLockRuleDTO.php b/app/Classes/Modules/Rules/DataTransferObjects/CheckTransferPeriodLockRuleDTO.php new file mode 100644 index 00000000..9b970f04 --- /dev/null +++ b/app/Classes/Modules/Rules/DataTransferObjects/CheckTransferPeriodLockRuleDTO.php @@ -0,0 +1,25 @@ +bookingId = $data['booking_id']; + $this->companyId = $data['company_id']; + } + + public function toArray(): array + { + return [ + 'booking_id' => $this->bookingId, + 'company_id' => $this->companyId, + ]; + } +} diff --git a/app/Classes/Modules/Rules/DataTransferObjects/CheckTransferPeriodLockRuleVariant2DTO.php b/app/Classes/Modules/Rules/DataTransferObjects/CheckTransferPeriodLockRuleVariant2DTO.php new file mode 100644 index 00000000..ffc8d967 --- /dev/null +++ b/app/Classes/Modules/Rules/DataTransferObjects/CheckTransferPeriodLockRuleVariant2DTO.php @@ -0,0 +1,22 @@ +bookingId = $data['id']; + } + + public function toArray(): array + { + return [ + 'id' => $this->bookingId, + ]; + } +} diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanPassTransferPeriodLockRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassTransferPeriodLockRule.php new file mode 100644 index 00000000..54cb66e2 --- /dev/null +++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassTransferPeriodLockRule.php @@ -0,0 +1,60 @@ +fetchesBooking = $fetchesBooking; + } + + /** + * @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 + { + $booking = $this->fetchesBooking->execute(['id' => $object->bookingId]); + $bookingAttribute = $booking->attributesKVP()->where('key', KVPKey::BOOKING_IS_LOCKED)->first(); + + if($bookingAttribute && in_array(Auth::user()->type, RoleTypes::ADMIN_ROLES)){ + throw new CriteriaNotFulfilledException("Booking is locked for edit."); + } + return true; + } +} diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php index fdaf5e75..baed9a8f 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php @@ -16,6 +16,7 @@ use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\CompanyType; use App\Classes\ValueObjects\Constants\DocumentType; use App\Classes\Jobs\SendUserPaymentProofUploadedEmail; +use App\Classes\ValueObjects\Constants\KVPKey; use App\Models\Company; use App\Models\Document; use Illuminate\Http\JsonResponse; @@ -92,6 +93,10 @@ class CreatePaymentProofDocumentLogic extends AbstractControllerLogic $this->createInvoiceTransactionProcessor->execute($transaction->owner->booking); + //cief todo: Prototype Period Lock - Starts + $this->updateOrCreateKeyValuePair($transaction->owner->booking, KVPKey::BOOKING_IS_LOCKED, 1); + //cief todo: Prototype Period Lock - Ends + // send email to customer // todo: a function to send a proof to the receipiant, they have to give us a email of the receipiant and also need to submiited purchase order $companyEmployee = $transaction->owner->booking->company->employees; @@ -104,4 +109,11 @@ class CreatePaymentProofDocumentLogic extends AbstractControllerLogic return $this->response([]); } + private function updateOrCreateKeyValuePair($booking, $key, $value) + { + $booking->attributesKVP()->updateOrCreate( + ['key' => $key], + ['value' => $value] + ); + } } diff --git a/app/Classes/ValueObjects/Constants/KVPKey.php b/app/Classes/ValueObjects/Constants/KVPKey.php index 97703206..f49e6f3f 100644 --- a/app/Classes/ValueObjects/Constants/KVPKey.php +++ b/app/Classes/ValueObjects/Constants/KVPKey.php @@ -11,7 +11,7 @@ class KVPKey public const AUTOCOUNT_DOCNO_OFFICIAL_RECEIPT = 'AUTOCOUNT_DOCNO_OR'; public const AUTOCOUNT_DOCDATE_INVOICE = 'AUTOCOUNT_DOCDATE_I'; - + public const AUTOCOUNT_DOCNO_CREDIT_NOTE = 'AUTOCOUNT_DOCNO_CN'; public const AUTOCOUNT_EINVOICE_VALIDATION_LINK = 'AUTOCOUNT_EINVOICE_VALIDATION_LINK'; @@ -24,4 +24,6 @@ class KVPKey public const BOOKING_EINVOICE_ELIGIBLE = 'BOOKING_EINVOICE_ELIGIBLE'; + public const BOOKING_IS_LOCKED = 'BOOKING_IS_LOCKED'; + } diff --git a/app/Http/Controllers/Bookings/CreateBookingLockController.php b/app/Http/Controllers/Bookings/CreateBookingLockController.php new file mode 100644 index 00000000..98cba114 --- /dev/null +++ b/app/Http/Controllers/Bookings/CreateBookingLockController.php @@ -0,0 +1,19 @@ +execute($request); + } +} diff --git a/app/Http/Controllers/Bookings/DeleteBookingLockController.php b/app/Http/Controllers/Bookings/DeleteBookingLockController.php new file mode 100644 index 00000000..89cbf7fe --- /dev/null +++ b/app/Http/Controllers/Bookings/DeleteBookingLockController.php @@ -0,0 +1,19 @@ +execute($request); + } +} diff --git a/app/Http/Controllers/Rules/CheckRuleController.php b/app/Http/Controllers/Rules/CheckRuleController.php index 59b24cd0..0df00313 100644 --- a/app/Http/Controllers/Rules/CheckRuleController.php +++ b/app/Http/Controllers/Rules/CheckRuleController.php @@ -5,6 +5,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 App\Classes\Modules\Rules\ControllersLogic\CheckTransferPeriodLockRuleLogic; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -36,4 +37,13 @@ class CheckRuleController public function checkTransferRule(Request $request, CheckTransferRuleLogic $logic): JsonResponse { return $logic->execute($request); } + + /** + * @param Request $request + * @param CheckTransferPeriodLockRuleLogic $logic + * @return JsonResponse + */ + public function checkTransferPeriodLockRule(Request $request, CheckTransferPeriodLockRuleLogic $logic): JsonResponse { + return $logic->execute($request); + } } diff --git a/app/Http/Resources/TransactionResource.php b/app/Http/Resources/TransactionResource.php index 172c29fd..de3fe122 100644 --- a/app/Http/Resources/TransactionResource.php +++ b/app/Http/Resources/TransactionResource.php @@ -42,11 +42,13 @@ class TransactionResource extends JsonResource $eInvoice = false; if($booking && $this->type === TransactionType::REFUND){ $kvp = $this->attributesKVP()->where('key', KVPKey::TRANSACTION_MODEL_CLASS)->first(); - $transactionCreditNote = Transaction::where('id', $kvp->value)->first(); - if($transactionCreditNote){ - $kvp = $transactionCreditNote->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE)->first(); - if($kvp){ - $eInvoice = true; + if($kvp){ + $transactionCreditNote = Transaction::where('id', $kvp->value)->first(); + if($transactionCreditNote){ + $kvp = $transactionCreditNote->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO_CREDIT_NOTE)->first(); + if($kvp){ + $eInvoice = true; + } } } } diff --git a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue index bc5f3dca..2055e6b7 100644 --- a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue @@ -1,6 +1,21 @@