From 01dd8073a13d29d71a06c215583675d6eb8ae291 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Wed, 26 Nov 2025 07:44:11 +0800 Subject: [PATCH 01/22] E-Invoice - Update the conditions for generating Sales Invoice Report --- .../CreateInvoiceTransactionV2CommandJob.php | 42 +++++++++++++++++++ .../Services/ExportsSalesInvoiceReport.php | 8 +++- 2 files changed, 49 insertions(+), 1 deletion(-) create mode 100644 app/Classes/Jobs/Commands/V2/CreateInvoiceTransactionV2CommandJob.php diff --git a/app/Classes/Jobs/Commands/V2/CreateInvoiceTransactionV2CommandJob.php b/app/Classes/Jobs/Commands/V2/CreateInvoiceTransactionV2CommandJob.php new file mode 100644 index 00000000..08576f16 --- /dev/null +++ b/app/Classes/Jobs/Commands/V2/CreateInvoiceTransactionV2CommandJob.php @@ -0,0 +1,42 @@ +booking = $booking; + } + + public function handle() + { + Log::info(Carbon::now() . ': Start job - Creating invoice for single booking.'); + $start = new Carbon(); + + (App()->make(CreateInvoiceTransactionV2Processor::class))->execute($this->booking); + + $end = new Carbon(); + $elapsedTime = $start->diff($end)->format('%H:%I:%S'); + Log::info(Carbon::now() . ': End job - Creating invoice for single booking. ElapsedTime: ' . $elapsedTime . '.'); + } + +} diff --git a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php index 3142441b..ff3f66c2 100644 --- a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php @@ -2,6 +2,7 @@ namespace App\Classes\Modules\Exports\Services; +use App\Classes\Jobs\Commands\V2\CreateInvoiceTransactionV2CommandJob; use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Models\Booking; @@ -71,7 +72,7 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR 'transactions.voucherRedemption', 'transactions.voucherRedemption.voucher.campaign' ]) - ->where('status', ApprovalStatus::COMPLETED) + // ->where('status', ApprovalStatus::COMPLETED) ->whereHas('transactions', function ($query) use ($startDate, $endDate) { $query->payments() ->complete() @@ -115,6 +116,11 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR } $invoiceTransaction = $booking->transactions->where('type', TransactionType::INVOICE)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->first(); + if(!$invoiceTransaction){ + Log::info('ExportsSalesInvoiceReport booking with NO invoice: ' . json_encode($booking)); + // CreateInvoiceTransactionV2CommandJob::dispatch($booking); + return $records; + } $currencyId = $booking->fix_currency_id; From ac3a71627c3ae9ba7d0856c5b90d44acca772745 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 27 Nov 2025 10:31:22 +0800 Subject: [PATCH 02/22] E-Invoice - Update the conditions for generating Sales Invoice Report with business logic update on generating invoice --- .../CreateInvoiceTransactionV2Processor.php | 56 ++++++++++--------- .../forms/PurchaseOrderFormComponent.vue | 23 +++++++- 2 files changed, 52 insertions(+), 27 deletions(-) diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php index 504dece5..619f34b5 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php @@ -105,7 +105,8 @@ class CreateInvoiceTransactionV2Processor } if ($booking->status === ApprovalStatus::COMPLETED && !$generateEInvoiceRefund) { - return; + Log::info('CreateInvoiceTransactionV2Processor Check 1 Bypass New Business Logic Update for booking ' . $booking->id); + // return; } $payable_amount = $this->calculatesBookingPayableAmount->execute($booking, $booking->fix_currency_id, $generateEInvoiceRefund); @@ -117,7 +118,8 @@ class CreateInvoiceTransactionV2Processor } // confirm that all payments has been transferred if ($this->calculatesBookingTransferredAmount->execute($booking) !== $this->calculatesBookingPaidAmount->execute($booking)) { - return; + Log::info('CreateInvoiceTransactionV2Processor Check 2 Bypass New Business Logic Update for booking ' . $booking->id); + // return; } if($generateEInvoiceRefund){ @@ -264,38 +266,40 @@ class CreateInvoiceTransactionV2Processor $transaction = $paymentTransaction->transactions()->where('type', TransactionType::BILL)->first(); } else{ // Special handling for refund cases (When a refund is deleted via DeleteRefundTransactionLogic, a booking payment transaction is set to ApprovalStatus::APPROVED) - $temp = $booking->transactions()->payments()->where('status', ApprovalStatus::APPROVED)->first(); + $paymentTransactionTemp = $booking->transactions()->payments()->where('status', ApprovalStatus::APPROVED)->first(); // Lets check if there is a refund case - $refund = $temp->transactions()->refunds()->where('status', ApprovalStatus::APPROVED)->first(); + $refund = $paymentTransactionTemp->transactions()->refunds()->where('status', ApprovalStatus::APPROVED)->first(); if($refund){ - $transaction = $temp; + $transaction = $paymentTransactionTemp->transactions()->where('type', TransactionType::BILL)->first(); } else{ - throw new Exception("No payment found for booking '$booking->id'."); + Log::info("CreateInvoiceTransactionV2Processor NO completed payment transaction, refund transaction found for booking '$booking->id'."); } } - $transaction_object = new TransactionObject( - $billNumber, - TransactionType::SUPPLIER_DELIVER, - $transaction->issuer, - $transaction->receiver, - $transaction->recipient_bank_account_id, - $transaction->payment_method, - $payable_amount, - $booking_amount, - $transaction->currency_id, - $transaction->original_currency_id, - $booking_currency_average_rate, - $total_tax, - $total_service_charge, - null, - ApprovalStatus::APPROVED - ); - $supplier_deliver_order_transaction = $this->createsTransaction->execute($purchaseOrder->booking, $transaction_object); + if($transaction){ + $transaction_object = new TransactionObject( + $billNumber, + TransactionType::SUPPLIER_DELIVER, + $transaction->issuer, + $transaction->receiver, + $transaction->recipient_bank_account_id, + $transaction->payment_method, + $payable_amount, + $booking_amount, + $transaction->currency_id, + $transaction->original_currency_id, + $booking_currency_average_rate, + $total_tax, + $total_service_charge, + null, + ApprovalStatus::APPROVED + ); + $supplier_deliver_order_transaction = $this->createsTransaction->execute($purchaseOrder->booking, $transaction_object); - // supply deliver order - $this->invoiceDocumentProcessor->execute($supplier_deliver_order_transaction, $purchaseOrder, $supplier, DocumentType::SUPPLIER_DELIVER_ORDER, null); + // supply deliver order + $this->invoiceDocumentProcessor->execute($supplier_deliver_order_transaction, $purchaseOrder, $supplier, DocumentType::SUPPLIER_DELIVER_ORDER, null); + } } //if(!$generateEInvoiceRefund){ diff --git a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue index 8e6959e0..05112123 100644 --- a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue +++ b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue @@ -200,7 +200,20 @@
- + +
+
+
+
+
@@ -258,6 +271,7 @@ products: [], files: [], uploadFiles: false, + poProcessing: false, } }, validations: { @@ -379,6 +393,7 @@ } this.updateList() } + this.poProcessing = false; }, errorHandler(error, statusCode, section) { //E-Invoice if(section === this.section + 'CheckEInvoiceRule' && statusCode === 422){ @@ -441,8 +456,14 @@ }; this.parameters.e_invoice_request = false; this.submit((this.route('api.company.einvoice.request.change')), 'post', this.section + 'ChangeOfMind', true, true); + }, + handleRepprove() { + if (this.poProcessing) return; + this.poProcessing = true; + this.submit(route('api.booking.po.approval', this.data.id), 'post', this.section, true, true); } }, mixins: [formHandler] } +< From c5ceeba0d036a9f07faf374f8b452f8a3205207b Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 27 Nov 2025 11:16:27 +0800 Subject: [PATCH 03/22] E-Invoice - Update the conditions for generating Sales Invoice Report --- .../Modules/Exports/Services/ExportsSalesInvoiceReport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php index ff3f66c2..f91a5f9a 100644 --- a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php @@ -72,7 +72,7 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR 'transactions.voucherRedemption', 'transactions.voucherRedemption.voucher.campaign' ]) - // ->where('status', ApprovalStatus::COMPLETED) + ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]) ->whereHas('transactions', function ($query) use ($startDate, $endDate) { $query->payments() ->complete() From 940c9d53440bc675f47188d5cfb552989bbd033e Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 27 Nov 2025 11:38:23 +0800 Subject: [PATCH 04/22] E-Invoice - Update the conditions for generating Sales Invoice Report --- .../Modules/Exports/Services/ExportsSalesInvoiceReport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php index f91a5f9a..a801ca5b 100644 --- a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php @@ -72,7 +72,7 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR 'transactions.voucherRedemption', 'transactions.voucherRedemption.voucher.campaign' ]) - ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]) + ->whereIn('status', [ApprovalStatus::COMPLETED]) ->whereHas('transactions', function ($query) use ($startDate, $endDate) { $query->payments() ->complete() From 03dda9cd5a459766392216f428a2237b3413d6c8 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 27 Nov 2025 12:32:01 +0800 Subject: [PATCH 05/22] E-Invoice - Update the conditions for generating Sales Invoice Report with business logic update on generating invoice --- .../Services/ExportsSalesInvoiceReport.php | 3 +- .../CreateInvoiceTransactionV2Processor.php | 4 ++ ...is_invoice_generated_to_bookings_table.php | 37 +++++++++++++++++++ ...nvoice_generated_to_booking_logs_table.php | 34 +++++++++++++++++ 4 files changed, 77 insertions(+), 1 deletion(-) create mode 100644 database/migrations/2025_11_27_120102_add_is_invoice_generated_to_bookings_table.php create mode 100644 database/migrations/2025_11_27_121256_add_is_invoice_generated_to_booking_logs_table.php diff --git a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php index a801ca5b..34c743c8 100644 --- a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php @@ -72,7 +72,8 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR 'transactions.voucherRedemption', 'transactions.voucherRedemption.voucher.campaign' ]) - ->whereIn('status', [ApprovalStatus::COMPLETED]) + // ->whereIn('status', [ApprovalStatus::COMPLETED]) + ->where('is_invoice_generated', 1) ->whereHas('transactions', function ($query) use ($startDate, $endDate) { $query->payments() ->complete() diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php index 619f34b5..399cb041 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php @@ -223,6 +223,10 @@ class CreateInvoiceTransactionV2Processor ); $invoice_transaction = $this->createsTransaction->execute($purchaseOrder->booking ?? $booking, $transaction_object); + //Update booking table, used on Export Sales Invoice Report + $booking->is_invoice_generated = true; + $booking->save(); + if ($kvpCopies) { foreach ($kvpCopies as $kvp) { $invoice_transaction->attributesKVP()->save($kvp); diff --git a/database/migrations/2025_11_27_120102_add_is_invoice_generated_to_bookings_table.php b/database/migrations/2025_11_27_120102_add_is_invoice_generated_to_bookings_table.php new file mode 100644 index 00000000..b2af1a22 --- /dev/null +++ b/database/migrations/2025_11_27_120102_add_is_invoice_generated_to_bookings_table.php @@ -0,0 +1,37 @@ +boolean('is_invoice_generated') + ->default(false) + ->after('status'); + + $table->index('is_invoice_generated', 'bookings_is_invoice_generated_index'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('bookings', function (Blueprint $table) { + $table->dropIndex('bookings_is_invoice_generated_index'); + $table->dropColumn('is_invoice_generated'); + }); + } +} diff --git a/database/migrations/2025_11_27_121256_add_is_invoice_generated_to_booking_logs_table.php b/database/migrations/2025_11_27_121256_add_is_invoice_generated_to_booking_logs_table.php new file mode 100644 index 00000000..e04b01d0 --- /dev/null +++ b/database/migrations/2025_11_27_121256_add_is_invoice_generated_to_booking_logs_table.php @@ -0,0 +1,34 @@ +boolean('is_invoice_generated') + ->default(false) + ->after('status'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('booking_logs', function (Blueprint $table) { + $table->dropColumn('is_invoice_generated'); + }); + } +} From 34e7b37a7c9dc7e9e78f005685ae682a4d639331 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 27 Nov 2025 13:32:23 +0800 Subject: [PATCH 06/22] E-Invoice - Update the conditions for generating Sales Invoice Report with business logic update on generating invoice --- .../ControllersLogic/ApprovePurchaseOrderLogic.php | 7 ++++++- app/Http/Resources/BookingResource.php | 1 + .../bookings/sections/BookingDetailsSectionComponent.vue | 4 ++-- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/app/Classes/Modules/Bookings/ControllersLogic/ApprovePurchaseOrderLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/ApprovePurchaseOrderLogic.php index 7422d6ca..1a533294 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/ApprovePurchaseOrderLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/ApprovePurchaseOrderLogic.php @@ -67,7 +67,12 @@ class ApprovePurchaseOrderLogic extends AbstractControllerLogic $this->updatesTransactionStatus->execute($purchaseOrder, ApprovalStatus::APPROVED); - $this->createInvoiceTransactionProcessor->execute($booking); + $this->createInvoiceTransactionProcessor->execute($booking, "", null, [ + 'generateEInvoice' => false, + 'generateEInvoiceWithNormalInvoiceTemplate' => false, + 'generateEInvoiceRefund' => false, + 'bookingOriginalStatus' => $booking->status + ]); return $this->response([]); } diff --git a/app/Http/Resources/BookingResource.php b/app/Http/Resources/BookingResource.php index 9c6edf96..92824aeb 100644 --- a/app/Http/Resources/BookingResource.php +++ b/app/Http/Resources/BookingResource.php @@ -98,6 +98,7 @@ class BookingResource extends JsonResource })->latest()->get()) ]), 'einvoice' => $eInvoice, + 'is_invoice_generated' => $this->is_invoice_generated, ]; } } diff --git a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue index 0e702efc..c427f4d8 100644 --- a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue @@ -6,7 +6,7 @@
-
+
@@ -122,7 +122,7 @@
-
+
From d8370ba6c7bf1b3b3e18449b17f6a6d76e3c0f6d Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 27 Nov 2025 13:43:39 +0800 Subject: [PATCH 07/22] E-Invoice - Update the conditions for generating Sales Invoice Report with business logic update on generating invoice --- .../bookings/sections/BookingDetailsSectionComponent.vue | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue index c427f4d8..c7fb73db 100644 --- a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue @@ -122,7 +122,7 @@
-
+
From f8bb4e7f520b82ab3bcdcc21bca40227cfd4a980 Mon Sep 17 00:00:00 2001 From: Edmond Lang Date: Wed, 10 Dec 2025 00:15:29 +0800 Subject: [PATCH 08/22] fb gtag update --- .../forms/RegistrationFormComponent.vue | 12 ++++++++++++ .../forms/confirmBookingComponent.vue | 14 ++++++++++++++ resources/assets/vue/utils/tracking.js | 13 +++++++++++++ .../views/pages/payments_redirect.blade.php | 19 ++++++++++++++++++- 4 files changed, 57 insertions(+), 1 deletion(-) create mode 100644 resources/assets/vue/utils/tracking.js diff --git a/resources/assets/vue/components/accounts/forms/RegistrationFormComponent.vue b/resources/assets/vue/components/accounts/forms/RegistrationFormComponent.vue index d6f05b1b..a046a7eb 100644 --- a/resources/assets/vue/components/accounts/forms/RegistrationFormComponent.vue +++ b/resources/assets/vue/components/accounts/forms/RegistrationFormComponent.vue @@ -169,6 +169,7 @@ + @endif +@endpush \ No newline at end of file From 8c29f957c92f8e3a5eaf883b78b40c1374f4f3a8 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Fri, 12 Dec 2025 12:59:05 +0800 Subject: [PATCH 09/22] E-Invoice - EXC2005, Test Result FeedBack 01 fixes --- .../ControllersLogic/CallbackBillplzLogic.php | 35 +-- .../ApprovePurchaseOrderLogic.php | 3 +- .../UpdateBookingAmountLogic.php | 45 ++-- .../UpdateBookingAmountOnHoldLogic.php | 1 + .../UpdateBookingAmountWithPOLogic.php | 24 +- .../UpdateBookingInvoiceStatusObject.php | 42 ++++ ...eatePurchaseOrderFor1688OrderProcessor.php | 8 +- .../Services/UpdatesBookingInvoiceStatus.php | 23 ++ .../Services/ExportsSalesInvoiceReport.php | 2 +- .../CreatePaymentProofDocumentLogic.php | 8 +- .../CreateInvoiceTransactionV2Processor.php | 211 ++++++++++-------- .../CreateSupplierTransactionProcessor.php | 1 + .../ValueObjects/Constants/ApprovalStatus.php | 2 +- app/Http/Resources/BookingResource.php | 14 +- ...2_add_invoice_status_to_bookings_table.php | 37 +++ ...d_invoice_status_to_booking_logs_table.php | 34 +++ database/seeds/DummyDataSeeder.php | 9 +- .../BookingDetailsSectionComponent.vue | 2 +- 18 files changed, 357 insertions(+), 144 deletions(-) create mode 100644 app/Classes/Modules/Bookings/DataTransferObjects/UpdateBookingInvoiceStatusObject.php create mode 100644 app/Classes/Modules/Bookings/Services/UpdatesBookingInvoiceStatus.php create mode 100644 database/migrations/2025_11_27_120102_add_invoice_status_to_bookings_table.php create mode 100644 database/migrations/2025_11_27_121256_add_invoice_status_to_booking_logs_table.php diff --git a/app/Classes/Modules/Billplzs/ControllersLogic/CallbackBillplzLogic.php b/app/Classes/Modules/Billplzs/ControllersLogic/CallbackBillplzLogic.php index b6537420..42726384 100644 --- a/app/Classes/Modules/Billplzs/ControllersLogic/CallbackBillplzLogic.php +++ b/app/Classes/Modules/Billplzs/ControllersLogic/CallbackBillplzLogic.php @@ -2,31 +2,32 @@ namespace App\Classes\Modules\Billplzs\ControllersLogic; -use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject; -use App\Classes\Modules\Wallets\Services\UpdatesWallet; +use App\Classes\Exceptions\MalformedRequestException; +use App\Classes\Exceptions\ResourceNotFoundException; +use App\Classes\General\Abstracts\AbstractControllerLogic; +use App\Classes\Jobs\Commands\V2\CreateInvoiceTransactionV2CommandJob; +use App\Classes\Modules\Billplzs\DataTransferObjects\BillplzXSignatureObject; +use App\Classes\Modules\Billplzs\Services\GetBillplzBill; use App\Classes\Modules\Transactions\Processors\CreateCashBackTransactionProcessor; use App\Classes\Modules\Transactions\Processors\CreateReceiptVoucherTransactionProcessor; - -use App\Classes\Exceptions\ResourceNotFoundException; +use App\Classes\Modules\Transactions\Services\FetchesTransaction; +use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus; +use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject; +use App\Classes\Modules\Wallets\Services\RecalculatesWalletBalance; +use App\Classes\Modules\Wallets\Services\UpdatesWallet; use App\Classes\Modules\Wallets\Services\UpdatesWalletBalance; +use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\ValueObjects\Constants\TransactionType; use App\Http\Resources\TransactionResource; + use App\Models\Booking; use App\Models\User; use App\Models\Wallet; -use Illuminate\Http\Request; -use Illuminate\Http\JsonResponse; -use App\Classes\Exceptions\MalformedRequestException; -use App\Classes\ValueObjects\Constants\ApprovalStatus; -use App\Classes\ValueObjects\Constants\TransactionType; -use App\Classes\Modules\Billplzs\Services\GetBillplzBill; -use App\Classes\Modules\Billplzs\DataTransferObjects\BillplzXSignatureObject; -use App\Classes\General\Abstracts\AbstractControllerLogic; -use App\Classes\Modules\Transactions\Services\FetchesTransaction; -use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Illuminate\Support\Facades\Log; -use App\Classes\Modules\Wallets\Services\RecalculatesWalletBalance; class CallbackBillplzLogic { @@ -117,6 +118,10 @@ class CallbackBillplzLogic $this->createReceiptVoucherTransactionProcessor->execute($booking, $transaction); } + if($booking){ + CreateInvoiceTransactionV2CommandJob::dispatch($booking); + } + // if ($transaction->type == TransactionType::PAYMENT) { // $cash_back_transaction = $this->createCashBackTransactionProcessor->execute($transaction); // } diff --git a/app/Classes/Modules/Bookings/ControllersLogic/ApprovePurchaseOrderLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/ApprovePurchaseOrderLogic.php index 1a533294..3360946a 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/ApprovePurchaseOrderLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/ApprovePurchaseOrderLogic.php @@ -72,7 +72,8 @@ class ApprovePurchaseOrderLogic extends AbstractControllerLogic 'generateEInvoiceWithNormalInvoiceTemplate' => false, 'generateEInvoiceRefund' => false, 'bookingOriginalStatus' => $booking->status - ]); + ] + ); return $this->response([]); } diff --git a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php index fd4af7f8..73985848 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountLogic.php @@ -2,25 +2,24 @@ namespace App\Classes\Modules\Bookings\ControllersLogic; +use App\Classes\Exceptions\MalformedRequestException; +use App\Classes\General\Abstracts\AbstractControllerLogic; +use App\Classes\Jobs\Commands\V2\CreateInvoiceTransactionV2CommandJob; +use App\Classes\Modules\Bookings\DataTransferObjects\BookingObject; +use App\Classes\Modules\Bookings\DataTransferObjects\UpdateBookingInvoiceStatusObject; +use App\Classes\Modules\Bookings\Services\CalculatesBookingOutstanding; +use App\Classes\Modules\Bookings\Services\FetchesBooking; +use App\Classes\Modules\Bookings\Services\UpdatesBookingInvoiceStatus; use App\Classes\Modules\Bookings\Services\UpdatesBookingFixedAmount; +use App\Classes\Modules\Bookings\Standards\Rules\CanUpdateBooking; +use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionV2Processor; use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\TransactionType; use App\Http\Resources\BookingResource; - -use App\Classes\General\Abstracts\AbstractControllerLogic; - -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\Bookings\Services\CalculatesBookingOutstanding; - -use ErrorException; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\DB; -use App\Classes\Exceptions\MalformedRequestException; use Illuminate\Support\Facades\Log; class UpdateBookingAmountLogic extends AbstractControllerLogic @@ -52,6 +51,12 @@ class UpdateBookingAmountLogic extends AbstractControllerLogic /** @var UpdatesTransactionStatus */ private $updatesTransactionStatus; + /** @var UpdatesBookingInvoiceStatus */ + private $updatesBookingInvoiceStatus; + + /** @var CreateInvoiceTransactionV2Processor */ + private $createInvoiceTransactionProcessor; + /** * UpdateBookingAmountLogic constructor. * @param CanUpdateBooking $canUpdateBooking @@ -59,14 +64,18 @@ class UpdateBookingAmountLogic extends AbstractControllerLogic * @param FetchesBooking $fetchesBooking * @param CalculatesBookingOutstanding $calculatesBookingOutstanding * @param UpdatesTransactionStatus $updatesTransactionStatus + * @param UpdatesBookingInvoiceStatus $updatesBookingInvoiceStatus + * @param CreateInvoiceTransactionV2Processor $createInvoiceTransactionProcessor */ - 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, UpdatesBookingInvoiceStatus $updatesBookingInvoiceStatus, CreateInvoiceTransactionV2Processor $createInvoiceTransactionProcessor) { $this->canUpdateBooking = $canUpdateBooking; $this->updatesBookingFixedAmount = $updatesBookingFixedAmount; $this->fetchesBooking = $fetchesBooking; $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; $this->updatesTransactionStatus = $updatesTransactionStatus; + $this->updatesBookingInvoiceStatus = $updatesBookingInvoiceStatus; + $this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor; } /** @@ -81,7 +90,7 @@ class UpdateBookingAmountLogic extends AbstractControllerLogic $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 .'.'); @@ -97,7 +106,15 @@ class UpdateBookingAmountLogic extends AbstractControllerLogic $booking = $this->updatesBookingFixedAmount->execute($booking, $input_amount); + if($booking->invoice_status === ApprovalStatus::APPROVED){ + $updateBookingInvoiceStatusObject = new UpdateBookingInvoiceStatusObject($booking->id, ApprovalStatus::PENDING_VERIFICATION); + $this->updatesBookingInvoiceStatus->execute($booking, $updateBookingInvoiceStatusObject); + } + else{ + $this->createInvoiceTransactionProcessor->execute($booking); + } + return $this->resourceResponse(new BookingResource($booking)); } -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php index 39dc6674..80e43945 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php @@ -91,6 +91,7 @@ class UpdateBookingAmountOnHoldLogic extends AbstractControllerLogic } $key = "BOOKING_AMOUNT_UPDATE"; + $keyValuePairObject = new KeyValuePairObject($key, $input_amount); $metadata = $booking->attributesKVP()->where('key', $key)->first(); if($metadata){ diff --git a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php index 4def81f7..b97a2667 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php @@ -10,6 +10,10 @@ use App\Classes\Modules\Bookings\Services\UpdatesBookingFixedAmount; use App\Classes\Modules\Bookings\Services\CalculatesBookingOutstanding; use App\Classes\Modules\Bookings\Services\CalculatesBookingPayableAmount; use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount; +use App\Classes\Modules\Bookings\Services\UpdatesBookingInvoiceStatus; +use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionV2Processor; +use App\Classes\Modules\Bookings\DataTransferObjects\UpdateBookingInvoiceStatusObject; +use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\TransactionType; use App\Http\Resources\BookingResource; use App\Models\Booking; @@ -45,6 +49,12 @@ class UpdateBookingAmountWithPOLogic extends AbstractControllerLogic /** @var CalculatesBookingRefundAmount */ private $calculatesBookingRefundAmount; + /** @var UpdatesBookingInvoiceStatus */ + private $updatesBookingInvoiceStatus; + + /** @var CreateInvoiceTransactionV2Processor */ + private $createInvoiceTransactionProcessor; + /** * UpdateBookingAmountWithPOLogic constructor. * @param FetchesBooking $fetchesBooking @@ -52,14 +62,18 @@ class UpdateBookingAmountWithPOLogic extends AbstractControllerLogic * @param CalculatesBookingOutstanding $calculatesBookingOutstanding * @param CalculatesBookingPayableAmount $calculatesBookingPayableAmount * @param CalculatesBookingRefundAmount $calculatesBookingRefundAmount + * @param UpdatesBookingInvoiceStatus $updatesBookingInvoiceStatus + * @param CreateInvoiceTransactionV2Processor $createInvoiceTransactionProcessor */ - public function __construct(FetchesBooking $fetchesBooking, UpdatesBookingFixedAmount $updatesBookingFixedAmount, CalculatesBookingOutstanding $calculatesBookingOutstanding, CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingRefundAmount $calculatesBookingRefundAmount) + public function __construct(FetchesBooking $fetchesBooking, UpdatesBookingFixedAmount $updatesBookingFixedAmount, CalculatesBookingOutstanding $calculatesBookingOutstanding, CalculatesBookingPayableAmount $calculatesBookingPayableAmount, CalculatesBookingRefundAmount $calculatesBookingRefundAmount, UpdatesBookingInvoiceStatus $updatesBookingInvoiceStatus, CreateInvoiceTransactionV2Processor $createInvoiceTransactionProcessor) { $this->fetchesBooking = $fetchesBooking; $this->updatesBookingFixedAmount = $updatesBookingFixedAmount; $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; $this->calculatesBookingPayableAmount = $calculatesBookingPayableAmount; $this->calculatesBookingRefundAmount = $calculatesBookingRefundAmount; + $this->updatesBookingInvoiceStatus = $updatesBookingInvoiceStatus; + $this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor; } /** @@ -110,6 +124,14 @@ class UpdateBookingAmountWithPOLogic extends AbstractControllerLogic $booking->transactions()->where('type', TransactionType::PROFORMA)->delete(); $booking = $this->updatesBookingFixedAmount->execute($booking, $bookingAmountUpdate); + if($booking->invoice_status === ApprovalStatus::APPROVED){ + $updateBookingInvoiceStatusObject = new UpdateBookingInvoiceStatusObject($booking->id, ApprovalStatus::PENDING_VERIFICATION); + $this->updatesBookingInvoiceStatus->execute($booking, $updateBookingInvoiceStatusObject); + } + else{ + $this->createInvoiceTransactionProcessor->execute($booking); + } + $request->merge(['is_privilleged_update' => true]); $bookingAttribute->delete(); diff --git a/app/Classes/Modules/Bookings/DataTransferObjects/UpdateBookingInvoiceStatusObject.php b/app/Classes/Modules/Bookings/DataTransferObjects/UpdateBookingInvoiceStatusObject.php new file mode 100644 index 00000000..6b04a695 --- /dev/null +++ b/app/Classes/Modules/Bookings/DataTransferObjects/UpdateBookingInvoiceStatusObject.php @@ -0,0 +1,42 @@ +id = $id; + $this->invoiceStatus = $invoiceStatus; + } + + /** + * @return int + */ + public function getId(): int + { + return $this->id; + } + + /** + * @return int + */ + public function getInvoiceStatus(): int + { + return $this->invoiceStatus; + } +} diff --git a/app/Classes/Modules/Bookings/Processors/CreatePurchaseOrderFor1688OrderProcessor.php b/app/Classes/Modules/Bookings/Processors/CreatePurchaseOrderFor1688OrderProcessor.php index 8a24a5ab..83b25386 100644 --- a/app/Classes/Modules/Bookings/Processors/CreatePurchaseOrderFor1688OrderProcessor.php +++ b/app/Classes/Modules/Bookings/Processors/CreatePurchaseOrderFor1688OrderProcessor.php @@ -88,7 +88,13 @@ class CreatePurchaseOrderFor1688OrderProcessor if($purchaseOrder->amount === $booking->fix_amount){ $this->updatesTransactionStatus->execute($purchaseOrder, ApprovalStatus::APPROVED); - $this->createInvoiceTransactionProcessor->execute($booking); + $this->createInvoiceTransactionProcessor->execute($booking, "", null, [ + 'generateEInvoice' => false, + 'generateEInvoiceWithNormalInvoiceTemplate' => false, + 'generateEInvoiceRefund' => false, + 'bookingOriginalStatus' => ApprovalStatus::COMPLETED + ] + ); } } diff --git a/app/Classes/Modules/Bookings/Services/UpdatesBookingInvoiceStatus.php b/app/Classes/Modules/Bookings/Services/UpdatesBookingInvoiceStatus.php new file mode 100644 index 00000000..97342170 --- /dev/null +++ b/app/Classes/Modules/Bookings/Services/UpdatesBookingInvoiceStatus.php @@ -0,0 +1,23 @@ +invoice_status = $object->getInvoiceStatus(); + return $this->handler($model); + } +} diff --git a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php index 34c743c8..a7c170b7 100644 --- a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php @@ -73,7 +73,7 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR 'transactions.voucherRedemption.voucher.campaign' ]) // ->whereIn('status', [ApprovalStatus::COMPLETED]) - ->where('is_invoice_generated', 1) + ->whereIn('invoice_status', [ApprovalStatus::APPROVED]) ->whereHas('transactions', function ($query) use ($startDate, $endDate) { $query->payments() ->complete() diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php index fdaf5e75..a1d12768 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/CreatePaymentProofDocumentLogic.php @@ -90,7 +90,13 @@ class CreatePaymentProofDocumentLogic extends AbstractControllerLogic $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::APPROVED); - $this->createInvoiceTransactionProcessor->execute($transaction->owner->booking); + $this->createInvoiceTransactionProcessor->execute($transaction->owner->booking, "", null, [ + 'generateEInvoice' => false, + 'generateEInvoiceWithNormalInvoiceTemplate' => false, + 'generateEInvoiceRefund' => false, + 'bookingOriginalStatus' => ApprovalStatus::COMPLETED + ] + ); // 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 diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php index 399cb041..b9361152 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php @@ -98,7 +98,12 @@ class CreateInvoiceTransactionV2Processor $generateEInvoice = $options['generateEInvoice'] ?? false; $generateEInvoiceWithNormalInvoiceTemplate = $options['generateEInvoiceWithNormalInvoiceTemplate'] ?? false; $generateEInvoiceRefund = $options['generateEInvoiceRefund'] ?? false; - $bookingOriginalStatus = $options['bookingOriginalStatus'] ?? ApprovalStatus::COMPLETED; + $bookingOriginalStatus = $options['bookingOriginalStatus'] ?? ApprovalStatus::APPROVED; + + // Log::info('CreateInvoiceTransactionV2Processor generateEInvoice:' . json_encode($generateEInvoice)); + // Log::info('CreateInvoiceTransactionV2Processor generateEInvoiceWithNormalInvoiceTemplate: ' . json_encode($generateEInvoiceWithNormalInvoiceTemplate)); + // Log::info('CreateInvoiceTransactionV2Processor generateEInvoiceRefund: ' . json_encode($generateEInvoiceRefund)); + // Log::info('CreateInvoiceTransactionV2Processor bookingOriginalStatus: ' . json_encode($bookingOriginalStatus)); if($generateEInvoiceRefund){ $generateEInvoice = true; //With or without refund, these 2 flags are meant to Generate E-Invoice, so cannot have opposite indicator @@ -122,6 +127,7 @@ class CreateInvoiceTransactionV2Processor // return; } + $purchaseOrder = null; if($generateEInvoiceRefund){ $purchaseOrder = $booking->transactions() ->where('type', TransactionType::PURCHASE_ORDER) @@ -136,14 +142,9 @@ class CreateInvoiceTransactionV2Processor } $constants = SegmentConstant::where('reference', SegmentConstants::SERVICE_TYPE)->where('detail->id', $booking->service->id)->first(); - - if ($constants->detail->is_billable && !$purchaseOrder && !$generateEInvoiceRefund) { - return; - } - - // $transaction = $booking->transactions() - // ->where('type', TransactionType::PAYMENT) - // ->first(); + // if ($constants->detail->is_billable && !$purchaseOrder && !$generateEInvoiceRefund) { + // return; + // } $transaction = $booking->transactions() ->where('type', TransactionType::PAYMENT) @@ -202,29 +203,39 @@ class CreateInvoiceTransactionV2Processor ->sum('tax'); } + $invoice_transaction = null; + if($booking->status === ApprovalStatus::APPROVED){ + //NEW INVOICE for non-einvoice user applicable only when booking is completed + $invoice_transaction = $booking->transactions() + ->where('type', TransactionType::INVOICE) + ->complete() + ->latest() + ->first(); + } - - $transaction_object = new TransactionObject( - $billNumber, - TransactionType::INVOICE, - $transaction->issuer, - $transaction->receiver, - $transaction->recipient_bank_account_id, - $transaction->payment_method, - $payable_amount, - $booking_amount, - $transaction->currency_id, - $transaction->original_currency_id, - $booking_currency_average_rate, - $total_tax, - $total_service_charge, - null, - ApprovalStatus::APPROVED - ); - $invoice_transaction = $this->createsTransaction->execute($purchaseOrder->booking ?? $booking, $transaction_object); + if(!$invoice_transaction) { + $transaction_object = new TransactionObject( + $billNumber, + TransactionType::INVOICE, + $transaction->issuer, + $transaction->receiver, + $transaction->recipient_bank_account_id, + $transaction->payment_method, + $payable_amount, + $booking_amount, + $transaction->currency_id, + $transaction->original_currency_id, + $booking_currency_average_rate, + $total_tax, + $total_service_charge, + null, + ApprovalStatus::APPROVED + ); + $invoice_transaction = $this->createsTransaction->execute($purchaseOrder->booking ?? $booking, $transaction_object); + } //Update booking table, used on Export Sales Invoice Report - $booking->is_invoice_generated = true; + $booking->invoice_status = ApprovalStatus::APPROVED; $booking->save(); if ($kvpCopies) { @@ -235,84 +246,86 @@ class CreateInvoiceTransactionV2Processor $voucherRedemption = $transaction->voucherRedemption; - // purchase order - if(!$generateEInvoiceRefund){ - $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::PURCHASE_ORDER, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate); - } - - // deliver order - if(!$generateEInvoiceRefund){ - $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::DELIVER_ORDER, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate); - } - - // e-invoice - if ($eInvoice) - { - if($generateEInvoice){ - $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::EINVOICE, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate, $generateEInvoiceRefund); + if($purchaseOrder){ + // purchase order + if(!$generateEInvoiceRefund){ + $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::PURCHASE_ORDER, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate); } - } - // invoice - else - { - $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::INVOICE, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate, $generateEInvoiceRefund); - } - if(!$generateEInvoiceRefund){ - $billNumber = $this->generatesTransactionBillNumber->execute('SPDO-'); - - $booking_currency_average_rate = $this->calculatesBookingCurrencyAverageRate->execute($booking, TransactionType::BILL, $generateEInvoiceRefund); - - $paymentTransaction = $booking->transactions()->payments()->where('status', ApprovalStatus::COMPLETED)->first(); - - $transaction = null; - if($paymentTransaction){ - $transaction = $paymentTransaction->transactions()->where('type', TransactionType::BILL)->first(); + // deliver order + if(!$generateEInvoiceRefund){ + $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::DELIVER_ORDER, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate); } - else{ // Special handling for refund cases (When a refund is deleted via DeleteRefundTransactionLogic, a booking payment transaction is set to ApprovalStatus::APPROVED) - $paymentTransactionTemp = $booking->transactions()->payments()->where('status', ApprovalStatus::APPROVED)->first(); - // Lets check if there is a refund case - $refund = $paymentTransactionTemp->transactions()->refunds()->where('status', ApprovalStatus::APPROVED)->first(); - if($refund){ - $transaction = $paymentTransactionTemp->transactions()->where('type', TransactionType::BILL)->first(); + + // e-invoice + if ($eInvoice) + { + if($generateEInvoice){ + $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::EINVOICE, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate, $generateEInvoiceRefund); } - else{ - Log::info("CreateInvoiceTransactionV2Processor NO completed payment transaction, refund transaction found for booking '$booking->id'."); + } + // invoice + else + { + $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::INVOICE, $voucherRedemption, $generateEInvoiceWithNormalInvoiceTemplate, $generateEInvoiceRefund); + } + + if(!$generateEInvoiceRefund){ + $billNumber = $this->generatesTransactionBillNumber->execute('SPDO-'); + + $booking_currency_average_rate = $this->calculatesBookingCurrencyAverageRate->execute($booking, TransactionType::BILL, $generateEInvoiceRefund); + + $paymentTransaction = $booking->transactions()->payments()->where('status', ApprovalStatus::COMPLETED)->first(); + + $transactionTypeBill= null; + if($paymentTransaction){ + $transactionTypeBill = $paymentTransaction->transactions()->where('type', TransactionType::BILL)->first(); + } + else{ // Special handling for refund cases (When a refund is deleted via DeleteRefundTransactionLogic, a booking payment transaction is set to ApprovalStatus::APPROVED) + $paymentTransactionTemp = $booking->transactions()->payments()->where('status', ApprovalStatus::APPROVED)->first(); + // Lets check if there is a refund case + $refund = $paymentTransactionTemp->transactions()->refunds()->where('status', ApprovalStatus::APPROVED)->first(); + if($refund){ + $transactionTypeBill = $paymentTransactionTemp->transactions()->where('type', TransactionType::BILL)->first(); + } + else{ + Log::info("CreateInvoiceTransactionV2Processor NO completed payment transaction nor refund transaction found for booking '$booking->id'."); + } + } + + if($transactionTypeBill){ + $transaction_object = new TransactionObject( + $billNumber, + TransactionType::SUPPLIER_DELIVER, + $transactionTypeBill->issuer, + $transactionTypeBill->receiver, + $transactionTypeBill->recipient_bank_account_id, + $transactionTypeBill->payment_method, + $payable_amount, + $booking_amount, + $transactionTypeBill->currency_id, + $transactionTypeBill->original_currency_id, + $booking_currency_average_rate, + $total_tax, + $total_service_charge, + null, + ApprovalStatus::APPROVED + ); + $supplier_deliver_order_transaction = $this->createsTransaction->execute($purchaseOrder->booking, $transaction_object); + + // supply deliver order + $this->invoiceDocumentProcessor->execute($supplier_deliver_order_transaction, $purchaseOrder, $supplier, DocumentType::SUPPLIER_DELIVER_ORDER, null); } } - if($transaction){ - $transaction_object = new TransactionObject( - $billNumber, - TransactionType::SUPPLIER_DELIVER, - $transaction->issuer, - $transaction->receiver, - $transaction->recipient_bank_account_id, - $transaction->payment_method, - $payable_amount, - $booking_amount, - $transaction->currency_id, - $transaction->original_currency_id, - $booking_currency_average_rate, - $total_tax, - $total_service_charge, - null, - ApprovalStatus::APPROVED - ); - $supplier_deliver_order_transaction = $this->createsTransaction->execute($purchaseOrder->booking, $transaction_object); + //if(!$generateEInvoiceRefund){ + $this->updatesBookingStatus->execute($booking, $bookingOriginalStatus); + //} - // supply deliver order - $this->invoiceDocumentProcessor->execute($supplier_deliver_order_transaction, $purchaseOrder, $supplier, DocumentType::SUPPLIER_DELIVER_ORDER, null); - } + // update perfex crm + // if(config('perfexcrm.is_enabled') == 'true'){ + // CreatePerfexCRMInvoice::dispatch($invoice_transaction, $purchaseOrder, $supplier); + // } } - - //if(!$generateEInvoiceRefund){ - $this->updatesBookingStatus->execute($booking, $bookingOriginalStatus); - //} - - // update perfex crm - // if(config('perfexcrm.is_enabled') == 'true'){ - // CreatePerfexCRMInvoice::dispatch($invoice_transaction, $purchaseOrder, $supplier); - // } } } diff --git a/app/Classes/Modules/Transactions/Processors/CreateSupplierTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateSupplierTransactionProcessor.php index b514b404..42a21d71 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateSupplierTransactionProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateSupplierTransactionProcessor.php @@ -86,6 +86,7 @@ class CreateSupplierTransactionProcessor $original_amount_after_refund = $payment->original_amount - $totalRefund; $this->updatesTransactionStatus->execute($payment, ApprovalStatus::COMPLETED); + $billNumber = $this->generatesTransactionBillNumber->execute('SPLR-'); $constant = SegmentConstant::where('reference', SegmentConstants::SERVICE_CHARGE)->where('detail->id', $supplier->id)->first(); diff --git a/app/Classes/ValueObjects/Constants/ApprovalStatus.php b/app/Classes/ValueObjects/Constants/ApprovalStatus.php index ba7660d4..987dbc6a 100644 --- a/app/Classes/ValueObjects/Constants/ApprovalStatus.php +++ b/app/Classes/ValueObjects/Constants/ApprovalStatus.php @@ -29,5 +29,5 @@ final class ApprovalStatus { self::SUSPENDED => "Suspended", self::EXPIRED => "Expired", self::REFUNDED => "Refunded", - ]; + ]; } diff --git a/app/Http/Resources/BookingResource.php b/app/Http/Resources/BookingResource.php index 92824aeb..73571b1b 100644 --- a/app/Http/Resources/BookingResource.php +++ b/app/Http/Resources/BookingResource.php @@ -58,13 +58,13 @@ class BookingResource extends JsonResource 'convertible_currency' => new CurrencyResource($this->convertibleCurrency), 'conversion_currency' => new CurrencyResource($this->conversionCurrency), 'documents' => [ - 'purchase_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::PURCHASE_ORDER)->first()), - 'delivery_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::DELIVER_ORDER)->first()), - 'invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::INVOICE)->first()), + 'purchase_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::PURCHASE_ORDER)->latest()->first()), + 'delivery_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::DELIVER_ORDER)->latest()->first()), + 'invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::INVOICE)->latest()->first()), 'e_invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::EINVOICE)->latest()->first()), - 'supplier_delivery_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::SUPPLIER_DELIVER_ORDER)->first()), - 'proforma_invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::PROFORMA_INVOICE)->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::EXPIRED])->orderByDesc('id')->first()), - 'ecommerce_purchase_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->first()), + 'supplier_delivery_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::SUPPLIER_DELIVER_ORDER)->latest()->first()), + 'proforma_invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::PROFORMA_INVOICE)->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::EXPIRED])->latest()->first()), + 'ecommerce_purchase_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->latest()->first()), ], 'order_reference_no' => $this->modelAttributes()->where('name', BookingAttributeNames::ORDER_REFERENCE_NO)->get()->map(function ($attr) { return [ @@ -98,7 +98,7 @@ class BookingResource extends JsonResource })->latest()->get()) ]), 'einvoice' => $eInvoice, - 'is_invoice_generated' => $this->is_invoice_generated, + 'invoice_status' => $this->invoice_status, ]; } } diff --git a/database/migrations/2025_11_27_120102_add_invoice_status_to_bookings_table.php b/database/migrations/2025_11_27_120102_add_invoice_status_to_bookings_table.php new file mode 100644 index 00000000..124800b4 --- /dev/null +++ b/database/migrations/2025_11_27_120102_add_invoice_status_to_bookings_table.php @@ -0,0 +1,37 @@ +unsignedTinyInteger('invoice_status') + ->default(0) + ->after('status'); + + $table->index('invoice_status', 'bookings_invoice_status_index'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('bookings', function (Blueprint $table) { + $table->dropIndex('bookings_invoice_status_index'); + $table->dropColumn('invoice_status'); + }); + } +} diff --git a/database/migrations/2025_11_27_121256_add_invoice_status_to_booking_logs_table.php b/database/migrations/2025_11_27_121256_add_invoice_status_to_booking_logs_table.php new file mode 100644 index 00000000..d0b21f09 --- /dev/null +++ b/database/migrations/2025_11_27_121256_add_invoice_status_to_booking_logs_table.php @@ -0,0 +1,34 @@ +boolean('invoice_status') + ->default(false) + ->after('status'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('booking_logs', function (Blueprint $table) { + $table->dropColumn('invoice_status'); + }); + } +} diff --git a/database/seeds/DummyDataSeeder.php b/database/seeds/DummyDataSeeder.php index a752ee6f..328dcc15 100644 --- a/database/seeds/DummyDataSeeder.php +++ b/database/seeds/DummyDataSeeder.php @@ -679,8 +679,13 @@ class DummyDataSeeder extends Seeder // once the invoice is generated the transaction table will include 2 new transaction type TransactionType::INVOICE, TransactionType::SUPPLIER_DELIVERY // and for documents will be generated and attached to the booking. // once this process is complete the booking status will update to ApprovalStatus::COMPLETED - $this->createInvoiceTransactionProcessor->execute($booking); - + $this->createInvoiceTransactionProcessor->execute($booking, "", null, [ + 'generateEInvoice' => false, + 'generateEInvoiceWithNormalInvoiceTemplate' => false, + 'generateEInvoiceRefund' => false, + 'bookingOriginalStatus' => ApprovalStatus::COMPLETED + ] + ); } } diff --git a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue index c7fb73db..d0cda96f 100644 --- a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue @@ -6,7 +6,7 @@
-
+
From 2f0f96fd794fc2b2d28c2df3ab782c15ef217543 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Fri, 12 Dec 2025 14:16:52 +0800 Subject: [PATCH 10/22] E-Invoice - EXC2005, Test Result FeedBack 01 fixes --- .../ControllersLogic/UpdateBookingAmountOnHoldLogic.php | 7 +++---- .../ControllersLogic/UpdateBookingAmountWithPOLogic.php | 3 ++- app/Classes/ValueObjects/Constants/KVPKey.php | 2 +- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php index 80e43945..3588909f 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountOnHoldLogic.php @@ -14,6 +14,7 @@ use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\Exceptions\MalformedRequestException; use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject; +use App\Classes\ValueObjects\Constants\KVPKey; use App\Http\Resources\BookingResource; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -90,10 +91,8 @@ class UpdateBookingAmountOnHoldLogic extends AbstractControllerLogic 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(); + $keyValuePairObject = new KeyValuePairObject(KVPKey::BOOKING_AMOUNT_UPDATE, $input_amount); + $metadata = $booking->attributesKVP()->where('key', KVPKey::BOOKING_AMOUNT_UPDATE)->first(); if($metadata){ $this->updatesKeyValuePair->execute($metadata, $keyValuePairObject); } diff --git a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php index b97a2667..48cc7d94 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/UpdateBookingAmountWithPOLogic.php @@ -14,6 +14,7 @@ use App\Classes\Modules\Bookings\Services\UpdatesBookingInvoiceStatus; use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionV2Processor; use App\Classes\Modules\Bookings\DataTransferObjects\UpdateBookingInvoiceStatusObject; use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\ValueObjects\Constants\KVPKey; use App\Classes\ValueObjects\Constants\TransactionType; use App\Http\Resources\BookingResource; use App\Models\Booking; @@ -88,7 +89,7 @@ class UpdateBookingAmountWithPOLogic extends AbstractControllerLogic /** @var Booking $booking */ $booking = $this->fetchesBooking->execute(['id' => $request->route('id') ?? $id]); $outstandingAmount = $this->calculatesBookingOutstanding->execute($booking); - $bookingAttribute = $booking->attributesKVP()->where('key', "BOOKING_AMOUNT_UPDATE")->first(); + $bookingAttribute = $booking->attributesKVP()->where('key', KVPKey::BOOKING_AMOUNT_UPDATE)->first(); // cief todo: 90 - BEFORE REVERT diff --git a/app/Classes/ValueObjects/Constants/KVPKey.php b/app/Classes/ValueObjects/Constants/KVPKey.php index 0eebe6bc..1ab5f1bd 100644 --- a/app/Classes/ValueObjects/Constants/KVPKey.php +++ b/app/Classes/ValueObjects/Constants/KVPKey.php @@ -28,6 +28,6 @@ class KVPKey public const AUTOCOUNT_DOCNO_SALES_DEPOSIT_BY_WALLET_REFUND = 'AUTOCOUNT_DOCNO_SALES_DEPOSIT_BY_WALLET_RF'; - + public const BOOKING_AMOUNT_UPDATE = 'BOOKING_AMOUNT_UPDATE'; } From 408baab0c6956ae2351f32fe9f417d3cd033b117 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Tue, 23 Dec 2025 15:24:05 +0800 Subject: [PATCH 11/22] E-Invoice - EXC3000: Exchange Rules of RM10K single INV --- .../CheckEInvoiceAmountLimitLogic.php | 67 ++++++++++++++ .../CheckEInvoiceAmountLimitRuleDTO.php | 36 ++++++++ .../CanPassMustEInvoiceAmountLimitRule.php | 87 +++++++++++++++++++ .../Controllers/Rules/CheckRuleController.php | 10 +++ .../BookingPaymentQuotationV2Component.vue | 72 ++++++++++----- .../forms/PurchaseOrderFormComponent.vue | 19 ++++ routes/rule.php | 1 + 7 files changed, 268 insertions(+), 24 deletions(-) create mode 100644 app/Classes/Modules/Rules/ControllersLogic/CheckEInvoiceAmountLimitLogic.php create mode 100644 app/Classes/Modules/Rules/DataTransferObjects/CheckEInvoiceAmountLimitRuleDTO.php create mode 100644 app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php diff --git a/app/Classes/Modules/Rules/ControllersLogic/CheckEInvoiceAmountLimitLogic.php b/app/Classes/Modules/Rules/ControllersLogic/CheckEInvoiceAmountLimitLogic.php new file mode 100644 index 00000000..bc9f18ae --- /dev/null +++ b/app/Classes/Modules/Rules/ControllersLogic/CheckEInvoiceAmountLimitLogic.php @@ -0,0 +1,67 @@ + 'Rule Check E-Invoice Amount Limit', + 'message' => 'You have successfully passed all rules evaluated' + ]; + } + + /** @var RuleEvaluator */ + private $ruleEvaluator; + + + /** @var CanPassMustEInvoiceAmountLimitRule */ + private $canPassMustEInvoiceAmountLimitRule; + + /** + * CheckEInvoiceAmountLimitLogic constructor. + * @param RuleEvaluator $ruleEvaluator + * @param CanPassMustEInvoiceAmountLimitRule $canPassMustEInvoiceAmountLimitRule + */ + public function __construct(RuleEvaluator $ruleEvaluator, CanPassMustEInvoiceAmountLimitRule $canPassMustEInvoiceAmountLimitRule) + { + $this->ruleEvaluator = $ruleEvaluator; + $this->canPassMustEInvoiceAmountLimitRule = $canPassMustEInvoiceAmountLimitRule; + } + + /** + * @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 CheckEInvoiceAmountLimitRuleDTO($request->all()); + + $result = $this->ruleEvaluator->evaluate([ + $this->canPassMustEInvoiceAmountLimitRule + ], $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/CheckEInvoiceAmountLimitRuleDTO.php b/app/Classes/Modules/Rules/DataTransferObjects/CheckEInvoiceAmountLimitRuleDTO.php new file mode 100644 index 00000000..b28e78f1 --- /dev/null +++ b/app/Classes/Modules/Rules/DataTransferObjects/CheckEInvoiceAmountLimitRuleDTO.php @@ -0,0 +1,36 @@ +bookingId = $data['booking_id']; + $this->companyId = $data['company_id']; + + $this->amount = $data['amount'] ?? null; + $this->paymentMethod = $data['payment_method'] ?? null; + $this->voucherCode = $data['voucherCode'] ?? null; + } + + public function toArray(): array + { + return [ + 'booking_id' => $this->bookingId, + 'company_id' => $this->companyId, + 'amount' => $this->amount, + 'payment_method' => $this->paymentMethod, + 'voucher_code' => $this->voucherCode, + ]; + } +} diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php new file mode 100644 index 00000000..201bad8b --- /dev/null +++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php @@ -0,0 +1,87 @@ +fetchesBooking = $fetchesBooking; + $this->fetchesBookingQuotation = $fetchesBookingQuotation; + $this->calculatesBookingOutstanding = $calculatesBookingOutstanding; + } + + /** + * @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 booking amount is RM10,000 or more, than must opt-in E-Invoice + $booking = $this->fetchesBooking->execute(['id' => $object->bookingId]); + $company = $booking->company; + + if(isset($object->amount)){ + $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', floatval(str_replace(',', '', $object->amount)))), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::PAYMENT_METHODS[$object->paymentMethod]); + $voucherCode = $object->voucherCode ?? null; + $configurations = $this->fetchesBookingQuotation->execute($booking->company, $conversionObject, $voucherCode, null, $booking); + } + else{ + $outstanding = $this->calculatesBookingOutstanding->execute($booking); + $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $outstanding)), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0 : 1, PaymentMethodType::CASH); + $configurations = $this->fetchesBookingQuotation->execute($booking->company, $conversionObject); + } + + $bookingAmountInMYR = $configurations->getTotal(); + + if($bookingAmountInMYR >= 10000 && (!$company->e_invoice || !$company->tin) ){ + throw new CriteriaNotFulfilledException("RM10,000 and above must opt-in for E-Invoice."); + } + return true; + } +} diff --git a/app/Http/Controllers/Rules/CheckRuleController.php b/app/Http/Controllers/Rules/CheckRuleController.php index 59b24cd0..b0a175c1 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\CheckEInvoiceAmountLimitLogic; 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 CheckEInvoiceAmountLimitLogic $logic + * @return JsonResponse + */ + public function checkEInvoiceAmountLimitRule(Request $request, CheckEInvoiceAmountLimitLogic $logic): JsonResponse { + return $logic->execute($request); + } } diff --git a/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationV2Component.vue b/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationV2Component.vue index 7dd9adc0..363a6d1f 100644 --- a/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationV2Component.vue +++ b/resources/assets/vue/components/bookings/forms/BookingPaymentQuotationV2Component.vue @@ -162,29 +162,6 @@
- - - - - - -
@@ -622,7 +599,7 @@ + @click.prevent="checkEInvoiceAmountLimitRule">Lock Booking
@@ -630,6 +607,31 @@
+ + + + + + + + +
@@ -740,6 +742,9 @@ $('#confirm-booking-modal').modal('show'); } } + else if(section === this.section + 'CheckEInvoiceAmountLimitRule'){ + this.checkPurchaseOrderRule(); + } else if(section === this.section + 'ChangeOfMind'){ this.$store.dispatch('reloadList', {'name': "bookingDetailSection"}); } @@ -767,6 +772,14 @@ if(section === this.section + 'CheckEInvoiceRule' && statusCode === 422){ $('#modal-einvoice-info').modal('show'); } + else if(section === this.section + 'CheckEInvoiceAmountLimitRule' && statusCode === 422){ + if(!this.data.company.e_invoice){ + $('#modal-einvoice-request').modal('show'); + } + else if(!this.data.company.tin){ + $('#modal-einvoice-info').modal('show'); + } + } this.error = error.message; }, makePayment(){ //E-Invoice @@ -837,6 +850,17 @@ }; this.submit(route('api.rule.check.einvoice'), 'post', this.section + 'CheckEInvoiceRule', false, true); }, + checkEInvoiceAmountLimitRule(){ + this.error = ''; + this.parameters = { + booking_id: this.data.id, + company_id: this.data.company.id, + payment_method: this.paymentMethod.id, + voucherCode: this.voucherCode, + amount: this.amount + }; + this.submit(route('api.rule.check.einvoice.amount-limit'), 'post', this.section + 'CheckEInvoiceAmountLimitRule', false, true); + }, checkPurchaseOrderRule(){ this.error = ''; this.parameters = { diff --git a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue index a96af8fc..2f546bd4 100644 --- a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue +++ b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue @@ -432,6 +432,9 @@ this.checkEInvoiceRule(); } else if(section === this.section + 'CheckEInvoiceRule'){ + this.checkEInvoiceAmountLimitRule(); + } + else if(section === this.section + 'CheckEInvoiceAmountLimitRule'){ if(response.payload.data.isPassed){ if(this.data.service.id === 14 || this.data.service.id === 15 || this.data.service.id === 16 || this.data.service.id === 17 || this.data.service.id === 18 || this.data.service.id === 19){ this.submit(route('api.booking.banking.create', this.data.id), 'post', this.section, true, true); @@ -452,6 +455,14 @@ if(section === this.section + 'CheckEInvoiceRule' && statusCode === 422){ $('#modal-einvoice-info').modal('show'); } + else if(section === this.section + 'CheckEInvoiceAmountLimitRule' && statusCode === 422){ + if(!this.data.company.e_invoice){ + $('#modal-einvoice-request').modal('show'); + } + else if(!this.data.company.tin){ + $('#modal-einvoice-info').modal('show'); + } + } }, addProduct(){ this.products.push({ @@ -518,6 +529,14 @@ }; this.submit(route('api.rule.check.einvoice'), 'post', this.section + 'CheckEInvoiceRule', false, true); }, + checkEInvoiceAmountLimitRule(){ + this.error = ''; + this.parameters = { + booking_id: this.data.id, + company_id: this.data.company.id, + }; + this.submit(route('api.rule.check.einvoice.amount-limit'), 'post', this.section + 'CheckEInvoiceAmountLimitRule', false, true); + }, updatedEInvoiceInfo(info){ this.$store.dispatch('reloadList', {'name': "bookingDetailSection"}); }, diff --git a/routes/rule.php b/routes/rule.php index d5330176..4918b4d0 100644 --- a/routes/rule.php +++ b/routes/rule.php @@ -9,4 +9,5 @@ Route::prefix('rule') 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'); + Route::post('/check/e-invoice/amount-limit', [CheckRuleController::class, 'checkEInvoiceAmountLimitRule'])->name('check.einvoice.amount-limit'); }); From 4b910e4df7de6502d504f74bd15853efd775ad12 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Wed, 24 Dec 2025 11:53:15 +0800 Subject: [PATCH 12/22] E-Invoice - EXC3000: Exchange Rules of RM10K single INV --- .../Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php index 201bad8b..fa3d66be 100644 --- a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php +++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php @@ -8,6 +8,7 @@ use App\Classes\Modules\Bookings\Services\FetchesBooking; use App\Classes\Modules\Bookings\Services\CalculatesBookingOutstanding; use App\Classes\Modules\Bookings\Services\FetchesBookingQuotation; use App\Classes\Modules\Currencies\DataTransferObjects\CurrencyConversionObject; +use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\PaymentMethodType; use Carbon\Carbon; use Illuminate\Support\Facades\Log; @@ -65,8 +66,11 @@ class CanPassMustEInvoiceAmountLimitRule extends AbstractRule //Check if booking amount is RM10,000 or more, than must opt-in E-Invoice $booking = $this->fetchesBooking->execute(['id' => $object->bookingId]); $company = $booking->company; + $totalPayments = 0; if(isset($object->amount)){ + $totalPayments = $booking->transactions()->payments()->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount'); + $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', floatval(str_replace(',', '', $object->amount)))), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::PAYMENT_METHODS[$object->paymentMethod]); $voucherCode = $object->voucherCode ?? null; $configurations = $this->fetchesBookingQuotation->execute($booking->company, $conversionObject, $voucherCode, null, $booking); @@ -78,6 +82,7 @@ class CanPassMustEInvoiceAmountLimitRule extends AbstractRule } $bookingAmountInMYR = $configurations->getTotal(); + $bookingAmountInMYR = $bookingAmountInMYR + $totalPayments; if($bookingAmountInMYR >= 10000 && (!$company->e_invoice || !$company->tin) ){ throw new CriteriaNotFulfilledException("RM10,000 and above must opt-in for E-Invoice."); From 6eb5ca7ba3ddc62881c6e4c367e978a9b0d6b486 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Mon, 29 Dec 2025 14:28:05 +0800 Subject: [PATCH 13/22] E-Invoice - EXC3000: Exchange Rules of RM10K single INV, update new business logic --- .../CanPassMustEInvoiceAmountLimitRule.php | 42 +++++++++++-------- 1 file changed, 25 insertions(+), 17 deletions(-) diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php index fa3d66be..0e925f6c 100644 --- a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php +++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php @@ -66,27 +66,35 @@ class CanPassMustEInvoiceAmountLimitRule extends AbstractRule //Check if booking amount is RM10,000 or more, than must opt-in E-Invoice $booking = $this->fetchesBooking->execute(['id' => $object->bookingId]); $company = $booking->company; - $totalPayments = 0; - if(isset($object->amount)){ - $totalPayments = $booking->transactions()->payments()->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount'); + // $totalPayments = 0; - $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', floatval(str_replace(',', '', $object->amount)))), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::PAYMENT_METHODS[$object->paymentMethod]); - $voucherCode = $object->voucherCode ?? null; - $configurations = $this->fetchesBookingQuotation->execute($booking->company, $conversionObject, $voucherCode, null, $booking); - } - else{ - $outstanding = $this->calculatesBookingOutstanding->execute($booking); - $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $outstanding)), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0 : 1, PaymentMethodType::CASH); - $configurations = $this->fetchesBookingQuotation->execute($booking->company, $conversionObject); + // if(isset($object->amount)){ + // $totalPayments = $booking->transactions()->payments()->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount'); + + // $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', floatval(str_replace(',', '', $object->amount)))), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0:1, PaymentMethodType::PAYMENT_METHODS[$object->paymentMethod]); + // $voucherCode = $object->voucherCode ?? null; + // $configurations = $this->fetchesBookingQuotation->execute($booking->company, $conversionObject, $voucherCode, null, $booking); + // } + // else{ + // $outstanding = $this->calculatesBookingOutstanding->execute($booking); + // $conversionObject = new CurrencyConversionObject(floatval(str_replace(',', '', $outstanding)), $booking->convertible_currency_id, $booking->service_id, $booking->fix_currency_id === 1 ? 0 : 1, PaymentMethodType::CASH); + // $configurations = $this->fetchesBookingQuotation->execute($booking->company, $conversionObject); + // } + + // $bookingAmountInMYR = $configurations->getTotal(); + // $bookingAmountInMYR = $bookingAmountInMYR + $totalPayments; + + // if($bookingAmountInMYR >= 10000 && (!$company->e_invoice || !$company->tin) ){ + // throw new CriteriaNotFulfilledException("RM10,000 and above must opt-in for E-Invoice."); + // } + + if((($booking->fix_amount >= 17000 && $booking->fix_currency_id === 2) || + ($booking->fix_amount >= 4000 && $booking->fix_currency_id === 3)) + && (!$company->e_invoice || !$company->tin) ){ + throw new CriteriaNotFulfilledException("Booking amount above limit, must opt-in for E-Invoice."); } - $bookingAmountInMYR = $configurations->getTotal(); - $bookingAmountInMYR = $bookingAmountInMYR + $totalPayments; - - if($bookingAmountInMYR >= 10000 && (!$company->e_invoice || !$company->tin) ){ - throw new CriteriaNotFulfilledException("RM10,000 and above must opt-in for E-Invoice."); - } return true; } } From 5ab978023f5e25d05307f23442231f76737d8544 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Mon, 29 Dec 2025 22:41:25 +0800 Subject: [PATCH 14/22] E-Invoice - Reinstate removed WALLET TOP UP REPORT from drop down list /payments page --- .../bookings/elements/DownloadUploadComponent.vue | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue index 81f1a195..1d48c642 100644 --- a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue +++ b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue @@ -24,6 +24,7 @@ 6. 01DRW - Sales Deposit by Wallet [AR PAYMENT ENTRY] → Filters by Created Date
7. 01DRF - Sales Deposit by Wallet [AR REFUND ENTRY] → Filters by Created Date
8. 01DD - Sales Deposit by Wallet [AR DEPOSIT ENTRY] → Filters by Created Date
+ 9. WALLET TOP UP REPORT [Wallet Deposit Received] → Filters by Top Up Date
"> @@ -52,6 +53,7 @@ 6. 01DRW - Sales Deposit by Wallet [AR PAYMENT ENTRY] → Filters by Created Date
7. 01DRF - Sales Deposit by Wallet [AR REFUND ENTRY] → Filters by Created Date
8. 01DD - Sales Deposit by Wallet [AR DEPOSIT ENTRY] → Filters by Created Date
+ 9. WALLET TOP UP REPORT [Wallet Deposit Received] → Filters by Top Up Date
"> @@ -196,10 +198,10 @@ export default { '01D - Sales Deposit Received [AR DEPOSIT ENTRY]', '01R - RECEIVE PAYMENT [AR RECEIVE PAYMENT]', 'Credit Note Report', - //'WALLET TOP UP REPORT [Wallet Deposit Received]', '01DRW - Sales Deposit by Wallet [AR PAYMENT ENTRY]', '01DRF - Sales Deposit by Wallet [AR REFUND ENTRY]', - '01DD - Sales Deposit by Wallet [AR DEPOSIT ENTRY]' + '01DD - Sales Deposit by Wallet [AR DEPOSIT ENTRY]', + 'WALLET TOP UP REPORT [Wallet Deposit Received]' ]; }, handleExportClick(){ @@ -215,10 +217,10 @@ export default { '01D - Sales Deposit Received [AR DEPOSIT ENTRY]': route('api.export.transactions.receive_payment_deposit_entry'), '01R - RECEIVE PAYMENT [AR RECEIVE PAYMENT]': route('api.export.transactions.receive_payment_for_booking'), 'Credit Note Report': route('api.export.transactions.ar_credit_note'), - //'WALLET TOP UP REPORT [Wallet Deposit Received]': route('api.export.transactions.wallet_top_up_deposit_entry'), '01DRW - Sales Deposit by Wallet [AR PAYMENT ENTRY]': route('api.export.transactions.sales_deposit_by_wallet_payment_entry'), '01DRF - Sales Deposit by Wallet [AR REFUND ENTRY]': route('api.export.transactions.sales_deposit_by_wallet_refund_entry'), '01DD - Sales Deposit by Wallet [AR DEPOSIT ENTRY]': route('api.export.transactions.sales_deposit_by_wallet_deposit_entry'), + 'WALLET TOP UP REPORT [Wallet Deposit Received]': route('api.export.transactions.wallet_top_up_deposit_entry'), }; let url = `${routesMap[reportType]}?startDate=${this.parameters.startDate}&endDate=${this.parameters.endDate}`; From 4d26017fd5c7db3e6674bfd09c5ced7869511450 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Mon, 29 Dec 2025 22:59:49 +0800 Subject: [PATCH 15/22] E-Invoice - EXC3000: Exchange Rules of RM10K single INV, update new business logic --- .../Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php index 0e925f6c..b0ecfafc 100644 --- a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php +++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php @@ -90,7 +90,7 @@ class CanPassMustEInvoiceAmountLimitRule extends AbstractRule // } if((($booking->fix_amount >= 17000 && $booking->fix_currency_id === 2) || - ($booking->fix_amount >= 4000 && $booking->fix_currency_id === 3)) + ($booking->fix_amount >= 2400 && $booking->fix_currency_id === 3)) && (!$company->e_invoice || !$company->tin) ){ throw new CriteriaNotFulfilledException("Booking amount above limit, must opt-in for E-Invoice."); } From 74785ad6fbd2a4483f7b81e62f57d38bf7c412ec Mon Sep 17 00:00:00 2001 From: Edmond Lang Date: Tue, 30 Dec 2025 23:29:55 +0800 Subject: [PATCH 16/22] update gtag amount --- .../vue/components/bookings/forms/confirmBookingComponent.vue | 4 ++-- resources/views/pages/payments_redirect.blade.php | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/resources/assets/vue/components/bookings/forms/confirmBookingComponent.vue b/resources/assets/vue/components/bookings/forms/confirmBookingComponent.vue index c2c0afca..6fc7e203 100644 --- a/resources/assets/vue/components/bookings/forms/confirmBookingComponent.vue +++ b/resources/assets/vue/components/bookings/forms/confirmBookingComponent.vue @@ -29,7 +29,7 @@ submitForm(){ // fire to gtag manager for fb pixel tracking: AddToCart — fired when the user clicks Confirm Order (user intent, OK even if API fails) track('exchange_add_to_cart', { - value: this.data.amount, + value: Number(String(this.data.amount).replace(/,/g, '')), currency: 'MYR' }); @@ -51,7 +51,7 @@ successHandler(response){ // fire to gtag manager for fb pixel tracking: InitiateCheckout — booking created track('exchange_checkout', { - value: this.data.amount, + value: Number(String(this.data.amount).replace(/,/g, '')), currency: 'MYR', booking_id: response.payload.data.marking }); diff --git a/resources/views/pages/payments_redirect.blade.php b/resources/views/pages/payments_redirect.blade.php index c7e198fe..946f0222 100644 --- a/resources/views/pages/payments_redirect.blade.php +++ b/resources/views/pages/payments_redirect.blade.php @@ -114,7 +114,7 @@ window.dataLayer.push({ event: 'exchange_purchase', transaction_id: @json($transaction->payment_reference ?? ''), - value: {{ (float)($transaction->amount ?? 0) }}, + value: {{ number_format((float)($transaction->amount ?? 0), 2, '.', '') }}, currency: 'MYR' }); })(); From 630fe1f74b4c21e674d4d6ce79fbf37f6365161f Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Wed, 31 Dec 2025 22:12:49 +0800 Subject: [PATCH 17/22] E-Invoice - EXC3000: Exchange Rules of RM10K single INV, update new business logic --- .../Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php index b0ecfafc..48b7e3ab 100644 --- a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php +++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php @@ -89,8 +89,10 @@ class CanPassMustEInvoiceAmountLimitRule extends AbstractRule // throw new CriteriaNotFulfilledException("RM10,000 and above must opt-in for E-Invoice."); // } - if((($booking->fix_amount >= 17000 && $booking->fix_currency_id === 2) || - ($booking->fix_amount >= 2400 && $booking->fix_currency_id === 3)) + //1 MYR, 2 CNY, 3USD + if((($booking->fix_amount >= 9000 && $booking->fix_currency_id === 1) || + ($booking->fix_amount >= 12600 && $booking->fix_currency_id === 2) || + ($booking->fix_amount >= 1920 && $booking->fix_currency_id === 3)) && (!$company->e_invoice || !$company->tin) ){ throw new CriteriaNotFulfilledException("Booking amount above limit, must opt-in for E-Invoice."); } From 1ed92f5ddf5002a7365905367293bbf21fa73b28 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Wed, 31 Dec 2025 22:13:55 +0800 Subject: [PATCH 18/22] E-Invoice - EXC3000: Exchange Rules of RM10K single INV, update new business logic --- .../Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php index 48b7e3ab..d077aab7 100644 --- a/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php +++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassMustEInvoiceAmountLimitRule.php @@ -89,7 +89,7 @@ class CanPassMustEInvoiceAmountLimitRule extends AbstractRule // throw new CriteriaNotFulfilledException("RM10,000 and above must opt-in for E-Invoice."); // } - //1 MYR, 2 CNY, 3USD + //1 MYR, 2 CNY, 3 USD if((($booking->fix_amount >= 9000 && $booking->fix_currency_id === 1) || ($booking->fix_amount >= 12600 && $booking->fix_currency_id === 2) || ($booking->fix_amount >= 1920 && $booking->fix_currency_id === 3)) @@ -99,4 +99,4 @@ class CanPassMustEInvoiceAmountLimitRule extends AbstractRule return true; } -} +} \ No newline at end of file From 6a694b1fad3db99a16018ca6f5c7fbfa1786e701 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Wed, 7 Jan 2026 13:08:42 +0800 Subject: [PATCH 19/22] E-Invoice - Fix an issue normal invoice not appearing for previous transfer after customer opted in for einvoice --- .../Processors/CreateInvoiceTransactionV2Processor.php | 3 ++- app/Http/Resources/BookingResource.php | 3 ++- 2 files changed, 4 insertions(+), 2 deletions(-) diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php index bb77f79a..b0d6fb7d 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionV2Processor.php @@ -166,7 +166,8 @@ class CreateInvoiceTransactionV2Processor $eInvoice = false; $eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00')); $bookingCreatedDate = Carbon::parse($booking->created_at); - if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $supplier->e_invoice === 1) { + $eInvoiceRequestedDate = Carbon::parse($supplier->e_invoice_requested_at); + if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $bookingCreatedDate->isAfter($eInvoiceRequestedDate) && $supplier->e_invoice === 1) { $eInvoice = true; } $kvp = $booking->attributesKVP()->where('key', KVPKey::BOOKING_EINVOICE_ELIGIBLE)->first(); diff --git a/app/Http/Resources/BookingResource.php b/app/Http/Resources/BookingResource.php index 73571b1b..e118f2e9 100644 --- a/app/Http/Resources/BookingResource.php +++ b/app/Http/Resources/BookingResource.php @@ -13,6 +13,7 @@ use App\Classes\ValueObjects\Constants\DocumentType; use App\Classes\ValueObjects\Constants\KVPKey; use Carbon\Carbon; use Illuminate\Http\Resources\Json\JsonResource; +use Illuminate\Support\Facades\Log; class BookingResource extends JsonResource { @@ -30,7 +31,7 @@ class BookingResource extends JsonResource $bookingCreatedDate = Carbon::parse($this->created_at); $eInvoiceRequestedDate = Carbon::parse($this->company->e_invoice_requested_at); //cief todo: 90 - for testing - if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $this->company->e_invoice === 1) { //&& $bookingCreatedDate->diffInMinutes($eInvoiceRequestedDate) <= 480 cief todo: 90 + if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $bookingCreatedDate->isAfter($eInvoiceRequestedDate) && $this->company->e_invoice === 1) { //&& $bookingCreatedDate->diffInMinutes($eInvoiceRequestedDate) <= 480 cief todo: 90 $eInvoice = true; } From c811f7748feb571842804e35c6673f4ce6fe38cf Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Wed, 7 Jan 2026 13:56:46 +0800 Subject: [PATCH 20/22] E-Invoice - Fix an issue normal invoice not appearing for previous transfer after customer opted in for einvoice --- .../ControllersLogic/FetchCompanyEInvoiceInfoLogic.php | 1 + app/Http/Resources/EInvoiceInfoResource.php | 2 ++ .../components/bookings/elements/EInvoiceInfoComponent.vue | 6 +++++- 3 files changed, 8 insertions(+), 1 deletion(-) diff --git a/app/Classes/Modules/Companies/ControllersLogic/FetchCompanyEInvoiceInfoLogic.php b/app/Classes/Modules/Companies/ControllersLogic/FetchCompanyEInvoiceInfoLogic.php index ebb2d275..2d886967 100644 --- a/app/Classes/Modules/Companies/ControllersLogic/FetchCompanyEInvoiceInfoLogic.php +++ b/app/Classes/Modules/Companies/ControllersLogic/FetchCompanyEInvoiceInfoLogic.php @@ -58,6 +58,7 @@ class FetchCompanyEInvoiceInfoLogic extends AbstractControllerLogic $eInvoiceInfo->tin = $company->tin; $eInvoiceInfo->msic_code = $company->msic_code; $eInvoiceInfo->e_invoice = $company->e_invoice; + $eInvoiceInfo->e_invoice_requested_at = $company->e_invoice_requested_at; } else{ return $this->response([]); diff --git a/app/Http/Resources/EInvoiceInfoResource.php b/app/Http/Resources/EInvoiceInfoResource.php index 97483dd3..a4126eef 100644 --- a/app/Http/Resources/EInvoiceInfoResource.php +++ b/app/Http/Resources/EInvoiceInfoResource.php @@ -2,6 +2,7 @@ namespace App\Http\Resources; +use Carbon\Carbon; use Illuminate\Http\Resources\Json\JsonResource; class EInvoiceInfoResource extends JsonResource @@ -26,6 +27,7 @@ class EInvoiceInfoResource extends JsonResource 'msic_code' => (string) $this->msic_code, 'tin' => (string) $this->tin, 'e_invoice' => (int) $this->e_invoice, + 'e_invoice_requested_date' => $this->e_invoice_requested_at ? Carbon::parse($this->e_invoice_requested_at)->format('d-m-Y') : null, ]; } } diff --git a/resources/assets/vue/components/bookings/elements/EInvoiceInfoComponent.vue b/resources/assets/vue/components/bookings/elements/EInvoiceInfoComponent.vue index 0a168216..3b4359cd 100644 --- a/resources/assets/vue/components/bookings/elements/EInvoiceInfoComponent.vue +++ b/resources/assets/vue/components/bookings/elements/EInvoiceInfoComponent.vue @@ -16,7 +16,7 @@

MSIC Code

{{ eInvoiceData.msic_code }}

-
+

Billing Address