diff --git a/app/Classes/Jobs/Commands/V2/OneTimeBatchProcessEInvoicesV2CommandJob.php b/app/Classes/Jobs/Commands/V2/OneTimeBatchProcessEInvoicesV2CommandJob.php new file mode 100644 index 00000000..26783cbe --- /dev/null +++ b/app/Classes/Jobs/Commands/V2/OneTimeBatchProcessEInvoicesV2CommandJob.php @@ -0,0 +1,44 @@ +booking = $booking; + } + + public function handle() + { + Log::info(Carbon::now() . ': Start job - Processing single booking for E-Invoices for July 2025.'); + $start = new Carbon(); + + $isAllowNormalInvoice = true; + (App()->make(RegenerateInvoiceBookingProcessor::class))->execute($this->booking, $isAllowNormalInvoice); + + $end = new Carbon(); + $elapsedTime = $start->diff($end)->format('%H:%I:%S'); + Log::info(Carbon::now() . ': End job - Processing single booking for E-Invoices for July 2025. ElapsedTime: ' . $elapsedTime . '.'); + } +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php index 39db1708..bf88251f 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php @@ -69,8 +69,9 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic 'with_transactions' => true ] ); + $normalInvoice = $request->input('normal_invoice', false); - $this->regenerateInvoiceBookingProcessor->execute($booking); + $this->regenerateInvoiceBookingProcessor->execute($booking, $normalInvoice); return $this->resourceResponse(new BookingResource($booking)); } diff --git a/app/Classes/Modules/Bookings/Processors/RegenerateInvoiceBookingProcessor.php b/app/Classes/Modules/Bookings/Processors/RegenerateInvoiceBookingProcessor.php index 38d89f08..7b392d08 100644 --- a/app/Classes/Modules/Bookings/Processors/RegenerateInvoiceBookingProcessor.php +++ b/app/Classes/Modules/Bookings/Processors/RegenerateInvoiceBookingProcessor.php @@ -14,6 +14,7 @@ use App\Classes\ValueObjects\Constants\TransactionType; use App\Models\Booking; use App\Models\Transaction; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Log; class RegenerateInvoiceBookingProcessor { @@ -48,7 +49,7 @@ class RegenerateInvoiceBookingProcessor $this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor; } - public function execute(Booking $booking) + public function execute(Booking $booking, bool $isAllowNormalInvoice = false) { $this->updatesBookingStatus->execute($booking, ApprovalStatus::APPROVED); @@ -58,6 +59,8 @@ class RegenerateInvoiceBookingProcessor ->orderBy('created_at', 'asc') ->first(); + Log::info('RegenerateInvoiceBookingProcessor booking: ' . json_encode($booking->marking)); + // get the first bill_no if($firstInvoice){ $firstBillNo = $firstInvoice->bill_no; @@ -90,10 +93,10 @@ class RegenerateInvoiceBookingProcessor $this->deletesDocument->execute($row); } - $this->createInvoiceTransactionProcessor->execute($booking, $firstBillNo, true); + $this->createInvoiceTransactionProcessor->execute($booking, $firstBillNo, true, $isAllowNormalInvoice); } else { - $this->createInvoiceTransactionProcessor->execute($booking); + $this->createInvoiceTransactionProcessor->execute($booking, "", false, $isAllowNormalInvoice); } } } diff --git a/app/Classes/Modules/Exports/Services/ExportsNullDebtors.php b/app/Classes/Modules/Exports/Services/ExportsNullDebtors.php index 11e48130..54523cfa 100644 --- a/app/Classes/Modules/Exports/Services/ExportsNullDebtors.php +++ b/app/Classes/Modules/Exports/Services/ExportsNullDebtors.php @@ -71,6 +71,8 @@ class ExportsNullDebtors implements FromQuery, WithHeadings, WithHeadingRow, Wit */ public function map($company): array { + $employee = $company->employees()->orderBy('id', 'DESC')->first(); + return [ '<>', // Code '300-0000', // DebtorControlAcc @@ -89,7 +91,7 @@ class ExportsNullDebtors implements FromQuery, WithHeadings, WithHeadingRow, Wit '', // DeliverAddr2 '', // DeliverAddr3 '', // DeliverPostCode - '', // EmailAddress + $employee->email, // EmailAddress '', // Attention '', // Phone1 '', // Phone2 diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php index 2267e51e..8f36ea91 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php @@ -44,7 +44,7 @@ class CreateInvoiceDocumentProcessor * @return void * @throws \App\Classes\Exceptions\MalformedRequestException */ - public function execute($transaction, $purchaseOrder, $supplier, $document_type, $voucherRedemption = null) + public function execute($transaction, $purchaseOrder, $supplier, $document_type, $voucherRedemption = null, $isAllowNormalInvoice = false) { // calculate current Paid Amount $booking = $transaction->owner_type == Booking::class ? $transaction->owner : null; @@ -63,9 +63,9 @@ class CreateInvoiceDocumentProcessor if ($bookingCreatedDate->isAfter($eInvoiceStartDate)) { $lastPaymentTransaction = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->latest()->first(); $documentDate = $lastPaymentTransaction->created_at; - if(Carbon::parse($booking->updated_at)->isAfter($lastPaymentTransaction->created_at)){ - $documentDate = $booking->updated_at; - } + // if(Carbon::parse($booking->updated_at)->isAfter($lastPaymentTransaction->created_at)){ //cief todo: 90 - Batch generate E-Invoice date incorrect + // $documentDate = $booking->updated_at; + // } } if($document_type === DocumentType::EINVOICE){ @@ -88,6 +88,12 @@ class CreateInvoiceDocumentProcessor $lowercaseDocumentType = strtolower($document_type); + if($document_type === DocumentType::EINVOICE){ //July 2025 workaround generate normal invoice instead of E-Invoice + if($isAllowNormalInvoice){ + $lowercaseDocumentType = strtolower(DocumentType::INVOICE); + } + } + $order_pdf = LaravelMpdf::loadView('pages.pdfs.' . $lowercaseDocumentType, [ 'transaction' => $transaction, diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php index e8c7ff21..44f0dbbf 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php @@ -21,6 +21,7 @@ use App\Classes\ValueObjects\Constants\DocumentType; use App\Models\Booking; use App\Models\SegmentConstant; use Carbon\Carbon; +use Illuminate\Support\Facades\Log; class CreateInvoiceTransactionProcessor { @@ -89,7 +90,7 @@ class CreateInvoiceTransactionProcessor * @return void * @throws MalformedRequestException */ - public function execute(Booking $booking, String $invoiceNo= "", bool $isAllowEInvoice = false) + public function execute(Booking $booking, String $invoiceNo= "", bool $isAllowEInvoice = false, bool $isAllowNormalInvoice = false) { if ($booking->status === ApprovalStatus::COMPLETED) { @@ -137,11 +138,18 @@ class CreateInvoiceTransactionProcessor } // $eInvoice = true; //cief todo: 90 - for testing + if($isAllowNormalInvoice){ + $invoiceNo = ""; //July 2025 workaround generate normal invoice instead of E-Invoice + } + if($invoiceNo){ $billNumber = $invoiceNo; } else{ $billNUmberPrefix = $eInvoice ? 'EINV-' : 'INV-'; + if($isAllowNormalInvoice){ + $billNUmberPrefix = 'INV-'; //July 2025 workaround generate normal invoice instead of E-Invoice + } $billNumber = $this->generatesTransactionBillNumber->execute($billNUmberPrefix); } @@ -189,7 +197,7 @@ class CreateInvoiceTransactionProcessor if ($eInvoice) { if($isAllowEInvoice){ - $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::EINVOICE, $voucherRedemption); + $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::EINVOICE, $voucherRedemption, $isAllowNormalInvoice); } } // invoice diff --git a/app/Console/Commands/V2/OneTimeBatchProcessEInvoicesV2Command.php b/app/Console/Commands/V2/OneTimeBatchProcessEInvoicesV2Command.php new file mode 100644 index 00000000..f47ffd03 --- /dev/null +++ b/app/Console/Commands/V2/OneTimeBatchProcessEInvoicesV2Command.php @@ -0,0 +1,80 @@ +startOfDay(); + $endDate = Carbon::create(2025, 7, 31)->endOfDay(); + + $bookings = Booking::where('status', ApprovalStatus::COMPLETED) + ->whereBetween('created_at', [$startDate, $endDate]) + ->get(); + + $count = 0; + foreach ($bookings as $booking) { + $firstInvoice = $booking->transactions() + ->whereIn('type', [TransactionType::INVOICE]) + ->withTrashed() + ->whereBetween('created_at', [$startDate, $endDate]) + ->orderBy('created_at', 'asc') + ->first(); + + $normalInvoice = $booking->documents()->where('document_type', DocumentType::INVOICE)->first(); + $eInvoice = $booking->documents()->where('document_type', DocumentType::EINVOICE)->first(); + + if($firstInvoice && !$normalInvoice && !$eInvoice){ + OneTimeBatchProcessEInvoicesV2CommandJob::dispatch($booking); + $count++; + Log::info('Processed: ' . $count); + Log::info('Booking ID: ' . $booking->marking . ' | created_at: ' . $booking->created_at); + } + } + } +} diff --git a/app/Http/Controllers/Reports/UnfinishedPaymentOrders.php b/app/Http/Controllers/Reports/UnfinishedPaymentOrders.php index c3bda14a..6266b4a1 100644 --- a/app/Http/Controllers/Reports/UnfinishedPaymentOrders.php +++ b/app/Http/Controllers/Reports/UnfinishedPaymentOrders.php @@ -13,7 +13,7 @@ class UnfinishedPaymentOrders extends Controller public function execute(Request $request) { $page = (int) $request->input('page', 1); - $perPage = 5000; + $perPage = 2500; $offset = ($page - 1) * $perPage; $cutOffDate = $request->cut_off_date ? Carbon::parse($request->cut_off_date) : null; @@ -126,9 +126,9 @@ function runNextBatch() { const row = document.createElement('tr'); row.innerHTML = ` \${item.order_ref} - RM \${item.booking_amount} - RM \${item.paid_amount} - RM \${item.outstanding_amount} + \${item.booking_amount} + \${item.paid_amount} + \${item.outstanding_amount} \${item.customer ?? '-'} \${item.created_at} `; diff --git a/resources/assets/vue/components/bookings/forms/RegenerateEInvoiceComponent.vue b/resources/assets/vue/components/bookings/forms/RegenerateEInvoiceComponent.vue index 6d6d15f9..1d2dd9af 100644 --- a/resources/assets/vue/components/bookings/forms/RegenerateEInvoiceComponent.vue +++ b/resources/assets/vue/components/bookings/forms/RegenerateEInvoiceComponent.vue @@ -29,6 +29,7 @@ export default { methods: { submitForm() { + this.parameters.normal_invoice = false; this.submit(this.route('api.booking.einvoice.regenerate', this.data.id), 'post', this.section, true, true); }, successHandler(){ diff --git a/resources/assets/vue/components/bookings/forms/RegenerateNormalInvoiceEInvoiceComponent.vue b/resources/assets/vue/components/bookings/forms/RegenerateNormalInvoiceEInvoiceComponent.vue new file mode 100644 index 00000000..b3279d3e --- /dev/null +++ b/resources/assets/vue/components/bookings/forms/RegenerateNormalInvoiceEInvoiceComponent.vue @@ -0,0 +1,42 @@ + + diff --git a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue index 68dffd3a..c7717536 100644 --- a/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue +++ b/resources/assets/vue/components/bookings/sections/BookingDetailsSectionComponent.vue @@ -334,7 +334,7 @@ -
+
Regenerate E-Invoice
@@ -342,6 +342,14 @@
+
+
+
Regenerate Normal Inv
+
+ + + +
@@ -497,7 +505,7 @@
-
+
Change Booking Owner
@@ -614,7 +622,7 @@