From b34ac0f1d3f1627e6fde6c43afddd5818a0e692b Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Sat, 2 Aug 2025 04:03:59 +0800 Subject: [PATCH 01/11] E-Invoice - Automapping Issues, Receive Payment Deposit Entry Report (Export) --- ...xportsReceivePaymentDepositEntryReport.php | 97 +++++++++++++++++++ .../Controllers/Exports/ExportController.php | 36 +++++++ .../elements/DownloadUploadComponent.vue | 6 +- routes/export.php | 1 + 4 files changed, 138 insertions(+), 2 deletions(-) create mode 100644 app/Classes/Modules/Exports/Services/ExportsReceivePaymentDepositEntryReport.php diff --git a/app/Classes/Modules/Exports/Services/ExportsReceivePaymentDepositEntryReport.php b/app/Classes/Modules/Exports/Services/ExportsReceivePaymentDepositEntryReport.php new file mode 100644 index 00000000..abdc7fba --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsReceivePaymentDepositEntryReport.php @@ -0,0 +1,97 @@ +startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(1); + $this->endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now(); + } + + public function headings(): array + { + return [ + 'DocDate', + 'DebtorCode', + 'Description', + 'DeptNo', + 'DepositPaymentMethod', + 'PaymentMethod', + 'PaymentAmt', + ]; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + $type = TransactionType::PAYMENT; + $query = Transaction::query(); + // $query->where('owner_type', '!=', Wallet::class); + $query->where('type', $type); + $query->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + $query->whereBetween('created_at', [$this->startDate, $this->endDate]); + + return $query; + } + + /** + * @param Transaction $transaction + * @return array + */ + public function map($transaction): array + { + $formattedDocumentDate = Carbon::parse($transaction->created_at)->format('m/d/Y'); + $owner = $transaction->owner; + $booking = null; + if($owner instanceof Booking){ + $booking = $owner; + $company = $booking->company; + } + else{ + $company = $owner->owner; + } + + $paymentMethod = ''; + if($transaction->payment_method == PaymentMethodType::WALLET){ + $paymentMethod = 'Wallet Deposit - Exc'; + if($owner instanceof Booking){ + return[]; + } + } + else{ + $paymentMethod = 'MBB'; + } + + return [ + $formattedDocumentDate, //DocDate + $company ? $company->debtor : '', //DebtorCode + $booking ? $booking->marking : '', //Description + 'C', //DeptNo + 'SALES DEPOSIT - EXC', //DepositPaymentMethod + $paymentMethod, //PaymentMethod + number_format($transaction->amount, 2), //PaymentAmt + ]; + } +} diff --git a/app/Http/Controllers/Exports/ExportController.php b/app/Http/Controllers/Exports/ExportController.php index 3b4836a3..bfd6b97a 100644 --- a/app/Http/Controllers/Exports/ExportController.php +++ b/app/Http/Controllers/Exports/ExportController.php @@ -10,6 +10,7 @@ use Illuminate\Support\Facades\Storage; use App\Classes\General\AWSS3Helper; use App\Classes\Modules\Exports\Services\ExportsARCreditNoteReport; use App\Classes\Modules\Exports\Services\ExportsCompanies; +use App\Classes\Modules\Exports\Services\ExportsReceivePaymentDepositEntryReport; use Carbon\Carbon; class ExportController @@ -119,4 +120,39 @@ class ExportController } return $response; } + + public function receivePaymentDepositEntry(Request $request){ + $validated = $request->validate([ + 'startDate' => 'nullable|date_format:d-m-Y', + 'endDate' => 'nullable|date_format:d-m-Y|after_or_equal:startDate', + ]); + + $startDate = null; + $endDate = null; + + if (isset($validated['startDate']) && $validated['startDate']) { + $startDate = Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay(); + } else { + $startDate = Carbon::now()->subMonths(1)->startOfDay(); + } + + if (isset($validated['endDate']) && $validated['endDate']) { + $endDate = Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay(); + } else { + $endDate = Carbon::now()->endOfDay(); + } + + $exportsTransactions = new ExportsReceivePaymentDepositEntryReport($startDate, $endDate); + + $exportFileName = '01D - EXCHANGE - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY].xls'; + $filesystemDriver = Storage::getDefaultDriver(); + if($filesystemDriver === 's3'){ + return response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $exportsTransactions) ]); + } + else{ + $response = $exportsTransactions->download($exportFileName, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + ob_end_clean(); + } + return $response; + } } diff --git a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue index 1461d0c6..f9373e19 100644 --- a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue +++ b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue @@ -115,7 +115,8 @@ export default { return [ 'Sales Invoice Report', 'Customers Report', - 'AR Credit Note Report', + '01D - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY]', + 'Credit Note Report', ]; }, handleExportClick(){ @@ -126,7 +127,8 @@ export default { const routesMap = { 'Sales Invoice Report': route('api.export.bookings.sales-invoices'), 'Customers Report': route('api.export.companies.customers-data'), - 'AR Credit Note Report': route('api.export.transactions.ar-credit-note'), + '01D - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY]': route('api.export.transactions.receive-payment-deposit-entry'), + 'Credit Note Report': route('api.export.transactions.ar-credit-note'), }; let url = `${routesMap[reportType]}?startDate=${this.parameters.startDate}&endDate=${this.parameters.endDate}`; diff --git a/routes/export.php b/routes/export.php index 4801bc4e..4d80d537 100644 --- a/routes/export.php +++ b/routes/export.php @@ -14,6 +14,7 @@ Route::group(['prefix' => 'export', 'as' => 'export.', 'namespace' => 'Exports'] }); Route::group(['prefix' => 'transactions', 'as' => 'transactions.'], function () { Route::get('/ar-credit-note', [ExportController::class, 'arCreditNote'])->name('ar-credit-note'); + Route::get('/receive-payment-deposit-entry', [ExportController::class, 'receivePaymentDepositEntry'])->name('receive-payment-deposit-entry'); }); }); From 15d9127eecb318a625aae80d435406351e5c34a3 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 7 Aug 2025 13:27:28 +0800 Subject: [PATCH 02/11] E-Invoice - Automapping Issues, Receive Payment for Booking Report (Export) --- .../ExportsReceivePaymentForBookingReport.php | 106 +++++++++++ .../Controllers/Exports/ExportController.php | 168 +++++------------- .../elements/DownloadUploadComponent.vue | 10 +- .../bookings/elements/UploadComponent.vue | 2 +- routes/export.php | 11 +- 5 files changed, 167 insertions(+), 130 deletions(-) create mode 100644 app/Classes/Modules/Exports/Services/ExportsReceivePaymentForBookingReport.php diff --git a/app/Classes/Modules/Exports/Services/ExportsReceivePaymentForBookingReport.php b/app/Classes/Modules/Exports/Services/ExportsReceivePaymentForBookingReport.php new file mode 100644 index 00000000..0958b037 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsReceivePaymentForBookingReport.php @@ -0,0 +1,106 @@ +startDate = $startDate ? Carbon::parse($startDate)->startOfDay() : Carbon::now()->subMonths(1); + $this->endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now(); + } + + public function headings(): array + { + return [ + 'DocNo', + 'Docdate', + 'DebtorCode', + 'Description', + 'DeptNo', + 'PaymentMethod', + 'PaymentAmt', + 'KnockOffDocNo', + 'KnockOffAmt', + ]; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + $type = TransactionType::PAYMENT; + $query = Transaction::query(); + // $query->where('owner_type', '!=', Wallet::class); + $query->where('type', $type); + $query->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + $query->whereBetween('created_at', [$this->startDate, $this->endDate]); + + return $query; + } + + /** + * @param Transaction $transaction + * @return array + */ + public function map($transaction): array + { + $autoCountSalesInvoiceId = null; + $formattedDocumentDate = Carbon::parse($transaction->created_at)->format('m/d/Y'); + $owner = $transaction->owner; + $booking = null; + if($owner instanceof Booking){ + $booking = $owner; + $company = $booking->company; + } + else{ + $company = $owner->owner; + } + + if($booking){ + $metadata = $booking->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO)->first(); + if($metadata){ + $autoCountSalesInvoiceId = $metadata->value; + } + } + + if($transaction->payment_method == PaymentMethodType::WALLET){ + if($owner instanceof Wallet){ + return[]; + } + } + + return [ + '<>', //DocNo + $formattedDocumentDate, //DocDate + $company ? $company->debtor : '', //DebtorCode + 'Payment for ' . $autoCountSalesInvoiceId ?? '', //Description + 'C', //DeptNo + 'SALES DEPOSIT - EXC', //PaymentMethod + number_format($transaction->amount, 2), //PaymentAmt + $autoCountSalesInvoiceId ?? '', //KnockOffDocNo + number_format($transaction->amount, 2), //KnockOffAmt + ]; + } +} diff --git a/app/Http/Controllers/Exports/ExportController.php b/app/Http/Controllers/Exports/ExportController.php index bfd6b97a..3e482509 100644 --- a/app/Http/Controllers/Exports/ExportController.php +++ b/app/Http/Controllers/Exports/ExportController.php @@ -11,148 +11,76 @@ use App\Classes\General\AWSS3Helper; use App\Classes\Modules\Exports\Services\ExportsARCreditNoteReport; use App\Classes\Modules\Exports\Services\ExportsCompanies; use App\Classes\Modules\Exports\Services\ExportsReceivePaymentDepositEntryReport; +use App\Classes\Modules\Exports\Services\ExportsReceivePaymentForBookingReport; use Carbon\Carbon; class ExportController { public function salesInvoices(Request $request){ - $validated = $request->validate([ - 'startDate' => 'nullable|date_format:d-m-Y', - 'endDate' => 'nullable|date_format:d-m-Y|after_or_equal:startDate', - ]); - - $startDate = null; - $endDate = null; - - if (isset($validated['startDate']) && $validated['startDate']) { - $startDate = Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay(); - } else { - $startDate = Carbon::now()->subMonths(1)->startOfDay(); - } - - if (isset($validated['endDate']) && $validated['endDate']) { - $endDate = Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay(); - } else { - $endDate = Carbon::now()->endOfDay(); - } - - - $exportsTransactions = new ExportsSalesInvoiceReport($startDate, $endDate); - - $exportFileName = 'Exchange - Sales Invoice Report.xls'; - $filesystemDriver = Storage::getDefaultDriver(); - if($filesystemDriver === 's3'){ - return response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $exportsTransactions) ]); - } - else{ - $response = $exportsTransactions->download($exportFileName, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); - ob_end_clean(); - } - return $response; + [$startDate, $endDate] = $this->getValidatedDates($request); + $exporter = new ExportsSalesInvoiceReport($startDate, $endDate); + return $this->handleExport($exporter, 'Exchange - Sales Invoice Report.xls'); } public function companies(Request $request){ + [$startDate, $endDate] = $this->getValidatedDates($request); + $exporter = new ExportsCompanies($startDate, $endDate); + return $this->handleExport($exporter, 'Exchange - Customers Data Report.xls'); + } + + public function arCreditNote(Request $request){ + [$startDate, $endDate] = $this->getValidatedDates($request); + $exporter = new ExportsARCreditNoteReport($startDate, $endDate); + return $this->handleExport($exporter, 'Exchange - AR Credit Note Report.xls'); + } + + public function receivePaymentDepositEntry(Request $request){ + [$startDate, $endDate] = $this->getValidatedDates($request); + $exporter = new ExportsReceivePaymentDepositEntryReport($startDate, $endDate); + return $this->handleExport($exporter, '01D - EXCHANGE - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY].xls'); + } + + public function receivePaymentDepositForBooking(Request $request){ + [$startDate, $endDate] = $this->getValidatedDates($request); + $exporter = new ExportsReceivePaymentForBookingReport($startDate, $endDate); + return $this->handleExport($exporter, '01R- RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT].xls'); + } + + private function getValidatedDates(Request $request): array + { $validated = $request->validate([ 'startDate' => 'nullable|date_format:d-m-Y', 'endDate' => 'nullable|date_format:d-m-Y|after_or_equal:startDate', ]); - $startDate = null; - $endDate = null; + $startDate = isset($validated['startDate']) && $validated['startDate'] + ? Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay() + : Carbon::now()->subMonth()->startOfDay(); - if (isset($validated['startDate']) && $validated['startDate']) { - $startDate = Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay(); - } else { - $startDate = Carbon::now()->subMonths(1)->startOfDay(); - } + $endDate = isset($validated['endDate']) && $validated['endDate'] + ? Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay() + : Carbon::now()->endOfDay(); - if (isset($validated['endDate']) && $validated['endDate']) { - $endDate = Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay(); - } else { - $endDate = Carbon::now()->endOfDay(); - } - - $exportsCompanies = new ExportsCompanies($startDate, $endDate); - - $exportFileName = 'Exchange - Customers Data Report.xls'; - $filesystemDriver = Storage::getDefaultDriver(); - if($filesystemDriver === 's3'){ - return response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $exportsCompanies) ]); - } - else{ - $response = $exportsCompanies->download($exportFileName, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); - ob_end_clean(); - } - return $response; + return [$startDate, $endDate]; } - public function arCreditNote(Request $request){ - $validated = $request->validate([ - 'startDate' => 'nullable|date_format:d-m-Y', - 'endDate' => 'nullable|date_format:d-m-Y|after_or_equal:startDate', - ]); - - $startDate = null; - $endDate = null; - - if (isset($validated['startDate']) && $validated['startDate']) { - $startDate = Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay(); - } else { - $startDate = Carbon::now()->subMonths(1)->startOfDay(); - } - - if (isset($validated['endDate']) && $validated['endDate']) { - $endDate = Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay(); - } else { - $endDate = Carbon::now()->endOfDay(); - } - - $exportsTransactions = new ExportsARCreditNoteReport($startDate, $endDate); - - $exportFileName = 'Exchange - AR Credit Note Report.xls'; + private function handleExport($exporter, string $exportFileName) + { $filesystemDriver = Storage::getDefaultDriver(); - if($filesystemDriver === 's3'){ - return response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $exportsTransactions) ]); - } - else{ - $response = $exportsTransactions->download($exportFileName, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); - ob_end_clean(); - } - return $response; - } - public function receivePaymentDepositEntry(Request $request){ - $validated = $request->validate([ - 'startDate' => 'nullable|date_format:d-m-Y', - 'endDate' => 'nullable|date_format:d-m-Y|after_or_equal:startDate', - ]); - - $startDate = null; - $endDate = null; - - if (isset($validated['startDate']) && $validated['startDate']) { - $startDate = Carbon::createFromFormat('d-m-Y', $validated['startDate'])->startOfDay(); - } else { - $startDate = Carbon::now()->subMonths(1)->startOfDay(); + if ($filesystemDriver === 's3') { + return response([ + 'src' => AWSS3Helper::S3Exportable($exportFileName, $exporter) + ]); } - if (isset($validated['endDate']) && $validated['endDate']) { - $endDate = Carbon::createFromFormat('d-m-Y', $validated['endDate'])->endOfDay(); - } else { - $endDate = Carbon::now()->endOfDay(); - } + $response = $exporter->download( + $exportFileName, + Excel::XLS, + ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet'] + ); - $exportsTransactions = new ExportsReceivePaymentDepositEntryReport($startDate, $endDate); - - $exportFileName = '01D - EXCHANGE - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY].xls'; - $filesystemDriver = Storage::getDefaultDriver(); - if($filesystemDriver === 's3'){ - return response([ 'src' => AWSS3Helper::S3Exportable($exportFileName, $exportsTransactions) ]); - } - else{ - $response = $exportsTransactions->download($exportFileName, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); - ob_end_clean(); - } + ob_end_clean(); // prevent corrupt download in some environments return $response; } } diff --git a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue index f9373e19..4d350be7 100644 --- a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue +++ b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue @@ -116,6 +116,7 @@ export default { 'Sales Invoice Report', 'Customers Report', '01D - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY]', + '01R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]', 'Credit Note Report', ]; }, @@ -125,10 +126,11 @@ export default { const reportType = this.parameters.reportType; const routesMap = { - 'Sales Invoice Report': route('api.export.bookings.sales-invoices'), - 'Customers Report': route('api.export.companies.customers-data'), - '01D - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY]': route('api.export.transactions.receive-payment-deposit-entry'), - 'Credit Note Report': route('api.export.transactions.ar-credit-note'), + 'Sales Invoice Report': route('api.export.bookings.sales_invoices'), + 'Customers Report': route('api.export.companies.customers_data'), + '01D - RECEIVE PAYMENT (FULL PAYMENT) [AR DEPOSIT ENTRY]': route('api.export.transactions.receive_payment_deposit_entry'), + '01R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]': route('api.export.transactions.receive_payment_for_booking'), + 'Credit Note Report': route('api.export.transactions.ar_credit_note'), }; let url = `${routesMap[reportType]}?startDate=${this.parameters.startDate}&endDate=${this.parameters.endDate}`; diff --git a/resources/assets/vue/components/bookings/elements/UploadComponent.vue b/resources/assets/vue/components/bookings/elements/UploadComponent.vue index 3803d89f..9f165e29 100644 --- a/resources/assets/vue/components/bookings/elements/UploadComponent.vue +++ b/resources/assets/vue/components/bookings/elements/UploadComponent.vue @@ -77,7 +77,7 @@ report_type: this.reportType }; - this.submit(this.route('api.import.sales-invoices'), 'post', this.section, true, true); + this.submit(this.route('api.import.sales_invoices'), 'post', this.section, true, true); } }, mixins: [ModalFromHandler] diff --git a/routes/export.php b/routes/export.php index 4d80d537..2e8f296e 100644 --- a/routes/export.php +++ b/routes/export.php @@ -7,17 +7,18 @@ use Illuminate\Support\Facades\Route; Route::group(['prefix' => 'export', 'as' => 'export.', 'namespace' => 'Exports'], function () { Route::group(['prefix' => 'bookings', 'as' => 'bookings.'], function () { - Route::get('/sales-invoices', [ExportController::class, 'salesInvoices'])->name('sales-invoices'); + Route::get('/sales-invoices', [ExportController::class, 'salesInvoices'])->name('sales_invoices'); }); Route::group(['prefix' => 'companies', 'as' => 'companies.'], function () { - Route::get('/customers-data', [ExportController::class, 'companies'])->name('customers-data'); + Route::get('/customers-data', [ExportController::class, 'companies'])->name('customers_data'); }); Route::group(['prefix' => 'transactions', 'as' => 'transactions.'], function () { - Route::get('/ar-credit-note', [ExportController::class, 'arCreditNote'])->name('ar-credit-note'); - Route::get('/receive-payment-deposit-entry', [ExportController::class, 'receivePaymentDepositEntry'])->name('receive-payment-deposit-entry'); + Route::get('/ar-credit-note', [ExportController::class, 'arCreditNote'])->name('ar_credit_note'); + Route::get('/receive-payment-deposit-entry', [ExportController::class, 'receivePaymentDepositEntry'])->name('receive_payment_deposit_entry'); + Route::get('/receive-payment-for-booking', [ExportController::class, 'receivePaymentDepositForBooking'])->name('receive_payment_for_booking'); }); }); Route::group(['prefix' => 'import', 'as' => 'import.', 'namespace' => 'Imports'], function () { - Route::post('/import', [ImportController::class, 'salesInvoices'])->name('sales-invoices'); + Route::post('/import', [ImportController::class, 'salesInvoices'])->name('sales_invoices'); }); From 54bc9d1cfa0c8aef48f6f10b062865203d92a4dc Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Sun, 10 Aug 2025 22:18:46 +0800 Subject: [PATCH 03/11] E-Invoice - Sales Invoice Report, updated filtering logic --- .../Services/ExportsSalesInvoiceReport.php | 27 +++++++++++++------ 1 file changed, 19 insertions(+), 8 deletions(-) diff --git a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php index 74598a8d..cf0a7fe7 100644 --- a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php @@ -14,7 +14,6 @@ use Maatwebsite\Excel\Concerns\WithMapping; use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount; use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundServiceCharge; use Carbon\Carbon; -use Illuminate\Support\Facades\Log; class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize { @@ -60,7 +59,17 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR // $query->where('type', TransactionType::PURCHASE_ORDER)->complete(); // }); - return Booking::where('status', ApprovalStatus::COMPLETED)->whereBetween('created_at', [$this->startDate, $this->endDate]); + // return Booking::where('status', ApprovalStatus::COMPLETED)->whereBetween('created_at', [$this->startDate, $this->endDate]); + + $startDate = $this->startDate; + $endDate = $this->endDate; + return Booking::where('status', ApprovalStatus::COMPLETED) + ->whereHas('transactions', function ($query) use ($startDate, $endDate) { + $query->payments() + ->complete() + ->whereBetween('created_at', [$startDate, $endDate]) + ->latest('created_at'); + }); } /** @@ -76,12 +85,18 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR $purchaseOrder = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first(); $company = $booking->company()->first(); - $lastPaymentTransaction = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->latest()->first(); + + $lastPaymentTransaction = $booking->transactions()->payments()->complete()->latest()->first(); if(!$lastPaymentTransaction){ return $records; } - $invoiceTransaction = $booking->transactions()->where('type', TransactionType::INVOICE)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->first(); + $documentDate = $lastPaymentTransaction->created_at; + if ($documentDate < $this->startDate || $documentDate > $this->endDate) { + return $records; + } + + $invoiceTransaction = $booking->transactions()->where('type', TransactionType::INVOICE)->complete()->first(); $currencyId = $booking->fix_currency_id; @@ -114,10 +129,6 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR $totalPayment = $paymentSum - $refundedAmount - $refundedServiceCharge; } - $documentDate = $lastPaymentTransaction->created_at; - // if(Carbon::parse($booking->updated_at)->isAfter($lastPaymentTransaction->created_at)){ //cief todo: 90 - Report E-Invoice date incorrect - // $documentDate = $booking->updated_at; - // } $formattedDocumentDate = Carbon::parse($documentDate)->format('m/d/Y'); $firstItem = true; From fb3a1668d34c001ad1203a8ccda8cbbc9131f464 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Sun, 10 Aug 2025 22:37:17 +0800 Subject: [PATCH 04/11] E-Invoice - Sales Invoice Report, updated filtering logic --- .../bookings/elements/DownloadUploadComponent.vue | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue index ab1524e8..c28b108e 100644 --- a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue +++ b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue @@ -69,6 +69,9 @@ +
+ {{error}} +
@@ -88,6 +91,7 @@ export default { }, data(){ return { + error: '', parameters: { startDate: '', endDate: '', @@ -125,6 +129,7 @@ export default { ]; }, handleExportClick(){ + this.error = ''; if (!this.validate()) return; const reportType = this.parameters.reportType; @@ -145,6 +150,7 @@ export default { } }, handleGenerateEInvoiceClick(){ + this.error = ''; if (!this.validate()) return; const reportType = this.parameters.reportType; @@ -175,6 +181,7 @@ export default { }, errorHandler(error) { this.isDownloading = false; + this.error = error.message + '. Please try again with a shorter date span between the two date filters.'; }, }, mixins: [componentHandler] From cbf650c8be75a66b750027e2b41d698d0b9ac893 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Sun, 10 Aug 2025 22:50:37 +0800 Subject: [PATCH 05/11] E-Invoice - Sales Invoice Report, updated filtering logic --- .../Modules/Exports/Services/ExportsSalesInvoiceReport.php | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php index cf0a7fe7..5ecc250c 100644 --- a/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsSalesInvoiceReport.php @@ -96,6 +96,10 @@ class ExportsSalesInvoiceReport implements FromQuery, WithHeadings, WithHeadingR return $records; } + if($company->e_invoice === 1){ + $documentDate = $documentDate->copy()->endOfMonth(); + } + $invoiceTransaction = $booking->transactions()->where('type', TransactionType::INVOICE)->complete()->first(); $currencyId = $booking->fix_currency_id; From bdd54cbe318c5dce15960e31fcb87b47a6aa4ce9 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Wed, 13 Aug 2025 02:32:09 +0800 Subject: [PATCH 06/11] E-Invoice - Automapping Issues, Receive Payment Deposit Entry Report (Export) Update --- .../Services/ExportsReceivePaymentDepositEntryReport.php | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/app/Classes/Modules/Exports/Services/ExportsReceivePaymentDepositEntryReport.php b/app/Classes/Modules/Exports/Services/ExportsReceivePaymentDepositEntryReport.php index abdc7fba..995b1e78 100644 --- a/app/Classes/Modules/Exports/Services/ExportsReceivePaymentDepositEntryReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsReceivePaymentDepositEntryReport.php @@ -31,6 +31,7 @@ class ExportsReceivePaymentDepositEntryReport implements FromQuery, WithHeadings public function headings(): array { return [ + 'DocNo', 'DocDate', 'DebtorCode', 'Description', @@ -75,7 +76,7 @@ class ExportsReceivePaymentDepositEntryReport implements FromQuery, WithHeadings $paymentMethod = ''; if($transaction->payment_method == PaymentMethodType::WALLET){ - $paymentMethod = 'Wallet Deposit - Exc'; + $paymentMethod = 'WALLET DEPOSIT - EXC'; if($owner instanceof Booking){ return[]; } @@ -85,6 +86,7 @@ class ExportsReceivePaymentDepositEntryReport implements FromQuery, WithHeadings } return [ + '<>', //DocNo $formattedDocumentDate, //DocDate $company ? $company->debtor : '', //DebtorCode $booking ? $booking->marking : '', //Description From c0b5c5f6d714ac6f9084008a766d085bb9061fac Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Wed, 13 Aug 2025 04:41:12 +0800 Subject: [PATCH 07/11] E-Invoice - Automapping Issues, Receive Payment for Booking Report (Import) Partial Completion --- .../ControllersLogic/ImportExcelLogic.php | 159 ++++++++++++------ .../elements/DownloadUploadComponent.vue | 14 +- 2 files changed, 123 insertions(+), 50 deletions(-) diff --git a/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php b/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php index c9b43488..248d09c1 100644 --- a/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php +++ b/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php @@ -58,7 +58,14 @@ class ImportExcelLogic extends AbstractControllerLogic $reportType = $request->input('report_type'); $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); - foreach ($object->getFiles() as $file){ + + $files = $object->getFiles(); + + if (count($files) > 1) { + throw new MalformedRequestException('Import function can only process one file at a time.'); + } + + foreach ($files as $file) { $collection = Excel::toCollection(null, json_decode($file)->file_info->original->file, null, null, true); $sheet = $collection->first(); @@ -75,6 +82,15 @@ class ImportExcelLogic extends AbstractControllerLogic 'businessactivitydesc', 'debtorcode', 'tradename', 'address', 'postcode', 'phone', 'emailaddress', 'city', 'countrycode', 'statecode' ]; + $paymentReportHeader = [ + 'docno', + 'docdate', + 'debtorcode', + 'description', + 'paymentmethod', + 'paymentamt', + 'knockoffdocno' + ]; if ($reportType === 'Sales Invoice Report') { $optionalColumn = 'einvoicevalidationlink'; @@ -89,53 +105,18 @@ class ImportExcelLogic extends AbstractControllerLogic } elseif ($reportType === 'Customers Report' && $normalizedHeader !== $customersReportHeader) { throw new MalformedRequestException('Uploaded Excel file format is incorrect. Column headers do not match expected format.'); } + elseif ($reportType === '01R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]' && $normalizedHeader !== $paymentReportHeader) { + throw new MalformedRequestException('Uploaded Excel file format is incorrect. Column headers do not match expected format.'); + } - $rows = $sheet->skip(1); - - foreach ($rows as $index => $details) { - $docNo = $details[0] ?? null; - $docDate = $details[1] ?? null; - $debtorCode = $details[2] ?? null; - $ref = $details[3] ?? null; - $shipInfo = $details[4] ?? null; - $accNo = $details[5] ?? null; - $detailDescription = $details[6] ?? null; - $furtherDescription = $details[7] ?? null; - $classification = $details[8] ?? null; - $deptNo = $details[9] ?? null; - $qty = $details[10] ?? null; - $unitPrice = $details[11] ?? null; - $submitEinvoice = $details[12] ?? null; - $consolidatedEinvoice = $details[13] ?? null; - $eInvoiceValidationLink = $details[14] ?? null; // Safe access for the new column - - Log::info("Row {$index} Details:", [ - 'DocNo' => $docNo, - 'DocDate' => $docDate, - 'DebtorCode' => $debtorCode, - 'Ref' => $ref, - 'ShipInfo' => $shipInfo, - 'AccNo' => $accNo, - 'DetailDescription' => $detailDescription, - 'FurtherDescription' => $furtherDescription, - 'Classification' => $classification, - 'DeptNo' => $deptNo, - 'Qty' => $qty, - 'UnitPrice' => $unitPrice, - 'SubmitEinvoice' => $submitEinvoice, - 'ConsolidatedEinvoice' => $consolidatedEinvoice, - 'EInvoiceValidationLink' => $eInvoiceValidationLink, - ]); - - $booking = Booking::where('marking', $ref)->first(); - if($booking){ - if($docNo != "" && $docNo != "<>"){ - $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_DOCNO, $docNo); - } - if($eInvoiceValidationLink){ - $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink); - } - } + if ($reportType === 'Sales Invoice Report') { + $this->processSalesInvoiceReport($sheet); + } + else if ($reportType === '01R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]'){ + $this->processPaymentReport($sheet); + } + else{ + throw new MalformedRequestException('Cannot process report type: ' . $reportType); } } @@ -153,4 +134,88 @@ class ImportExcelLogic extends AbstractControllerLogic $this->createsKeyValuePair->execute($booking, $keyValuePairObject); } } + + private function processSalesInvoiceReport($sheet){ + $rows = $sheet->skip(1); + + foreach ($rows as $index => $details) { + $docNo = $details[0] ?? null; + $docDate = $details[1] ?? null; + $debtorCode = $details[2] ?? null; + $ref = $details[3] ?? null; + $shipInfo = $details[4] ?? null; + $accNo = $details[5] ?? null; + $detailDescription = $details[6] ?? null; + $furtherDescription = $details[7] ?? null; + $classification = $details[8] ?? null; + $deptNo = $details[9] ?? null; + $qty = $details[10] ?? null; + $unitPrice = $details[11] ?? null; + $submitEinvoice = $details[12] ?? null; + $consolidatedEinvoice = $details[13] ?? null; + $eInvoiceValidationLink = $details[14] ?? null; // Safe access for the new column + + Log::info("Row {$index} Details:", [ + 'DocNo' => $docNo, + 'DocDate' => $docDate, + 'DebtorCode' => $debtorCode, + 'Ref' => $ref, + 'ShipInfo' => $shipInfo, + 'AccNo' => $accNo, + 'DetailDescription' => $detailDescription, + 'FurtherDescription' => $furtherDescription, + 'Classification' => $classification, + 'DeptNo' => $deptNo, + 'Qty' => $qty, + 'UnitPrice' => $unitPrice, + 'SubmitEinvoice' => $submitEinvoice, + 'ConsolidatedEinvoice' => $consolidatedEinvoice, + 'EInvoiceValidationLink' => $eInvoiceValidationLink, + ]); + + $booking = Booking::where('marking', $ref)->first(); + if($booking){ + if($docNo != "" && $docNo != "<>"){ + $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_DOCNO, $docNo); + } + if($eInvoiceValidationLink){ + $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink); + } + } + } + } + + private function processPaymentReport($sheet){ + $rows = $sheet->skip(1); + + foreach ($rows as $index => $details) { + $docNo = $details[0] ?? null; + $docDate = $details[1] ?? null; + $debtorCode = $details[2] ?? null; + $description = $details[3] ?? null; + $paymentMethod = $details[4] ?? null; + $paymentAmt = $details[5] ?? null; + $knockOffDocNo = $details[6] ?? null; + + Log::info("Row {$index} Payment Details:", [ + 'DocNo' => $docNo, + 'DocDate' => $docDate, + 'DebtorCode' => $debtorCode, + 'Description' => $description, + 'PaymentMethod' => $paymentMethod, + 'PaymentAmt' => $paymentAmt, + 'KnockOffDocNo' => $knockOffDocNo, + ]); + + // $booking = Booking::where('marking', $ref)->first(); + // if($booking){ + // if($docNo != "" && $docNo != "<>"){ + // $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_DOCNO, $docNo); + // } + // if($eInvoiceValidationLink){ + // $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink); + // } + // } + } + } } diff --git a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue index 4d350be7..6766d83a 100644 --- a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue +++ b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue @@ -33,9 +33,13 @@
@@ -95,6 +99,10 @@ export default { }, isDownloading: false, generateEInvoicesUrl: null, + allowedReportTypes: [ + 'Sales Invoice Report', + '01R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]', + ] } }, validations: { From 0665e897997f22c116f7b87cfa9d7c587ee62424 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Mon, 18 Aug 2025 22:15:42 +0800 Subject: [PATCH 08/11] E-Invoice - Automapping Issues, Receive Payment for Booking Report (Export), added new column PM requested --- .../Exports/Services/ExportsReceivePaymentForBookingReport.php | 2 ++ 1 file changed, 2 insertions(+) diff --git a/app/Classes/Modules/Exports/Services/ExportsReceivePaymentForBookingReport.php b/app/Classes/Modules/Exports/Services/ExportsReceivePaymentForBookingReport.php index 0958b037..32d6e86d 100644 --- a/app/Classes/Modules/Exports/Services/ExportsReceivePaymentForBookingReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsReceivePaymentForBookingReport.php @@ -40,6 +40,7 @@ class ExportsReceivePaymentForBookingReport implements FromQuery, WithHeadings, 'DeptNo', 'PaymentMethod', 'PaymentAmt', + 'KnockOffDocType', 'KnockOffDocNo', 'KnockOffAmt', ]; @@ -99,6 +100,7 @@ class ExportsReceivePaymentForBookingReport implements FromQuery, WithHeadings, 'C', //DeptNo 'SALES DEPOSIT - EXC', //PaymentMethod number_format($transaction->amount, 2), //PaymentAmt + 'RI', //KnockOffDocType $autoCountSalesInvoiceId ?? '', //KnockOffDocNo number_format($transaction->amount, 2), //KnockOffAmt ]; From 5b0c11824d175af4632511c406cdd1af1719f0ee Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 21 Aug 2025 03:21:50 +0800 Subject: [PATCH 09/11] E-Invoice - Automapping Issues, Receive Payment for Booking Report (Import) Partial Completion --- .../ControllersLogic/ImportExcelLogic.php | 42 ++++++++++++++----- app/Classes/ValueObjects/Constants/KVPKey.php | 2 + .../Controllers/Imports/ImportController.php | 6 ++- .../elements/DownloadUploadComponent.vue | 17 +++++++- .../bookings/elements/UploadComponent.vue | 15 ++++++- routes/export.php | 3 +- 6 files changed, 69 insertions(+), 16 deletions(-) diff --git a/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php b/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php index 248d09c1..7c4c539e 100644 --- a/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php +++ b/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php @@ -12,6 +12,7 @@ use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\KVPKey; use App\Models\Booking; +use App\Models\KeyValuePair; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Facades\Log; @@ -55,6 +56,8 @@ class ImportExcelLogic extends AbstractControllerLogic */ public function logic(Request $request) : JsonResponse { + $result = []; + $reportType = $request->input('report_type'); $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); @@ -113,14 +116,20 @@ class ImportExcelLogic extends AbstractControllerLogic $this->processSalesInvoiceReport($sheet); } else if ($reportType === '01R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]'){ - $this->processPaymentReport($sheet); + $result = $this->processPaymentReport($sheet); + $result = [ + 'message' => empty($result) + ? '' + : 'Some payments are unprocessed: ', + 'data' => $result + ]; } else{ throw new MalformedRequestException('Cannot process report type: ' . $reportType); } } - return $this->response([]); + return $this->response($result); } private function updateOrCreateKeyValuePair($booking, $key, $value) @@ -186,6 +195,7 @@ class ImportExcelLogic extends AbstractControllerLogic } private function processPaymentReport($sheet){ + $unprocessedKnockOffs = []; $rows = $sheet->skip(1); foreach ($rows as $index => $details) { @@ -207,15 +217,25 @@ class ImportExcelLogic extends AbstractControllerLogic 'KnockOffDocNo' => $knockOffDocNo, ]); - // $booking = Booking::where('marking', $ref)->first(); - // if($booking){ - // if($docNo != "" && $docNo != "<>"){ - // $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_DOCNO, $docNo); - // } - // if($eInvoiceValidationLink){ - // $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink); - // } - // } + if($knockOffDocNo) + { + $kvp = KeyValuePair::where('key', KVPKey::AUTOCOUNT_DOCNO)->where('value', $knockOffDocNo)->first(); + Log::info('key: ' . json_encode($kvp)); + $booking = $kvp->owner; + if($booking){ + if($docNo != "" && $docNo != "<>"){ + $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_OFFICIAL_RECEIPT_DOCNO, $docNo); + } + // if($eInvoiceValidationLink){ + // $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink); + // } + } + else{ + $unprocessedKnockOffs[] = $knockOffDocNo; + } + } } + + return $unprocessedKnockOffs; } } diff --git a/app/Classes/ValueObjects/Constants/KVPKey.php b/app/Classes/ValueObjects/Constants/KVPKey.php index a15f7d91..50d3f17e 100644 --- a/app/Classes/ValueObjects/Constants/KVPKey.php +++ b/app/Classes/ValueObjects/Constants/KVPKey.php @@ -8,6 +8,8 @@ class KVPKey public const AUTOCOUNT_DOCNO = 'AUTOCOUNT_DOCNO'; + public const AUTOCOUNT_OFFICIAL_RECEIPT_DOCNO = 'AUTOCOUNT_OR_DOCNO'; + public const AUTOCOUNT_EINVOICE_VALIDATION_LINK = 'AUTOCOUNT_EINVOICE_VALIDATION_LINK'; public const CREDIT_NOTE_APPROVAL_DATE = 'CREDIT_NOTE_APPROVAL_DATE'; diff --git a/app/Http/Controllers/Imports/ImportController.php b/app/Http/Controllers/Imports/ImportController.php index 02f364b6..5e045b03 100644 --- a/app/Http/Controllers/Imports/ImportController.php +++ b/app/Http/Controllers/Imports/ImportController.php @@ -9,9 +9,13 @@ use Illuminate\Http\Request; class ImportController extends Controller { - public function salesInvoices(Request $request, ImportExcelLogic $logic): JsonResponse { return $logic->execute($request); } + + public function officialReceipt(Request $request, ImportExcelLogic $logic): JsonResponse + { + return $logic->execute($request); + } } diff --git a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue index e8837794..c43d73dc 100644 --- a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue +++ b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue @@ -44,7 +44,7 @@ Import - +
@@ -122,6 +122,18 @@ export default { }, } }, + computed: { + importUrl() { + const reportType = this.parameters.reportType; + + const importRoutesMap = { + 'Sales Invoice Report': route('api.import.sales_invoices'), + '01R - RECEIVE PAYMENT (FULL PAYMENT) [AR RECEIVE PAYMENT]': route('api.import.official_receipt'), + }; + + return importRoutesMap[reportType] || ''; + } + }, methods: { options() { return [ @@ -190,6 +202,9 @@ export default { this.isDownloading = false; this.error = error.message + '. Please try again with a shorter date span between the two date filters.'; }, + importSuccess(payload) { + this.error = payload.message + payload.data; + } }, mixins: [componentHandler] }; diff --git a/resources/assets/vue/components/bookings/elements/UploadComponent.vue b/resources/assets/vue/components/bookings/elements/UploadComponent.vue index 9f165e29..2eeceba8 100644 --- a/resources/assets/vue/components/bookings/elements/UploadComponent.vue +++ b/resources/assets/vue/components/bookings/elements/UploadComponent.vue @@ -58,6 +58,10 @@ type: String, required: true }, + url: { + type: String, + required: true + }, }, data(){ return { @@ -77,8 +81,15 @@ report_type: this.reportType }; - this.submit(this.route('api.import.sales_invoices'), 'post', this.section, true, true); - } + this.submit(this.url, 'post', this.section, true, true); + }, + successHandler(response) { + this.closeModal(); + this.formHandler(); + if(this.url === route('api.import.official_receipt')){ + this.$emit('importSuccess', response.payload); + } + }, }, mixins: [ModalFromHandler] diff --git a/routes/export.php b/routes/export.php index 2e8f296e..4b1c2576 100644 --- a/routes/export.php +++ b/routes/export.php @@ -20,5 +20,6 @@ Route::group(['prefix' => 'export', 'as' => 'export.', 'namespace' => 'Exports'] }); Route::group(['prefix' => 'import', 'as' => 'import.', 'namespace' => 'Imports'], function () { - Route::post('/import', [ImportController::class, 'salesInvoices'])->name('sales_invoices'); + Route::post('/import/sales-invoice', [ImportController::class, 'salesInvoices'])->name('sales_invoices'); + Route::post('/import/offical-receipt', [ImportController::class, 'officialReceipt'])->name('official_receipt'); }); From 40e3ffe3cbae3f19848ae4758b38ee916f205b07 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 21 Aug 2025 03:39:44 +0800 Subject: [PATCH 10/11] E-Invoice - Automapping Issues, Receive Payment for Booking Report (Import) Partial Completion --- .../ControllersLogic/ImportExcelLogic.php | 22 +++++++++++-------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php b/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php index 7c4c539e..22eb7eb4 100644 --- a/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php +++ b/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php @@ -120,7 +120,7 @@ class ImportExcelLogic extends AbstractControllerLogic $result = [ 'message' => empty($result) ? '' - : 'Some payments are unprocessed: ', + : 'Some data are unprocessed: ', 'data' => $result ]; } @@ -220,15 +220,19 @@ class ImportExcelLogic extends AbstractControllerLogic if($knockOffDocNo) { $kvp = KeyValuePair::where('key', KVPKey::AUTOCOUNT_DOCNO)->where('value', $knockOffDocNo)->first(); - Log::info('key: ' . json_encode($kvp)); - $booking = $kvp->owner; - if($booking){ - if($docNo != "" && $docNo != "<>"){ - $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_OFFICIAL_RECEIPT_DOCNO, $docNo); + if($kvp){ + $booking = $kvp->owner; + if($booking){ + if($docNo != "" && $docNo != "<>"){ + $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_OFFICIAL_RECEIPT_DOCNO, $docNo); + } + // if($eInvoiceValidationLink){ + // $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink); + // } + } + else{ + $unprocessedKnockOffs[] = $knockOffDocNo; } - // if($eInvoiceValidationLink){ - // $this->updateOrCreateKeyValuePair($booking, KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK, $eInvoiceValidationLink); - // } } else{ $unprocessedKnockOffs[] = $knockOffDocNo; From fc410a24aa03bed944d1dd8b9ae1bc384fafae0e Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Fri, 22 Aug 2025 21:15:16 +0800 Subject: [PATCH 11/11] E-Invoice - special handling of cases for those booking done before 1st July 2025 that need to generate E-Invoice --- .../BatchBookingsGenerateEInvoiceLogic.php | 10 ++++++++-- .../Processors/CreateInvoiceTransactionProcessor.php | 6 +++++- app/Classes/ValueObjects/Constants/KVPKey.php | 2 ++ app/Http/Resources/BookingResource.php | 10 +++++++--- 4 files changed, 22 insertions(+), 6 deletions(-) diff --git a/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php index 703fe348..9d44e244 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php @@ -82,7 +82,13 @@ class BatchBookingsGenerateEInvoiceLogic extends AbstractControllerLogic $endDate = $endDate ? Carbon::parse($endDate)->endOfDay() : Carbon::now(); $bookings = Booking::where('status', ApprovalStatus::COMPLETED) - ->whereBetween('created_at', [$startDate, $endDate]) + // ->whereBetween('created_at', [$startDate, $endDate]) + ->whereHas('transactions', function ($query) use ($startDate, $endDate) { + $query->payments() + ->complete() + ->whereBetween('created_at', [$startDate, $endDate]) + ->latest('created_at'); + }) ->whereHas('attributesKVP', function (Builder $query) { $query->where('key', KVPKey::AUTOCOUNT_DOCNO); }) @@ -92,7 +98,7 @@ class BatchBookingsGenerateEInvoiceLogic extends AbstractControllerLogic ->get(); foreach ($bookings as $booking) { - // $autocountValue = optional($booking->attributesKVP->first())->value; + //$autocountValue = optional($booking->attributesKVP->first())->value; //Log::info('Booking ID: ' . $booking->marking . ' | AUTOCOUNT_DOCNO: ' . $autocountValue); // $this->regenerateInvoiceBookingProcessor->execute($booking); ProcessBookingForEInvoiceV2CommandJob::dispatch($booking); diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php index 44f0dbbf..799032ab 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php @@ -18,6 +18,7 @@ use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\SegmentConstants; use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\ValueObjects\Constants\DocumentType; +use App\Classes\ValueObjects\Constants\KVPKey; use App\Models\Booking; use App\Models\SegmentConstant; use Carbon\Carbon; @@ -136,7 +137,10 @@ class CreateInvoiceTransactionProcessor if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $supplier->e_invoice === 1) { $eInvoice = true; } - // $eInvoice = true; //cief todo: 90 - for testing + $kvp = $booking->attributesKVP()->where('key', KVPKey::BOOKING_EINVOICE_ELIGIBLE)->first(); + if($kvp){ + $eInvoice = true; + } if($isAllowNormalInvoice){ $invoiceNo = ""; //July 2025 workaround generate normal invoice instead of E-Invoice diff --git a/app/Classes/ValueObjects/Constants/KVPKey.php b/app/Classes/ValueObjects/Constants/KVPKey.php index 50d3f17e..b2943b4c 100644 --- a/app/Classes/ValueObjects/Constants/KVPKey.php +++ b/app/Classes/ValueObjects/Constants/KVPKey.php @@ -16,4 +16,6 @@ class KVPKey public const TRANSACTION_MODEL_CLASS = 'App\Models\Transaction'; + public const BOOKING_EINVOICE_ELIGIBLE = 'BOOKING_EINVOICE_ELIGIBLE'; + } diff --git a/app/Http/Resources/BookingResource.php b/app/Http/Resources/BookingResource.php index 449c6a59..dbb11d0c 100644 --- a/app/Http/Resources/BookingResource.php +++ b/app/Http/Resources/BookingResource.php @@ -10,6 +10,7 @@ use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\BookingAttributeNames; use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\ValueObjects\Constants\DocumentType; +use App\Classes\ValueObjects\Constants\KVPKey; use Carbon\Carbon; use Illuminate\Http\Resources\Json\JsonResource; @@ -32,9 +33,12 @@ class BookingResource extends JsonResource if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $this->company->e_invoice === 1) { //&& $bookingCreatedDate->diffInMinutes($eInvoiceRequestedDate) <= 480 cief todo: 90 $eInvoice = true; } - // if ($this->company->e_invoice === 1) { - // $eInvoice = true; - // } + + $kvp = $this->attributesKVP()->where('key', KVPKey::BOOKING_EINVOICE_ELIGIBLE)->first(); + if($kvp){ + $eInvoice = true; + } + return [ 'id' => $this->id, 'company' => new CompanyResource($this->company),