From 6cfa6f8d75c76649dcde03a8fd4022590f916b71 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Sun, 8 Jun 2025 03:52:14 +0800 Subject: [PATCH] E-Invoice - Partial completion of => Doc Delivery - E-INVOICE, E-CN, E-RN + Edit Booking Amount (3.0) --- .../UpdateBookingAmountOnHoldLogic.php | 115 ++++++++++++++++++ .../UpdateBookingAmountWithPOLogic.php | 78 ++++++++++++ .../CreatePurchaseOrderTransactionLogic.php | 5 +- .../UpdateBookingAmountController.php | 11 +- ...eatePurchaseOrderTransactionController.php | 12 +- app/Models/Booking.php | 11 +- .../elements/PaymentHistoryComponent.vue | 18 +-- .../EditBookingAmountFormV2Component.vue | 69 +++++++++++ routes/booking.php | 2 + 9 files changed, 300 insertions(+), 21 deletions(-) create mode 100644 app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php create mode 100644 app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php create mode 100644 resources/assets/vue/components/bookings/forms/EditBookingAmountFormV2Component.vue diff --git a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php new file mode 100644 index 00000000..39dc6674 --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php @@ -0,0 +1,115 @@ + 'Recorded Booking Amount', + 'message' => 'You have successfully recorded the Booking Amount to be updated' + ]; + } + + /** @var CanUpdateBooking */ + private $canUpdateBooking; + + /** @var UpdatesBookingFixedAmount */ + private $updatesBookingFixedAmount; + + /** @var FetchesBooking */ + private $fetchesBooking; + + /** @var CalculatesBookingOutstanding */ + private $calculatesBookingOutstanding; + + /** @var UpdatesTransactionStatus */ + private $updatesTransactionStatus; + + /** @var CreatesKeyValuePair */ + private $createsKeyValuePair; + + /** @var UpdatesKeyValuePair */ + private $updatesKeyValuePair; + + /** + * UpdateBookingAmountLogic constructor. + * @param CanUpdateBooking $canUpdateBooking + * @param UpdatesBookingFixedAmount $updatesBookingFixedAmount + * @param FetchesBooking $fetchesBooking + * @param CalculatesBookingOutstanding $calculatesBookingOutstanding + * @param UpdatesTransactionStatus $updatesTransactionStatus + * @param CreatesKeyValuePair $createsKeyValuePair + * @param UpdatesKeyValuePair $updatesKeyValuePair + */ + public function __construct(CanUpdateBooking $canUpdateBooking, UpdatesBookingFixedAmount $updatesBookingFixedAmount, FetchesBooking $fetchesBooking, CalculatesBookingOutstanding $calculatesBookingOutstanding, UpdatesTransactionStatus $updatesTransactionStatus, CreatesKeyValuePair $createsKeyValuePair, UpdatesKeyValuePair $updatesKeyValuePair) + { + $this->canUpdateBooking = $canUpdateBooking; + $this->updatesBookingFixedAmount = $updatesBookingFixedAmount; + $this->fetchesBooking = $fetchesBooking; + $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; + $this->updatesTransactionStatus = $updatesTransactionStatus; + $this->createsKeyValuePair = $createsKeyValuePair; + $this->updatesKeyValuePair = $updatesKeyValuePair; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws MalformedRequestException + */ + public function logic(Request $request) : JsonResponse + { + $booking = $this->fetchesBooking->execute(['id' => $request->route('id')]); + + $input_amount = number_format( floatval(str_replace(',', '', $request->input('amount_to_edit', $booking->fix_amount))), 5, '.', ''); + + $minimum_amount = $booking->fix_amount - $this->calculatesBookingOutstanding->execute($booking); + + if (((float)$input_amount + 0.01) < (float)$minimum_amount) { + throw new MalformedRequestException('Booking Amount cannot be less than '. $minimum_amount .'.'); + } + + $key = "BOOKING_AMOUNT_UPDATE"; + $keyValuePairObject = new KeyValuePairObject($key, $input_amount); + $metadata = $booking->attributesKVP()->where('key', $key)->first(); + if($metadata){ + $this->updatesKeyValuePair->execute($metadata, $keyValuePairObject); + } + else{ + $this->createsKeyValuePair->execute($booking, $keyValuePairObject); + } + + $poTransaction = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first(); + // $booking->transactions()->where('type', TransactionType::PROFORMA)->delete(); + + if($poTransaction) { + $this->updatesTransactionStatus->execute($poTransaction, ApprovalStatus::PENDING_SUBMISSION); + } + + // $booking = $this->updatesBookingFixedAmount->execute($booking, $input_amount); + + return $this->resourceResponse(new BookingResource($booking)); + } + +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php new file mode 100644 index 00000000..eaa477a5 --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php @@ -0,0 +1,78 @@ + 'Update Purchase Order With Booking Amount Update', + 'message' => 'You have successfully updated booking amount' + ]; + } + + /** @var FetchesBooking */ + private $fetchesBooking; + + /** @var UpdatesBookingFixedAmount */ + private $updatesBookingFixedAmount; + + /** + * UpdateBookingAmountWithPOLogic constructor. + * @param FetchesBooking $fetchesBooking + * @param UpdatesBookingFixedAmount $updatesBookingFixedAmount + */ + public function __construct(FetchesBooking $fetchesBooking, UpdatesBookingFixedAmount $updatesBookingFixedAmount) + { + $this->fetchesBooking = $fetchesBooking; + $this->updatesBookingFixedAmount = $updatesBookingFixedAmount; + } + + /** + * @param Request $request + * @param string $id + * @return JsonResponse + * @throws \App\Classes\Exceptions\MalformedRequestException + * @throws \App\Classes\Exceptions\CriteriaNotFulfilledException + */ + public function logic(Request $request, $id = '') : JsonResponse + { + /** @var Booking $booking */ + $booking = $this->fetchesBooking->execute(['id' => $request->route('id') ?? $id]); + $bookingAttribute = $booking->attributesKVP()->where('key', "BOOKING_AMOUNT_UPDATE")->first(); + + if($bookingAttribute){ + $total = collect($request->input('products'))->sum(function($product){ + return $product['quantity'] * floatval(str_replace(',', '', $product['unit_price'])); + }); + $bookingAmountUpdate = (float)$bookingAttribute->value; + $isTally = $total === $bookingAmountUpdate ? true : false; + if(!$isTally){ + throw new MalformedRequestException('Purchase Order total not tally with updated booking amount of ' . $bookingAmountUpdate); + } + $booking->transactions()->where('type', TransactionType::PROFORMA)->delete(); + $booking = $this->updatesBookingFixedAmount->execute($booking, $bookingAmountUpdate); + + $request->merge(['is_privilleged_update' => true]); + + $bookingAttribute->delete(); + } + + return $this->resourceResponse(new BookingResource($booking)); + } +} diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php index 59757fa1..d5d97536 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php @@ -39,7 +39,7 @@ class CreatePurchaseOrderTransactionLogic extends AbstractControllerLogic protected function notification():array { return [ 'title' => 'Update Purchase Order', - 'message' => 'You have successfully updated you booking\'s purchase order' + 'message' => 'You have successfully updated your booking\'s purchase order' ]; } @@ -84,7 +84,8 @@ class CreatePurchaseOrderTransactionLogic extends AbstractControllerLogic */ public function logic(Request $request, $id = '') : JsonResponse { - if(!in_array(Auth::user()->type, RoleTypes::ADMIN_ROLES)){ + //This checking is excluded for (1) Admin, (2) Update of booking amount post payment as user + if(!in_array(Auth::user()->type, RoleTypes::ADMIN_ROLES) && !$request->has('is_privilleged_update')){ $dto = new CreatePurchaseOrderDTO($request->all()); $result = $this->ruleEvaluator->evaluate([ $this->canPassEditingPORule diff --git a/app/Http/Controllers/Bookings/UpdateBookingAmountController.php b/app/Http/Controllers/Bookings/UpdateBookingAmountController.php index d0f6dd6c..394d4039 100644 --- a/app/Http/Controllers/Bookings/UpdateBookingAmountController.php +++ b/app/Http/Controllers/Bookings/UpdateBookingAmountController.php @@ -3,6 +3,7 @@ namespace App\Http\Controllers\Bookings; use App\Classes\Modules\Bookings\ControllersLogic\UpdateBookingAmountLogic; +use App\Classes\Modules\Bookings\ControllersLogic\UpdateBookingAmountOnHoldLogic; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -17,4 +18,12 @@ class UpdateBookingAmountController return $logic->execute($request); } -} \ No newline at end of file + /** + * @param Request $request + * @param UpdateBookingAmountOnHoldLogic $logic + * @return JsonResponse + */ + public function updateOnHold(Request $request, UpdateBookingAmountOnHoldLogic $logic): JsonResponse { + return $logic->execute($request); + } +} diff --git a/app/Http/Controllers/Transactions/CreatePurchaseOrderTransactionController.php b/app/Http/Controllers/Transactions/CreatePurchaseOrderTransactionController.php index 67a74537..625f1afe 100644 --- a/app/Http/Controllers/Transactions/CreatePurchaseOrderTransactionController.php +++ b/app/Http/Controllers/Transactions/CreatePurchaseOrderTransactionController.php @@ -6,6 +6,8 @@ namespace App\Http\Controllers\Transactions; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use App\Classes\Modules\Transactions\ControllersLogic\CreatePurchaseOrderTransactionLogic; +use App\Classes\Modules\Bookings\ControllersLogic\UpdateBookingAmountWithPOLogic; + class CreatePurchaseOrderTransactionController @@ -15,7 +17,13 @@ class CreatePurchaseOrderTransactionController * @param CreatePurchaseOrderTransactionLogic $logic * @return JsonResponse */ - public function create(Request $request, CreatePurchaseOrderTransactionLogic $logic) : JsonResponse { - return $logic->execute($request); + public function create(Request $request, CreatePurchaseOrderTransactionLogic $createLogic, UpdateBookingAmountWithPOLogic $updateLogic) : JsonResponse { + // return $logic->execute($request); + $updateResult = $updateLogic->execute($request); + + if ($updateResult instanceof JsonResponse && $updateResult->getStatusCode() !== 200) { + return $updateResult; + } + return $createLogic->execute($request); } } diff --git a/app/Models/Booking.php b/app/Models/Booking.php index 259ca01e..d488c1e4 100644 --- a/app/Models/Booking.php +++ b/app/Models/Booking.php @@ -3,6 +3,7 @@ namespace App\Models; use App\Classes\General\Interfaces\Documentable; +use App\Classes\General\Interfaces\KeyValueInterface; use App\Classes\General\Interfaces\Transactionable; use App\Classes\General\Interfaces\Voucherifiable; use App\Classes\General\Traits\LogData; @@ -26,7 +27,7 @@ use Staudenmeir\EloquentHasManyDeep\HasRelationships; * @property int convertible_currency_id * @property int conversion_currency_id */ -class Booking extends AbstractModel implements Documentable, Transactionable, Voucherifiable +class Booking extends AbstractModel implements Documentable, Transactionable, Voucherifiable, KeyValueInterface { use HasRelationships; use SoftDeletes; @@ -130,4 +131,12 @@ class Booking extends AbstractModel implements Documentable, Transactionable, Vo return $this->morphMany(VoucherEntityMapping::class, 'owner'); } + /** + * @return MorphMany + */ + public function attributesKVP(): MorphMany + { + return $this->morphMany(KeyValuePair::class, 'owner'); + } + } diff --git a/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue b/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue index f7d1f91e..53007c6b 100644 --- a/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue +++ b/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue @@ -336,7 +336,8 @@
{{this.data.fixed_currency.short_code}} {{(Math.round((this.data.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
--> - + + @@ -402,8 +403,7 @@ - -
+
Amount
{{refund.currency.short_code}} {{(Math.round((refund.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
@@ -422,18 +422,6 @@
- - -
-
Amount
-
-
{{refund.currency.short_code}} {{(Math.round((refund.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
-
-
-
{{refund.original_currency.short_code}} {{(Math.round((refund.original_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
-
-
-
diff --git a/resources/assets/vue/components/bookings/forms/EditBookingAmountFormV2Component.vue b/resources/assets/vue/components/bookings/forms/EditBookingAmountFormV2Component.vue new file mode 100644 index 00000000..a7001a99 --- /dev/null +++ b/resources/assets/vue/components/bookings/forms/EditBookingAmountFormV2Component.vue @@ -0,0 +1,69 @@ + + diff --git a/routes/booking.php b/routes/booking.php index e0a79fa1..e305276b 100644 --- a/routes/booking.php +++ b/routes/booking.php @@ -2,6 +2,7 @@ use App\Http\Controllers\Bookings\RegenerateBookingPaymentRVController; use App\Http\Controllers\Bookings\RegenerateBookingEInvoiceController; +use App\Http\Controllers\Bookings\UpdateBookingAmountController; use Illuminate\Support\Facades\Route; Route::group(['prefix' => 'booking', 'as' => 'booking.', 'namespace' => 'Bookings'], function () { @@ -36,6 +37,7 @@ Route::group(['prefix' => 'booking', 'as' => 'booking.', 'namespace' => 'Booking Route::delete('{id}/purchase_order/pdf', 'DeletePurchaseOrderPdfController@delete')->name('po.pdf.delete'); Route::put('{id}/updateAmount', 'UpdateBookingAmountController@update')->name('booking_amount.update'); + Route::put('{id}/updateAmountWithPO', [UpdateBookingAmountController::class, 'updateOnHold'])->name('amount.update'); Route::put('{id}/updateOrderReferences', 'UpdateBookingOrderReferenceController@update')->name('booking_order_reference.update'); Route::post('/merge', 'MergeBookingController@merge')->name('merge');