From e6b73b2261a1a9c16f29af15e9d1c21322fcea2e Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 31 Jul 2025 22:23:35 +0800 Subject: [PATCH 1/5] E-Invoice - Automapping Issues, AR Credit Note Report (Export) --- .../BatchBookingsGenerateEInvoiceLogic.php | 7 +- .../Services/ExportsARCreditNoteReport.php | 124 ++++++++++++++++++ .../ControllersLogic/ImportExcelLogic.php | 13 +- .../CreateInvoiceDocumentProcessor.php | 5 +- .../Services/UpdatesTransactionStatus.php | 32 ++++- app/Classes/ValueObjects/Constants/KVPKey.php | 15 +++ .../Controllers/Exports/ExportController.php | 36 +++++ .../elements/DownloadUploadComponent.vue | 9 +- routes/export.php | 3 + 9 files changed, 226 insertions(+), 18 deletions(-) create mode 100644 app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php create mode 100644 app/Classes/ValueObjects/Constants/KVPKey.php diff --git a/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php index 1b467042..703fe348 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/BatchBookingsGenerateEInvoiceLogic.php @@ -8,6 +8,7 @@ use App\Classes\Jobs\Commands\V2\ProcessBookingForEInvoiceV2CommandJob; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Models\Booking; use App\Classes\Modules\Bookings\Processors\RegenerateInvoiceBookingProcessor; +use App\Classes\ValueObjects\Constants\KVPKey; use Carbon\Carbon; use Illuminate\Database\Eloquent\Builder; use Illuminate\Http\JsonResponse; @@ -27,7 +28,7 @@ class BatchBookingsGenerateEInvoiceLogic extends AbstractControllerLogic return [ 'title' => 'Generate Bookings E-Invoices', 'message' => sprintf( - 'You have successfully submitted %d booking%s for E-Invoices.', + 'You have successfully submitted %d booking%s for E-Invoices processing.', $this->processedCount, $this->processedCount === 1 ? '' : 's' ), @@ -83,10 +84,10 @@ class BatchBookingsGenerateEInvoiceLogic extends AbstractControllerLogic $bookings = Booking::where('status', ApprovalStatus::COMPLETED) ->whereBetween('created_at', [$startDate, $endDate]) ->whereHas('attributesKVP', function (Builder $query) { - $query->where('key', 'AUTOCOUNT_DOCNO'); + $query->where('key', KVPKey::AUTOCOUNT_DOCNO); }) ->with(['attributesKVP' => function ($query) { - $query->where('key', 'AUTOCOUNT_DOCNO'); + $query->where('key', KVPKey::AUTOCOUNT_DOCNO); }]) ->get(); diff --git a/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php b/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php new file mode 100644 index 00000000..c2bd406a --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php @@ -0,0 +1,124 @@ +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', + 'Ref', + 'Description', + 'Reason', + 'DeptNo', + 'Qty', + 'UnitPrice', + 'AccNo', + 'submiteinvoice', + 'ConsolidatedEinvoice', + 'KnockOffDocNo', + 'KnockOffAmt', + ]; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + $type = TransactionType::CREDIT_NOTE; + $query = Transaction::query(); + + $query->where('type', $type); + // $query->where('owner_type', Wallet::class); + $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 + { + $booking = null; + $autoCountSalesInvoiceId = null; + $formattedDocumentDate = null; + + $company = $transaction->owner->owner; + $kvps = KeyValuePair::where('value', $transaction->id) + ->where('key', 'App\Models\Transaction') + ->orderByDesc('created_at') + ->get(); + + foreach ($kvps as $kvp) { + if ($kvp && $kvp->owner && $kvp->owner->owner && $kvp->owner->owner->type === 1) { + $booking = $kvp->owner->owner->booking; + if($booking){ + $metadata = $booking->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO)->first(); + if($metadata){ + $autoCountSalesInvoiceId = $metadata->value; + } + break; + } + } + } + + $documentDate = $transaction->created_at; + $metadata = $transaction->attributesKVP()->where('key', KVPKey::APPROVAL_DATE)->latest('created_at')->first(); + if($metadata){ + $documentDate = Carbon::parse($metadata->value); + } + if($company->e_invoice === 1){ + $documentDate = $documentDate->copy()->endOfMonth(); + } + $formattedDocumentDate = Carbon::parse($documentDate)->format('d/m/Y'); + + return [ + '<>', //DocNo + $formattedDocumentDate, //DocDate + $company->debtor, //DebtorCode + $booking ? $booking->marking : '', //Ref + $transaction->payment_reference, //Description + $transaction->payment_reference, //Reason + 'C', //DeptNo + '1', //Qty + number_format($transaction->amount, 2), //UnitPrice + '511-0000', //AccNo + 'F', //submiteinvoice + $company->e_invoice ? 'F' : 'T', //ConsolidatedEinvoice + $autoCountSalesInvoiceId ?? '', //KnockOffDocNo + number_format($transaction->amount, 2), //KnockOffAmt + ]; + } +} diff --git a/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php b/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php index a199f75d..c9b43488 100644 --- a/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php +++ b/app/Classes/Modules/Imports/ControllersLogic/ImportExcelLogic.php @@ -10,6 +10,7 @@ use App\Classes\Modules\Accounts\Services\UpdatesKeyValuePair; use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject; use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\ValueObjects\Constants\KVPKey; use App\Models\Booking; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -127,11 +128,13 @@ class ImportExcelLogic extends AbstractControllerLogic ]); $booking = Booking::where('marking', $ref)->first(); - if($docNo != "<>"){ - $this->updateOrCreateKeyValuePair($booking, "AUTOCOUNT_DOCNO", $docNo); - } - if($eInvoiceValidationLink){ - $this->updateOrCreateKeyValuePair($booking, "AUTOCOUNT_EINVOICE_VALIDATION_LINK", $eInvoiceValidationLink); + 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/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php index 80f963ca..2267e51e 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php @@ -7,6 +7,7 @@ use App\Classes\Modules\Documents\Services\CreatesFiles; use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\DocumentType; +use App\Classes\ValueObjects\Constants\KVPKey; use App\Classes\ValueObjects\Constants\TransactionType; use App\Models\Booking; use App\Models\Document; @@ -68,11 +69,11 @@ class CreateInvoiceDocumentProcessor } if($document_type === DocumentType::EINVOICE){ - $metadata = $booking->attributesKVP()->where('key', 'AUTOCOUNT_DOCNO')->first(); + $metadata = $booking->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO)->first(); if($metadata){ $autoCountInvoiceId = $metadata->value; } - $metadata = $booking->attributesKVP()->where('key', 'AUTOCOUNT_EINVOICE_VALIDATION_LINK')->first(); + $metadata = $booking->attributesKVP()->where('key', KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK)->first(); if($metadata){ $autoCountEInvoiceValidationLink = $metadata->value; } diff --git a/app/Classes/Modules/Transactions/Services/UpdatesTransactionStatus.php b/app/Classes/Modules/Transactions/Services/UpdatesTransactionStatus.php index d92e3e9a..43b77aaa 100644 --- a/app/Classes/Modules/Transactions/Services/UpdatesTransactionStatus.php +++ b/app/Classes/Modules/Transactions/Services/UpdatesTransactionStatus.php @@ -3,10 +3,14 @@ namespace App\Classes\Modules\Transactions\Services; use App\Classes\General\Eloquent\AbstractUpdateRecord; +use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject; +use App\Classes\Modules\Accounts\Services\CreatesKeyValuePair; +use App\Classes\Modules\Accounts\Services\UpdatesKeyValuePair; use App\Classes\Modules\PerfexCRM\Processors\TransactionToPerfexCRMProcessorV2; use App\Models\Transaction; use App\Classes\Modules\Vouchers\Processors\Voucherify\TransactionToVoucherifyProcessor; use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\ValueObjects\Constants\KVPKey; use App\Classes\ValueObjects\Constants\TransactionType; class UpdatesTransactionStatus extends AbstractUpdateRecord @@ -17,15 +21,25 @@ class UpdatesTransactionStatus extends AbstractUpdateRecord /** @var TransactionToVoucherifyProcessor */ private $transactionToVoucherifyProcessor; + /** @var CreatesKeyValuePair */ + private $createsKeyValuePair; + + /** @var UpdatesKeyValuePair */ + private $updatesKeyValuePair; + /** * UpdatesTransactionStatus constructor. * @param TransactionToPerfexCRMProcessorV2 $transactionToPerfexCRMProcessor * @param TransactionToVoucherifyProcessor $transactionToVoucherifyProcessor + * @param CreatesKeyValuePair $createsKeyValuePair + * @param UpdatesKeyValuePair $updatesKeyValuePair */ - public function __construct(TransactionToPerfexCRMProcessorV2 $transactionToPerfexCRMProcessor, TransactionToVoucherifyProcessor $transactionToVoucherifyProcessor) + public function __construct(TransactionToPerfexCRMProcessorV2 $transactionToPerfexCRMProcessor, TransactionToVoucherifyProcessor $transactionToVoucherifyProcessor, CreatesKeyValuePair $createsKeyValuePair, UpdatesKeyValuePair $updatesKeyValuePair) { $this->transactionToPerfexCRMProcessor = $transactionToPerfexCRMProcessor; $this->transactionToVoucherifyProcessor = $transactionToVoucherifyProcessor; + $this->createsKeyValuePair = $createsKeyValuePair; + $this->updatesKeyValuePair = $updatesKeyValuePair; } @@ -48,6 +62,22 @@ class UpdatesTransactionStatus extends AbstractUpdateRecord $this->transactionToVoucherifyProcessor->execute($transaction, "PAID"); } + if($status == ApprovalStatus::APPROVED && ($transaction->type == TransactionType::REFUND)){ + $this->updateOrCreateKeyValuePair($transaction, KVPKey::APPROVAL_DATE, now()); + } + return $result; } + + private function updateOrCreateKeyValuePair($transaction, $key, $value) + { + $keyValuePairObject = new KeyValuePairObject($key, $value); + $metadata = $transaction->attributesKVP()->where('key', $key)->first(); + + if ($metadata) { + $this->updatesKeyValuePair->execute($metadata, $keyValuePairObject); + } else { + $this->createsKeyValuePair->execute($transaction, $keyValuePairObject); + } + } } diff --git a/app/Classes/ValueObjects/Constants/KVPKey.php b/app/Classes/ValueObjects/Constants/KVPKey.php new file mode 100644 index 00000000..d3526ba9 --- /dev/null +++ b/app/Classes/ValueObjects/Constants/KVPKey.php @@ -0,0 +1,15 @@ +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'; + $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 ab1524e8..1461d0c6 100644 --- a/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue +++ b/resources/assets/vue/components/bookings/elements/DownloadUploadComponent.vue @@ -97,13 +97,6 @@ export default { generateEInvoicesUrl: null, } }, - mounted(){ - switch(this.section) { - case 'paymentsReportSection': - this.parameters.reportType = 'Sales Invoice Report' - break; - } - }, validations: { parameters: { startDate: { @@ -122,6 +115,7 @@ export default { return [ 'Sales Invoice Report', 'Customers Report', + 'AR Credit Note Report', ]; }, handleExportClick(){ @@ -132,6 +126,7 @@ 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'), }; let url = `${routesMap[reportType]}?startDate=${this.parameters.startDate}&endDate=${this.parameters.endDate}`; diff --git a/routes/export.php b/routes/export.php index 2a766539..4801bc4e 100644 --- a/routes/export.php +++ b/routes/export.php @@ -12,6 +12,9 @@ Route::group(['prefix' => 'export', 'as' => 'export.', 'namespace' => 'Exports'] Route::group(['prefix' => 'companies', 'as' => 'companies.'], function () { 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::group(['prefix' => 'import', 'as' => 'import.', 'namespace' => 'Imports'], function () { From d5ad357496f361a038a66d24ac5efe8759a28a44 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 31 Jul 2025 23:23:11 +0800 Subject: [PATCH 2/5] E-Invoice - Automapping Issues, AR Credit Note Report (Export) --- .../Services/ExportsARCreditNoteReport.php | 4 +-- .../GenerateCreditNotePdfV2Logic.php | 16 +++++++--- .../Services/UpdatesTransactionStatus.php | 32 +------------------ .../Processors/CreditWalletProcessor.php | 31 ++++++++++++++++-- app/Classes/ValueObjects/Constants/KVPKey.php | 4 ++- 5 files changed, 46 insertions(+), 41 deletions(-) diff --git a/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php b/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php index c2bd406a..240c9d9e 100644 --- a/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php @@ -94,8 +94,8 @@ class ExportsARCreditNoteReport implements FromQuery, WithHeadings, WithHeadingR } } - $documentDate = $transaction->created_at; - $metadata = $transaction->attributesKVP()->where('key', KVPKey::APPROVAL_DATE)->latest('created_at')->first(); + $documentDate = $transaction->created_at; //NEW 2025: default in case there is no approval date + $metadata = $transaction->attributesKVP()->where('key', KVPKey::CREDIT_NOTE_APPROVAL_DATE)->latest('created_at')->first(); if($metadata){ $documentDate = Carbon::parse($metadata->value); } diff --git a/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php b/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php index 824d5528..71cf667c 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php @@ -10,6 +10,7 @@ use App\Classes\Modules\Transactions\Services\FetchesTransaction; use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\General\AWSS3Helper; use App\Classes\ValueObjects\Constants\DocumentType; +use App\Classes\ValueObjects\Constants\KVPKey; use App\Models\KeyValuePair; use App\Models\Transaction; use Carbon\Carbon; @@ -49,9 +50,9 @@ class GenerateCreditNotePdfV2Logic if($transaction->type === TransactionType::REFUND){ //Retrieve TransactionType::CREDIT_NOTE $booking = $transaction->owner->booking; - $kvp = $transaction->attributesKVP()->latest()->first(); + $kvp = $transaction->attributesKVP()->where('key', KVPKey::TRANSACTION_MODEL_CLASS)->latest()->first(); if($kvp){ - if($kvp->key === 'App\Models\Transaction'){ + if($kvp->key === KVPKey::TRANSACTION_MODEL_CLASS){ $transaction = $this->fetchesTransaction->execute(['id' => $kvp->value ]); } } @@ -62,7 +63,7 @@ class GenerateCreditNotePdfV2Logic $pdfTemplateName = 'pages.pdfs.credit_note'; //default //For New Cases with e-invoice: Retrieve the refund transaction for this credit note - $kvp = KeyValuePair::where('key', 'App\Models\Transaction')->where('value', $transaction->id)->first(); + $kvp = KeyValuePair::where('key', KVPKey::TRANSACTION_MODEL_CLASS)->where('value', $transaction->id)->first(); if($kvp){ $kvpOwner = $kvp->owner; if($kvpOwner && $kvpOwner instanceof Transaction && $kvpOwner->type === TransactionType::REFUND){ @@ -71,7 +72,12 @@ class GenerateCreditNotePdfV2Logic } } - $date = $transaction->created_at; + $date = $transaction->created_at; //NEW 2025: default in case there is no approval date + $metadata = $transaction->attributesKVP()->where('key', KVPKey::CREDIT_NOTE_APPROVAL_DATE)->latest('created_at')->first(); + if($metadata){ + $date = Carbon::parse($metadata->value); + } + $supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]); $brn = $supplier->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first(); @@ -88,7 +94,7 @@ class GenerateCreditNotePdfV2Logic { if($supplier->e_invoice === 1){ Log::info('Based on booking created date, E-Credit Note started and company wants e-invoice ' . json_encode($booking)); - $date = $booking->updated_at->copy()->endOfMonth(); + $date = $date->copy()->endOfMonth(); $pdfTemplateName = 'pages.pdfs.e_credit_note'; } else{ diff --git a/app/Classes/Modules/Transactions/Services/UpdatesTransactionStatus.php b/app/Classes/Modules/Transactions/Services/UpdatesTransactionStatus.php index 43b77aaa..d92e3e9a 100644 --- a/app/Classes/Modules/Transactions/Services/UpdatesTransactionStatus.php +++ b/app/Classes/Modules/Transactions/Services/UpdatesTransactionStatus.php @@ -3,14 +3,10 @@ namespace App\Classes\Modules\Transactions\Services; use App\Classes\General\Eloquent\AbstractUpdateRecord; -use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject; -use App\Classes\Modules\Accounts\Services\CreatesKeyValuePair; -use App\Classes\Modules\Accounts\Services\UpdatesKeyValuePair; use App\Classes\Modules\PerfexCRM\Processors\TransactionToPerfexCRMProcessorV2; use App\Models\Transaction; use App\Classes\Modules\Vouchers\Processors\Voucherify\TransactionToVoucherifyProcessor; use App\Classes\ValueObjects\Constants\ApprovalStatus; -use App\Classes\ValueObjects\Constants\KVPKey; use App\Classes\ValueObjects\Constants\TransactionType; class UpdatesTransactionStatus extends AbstractUpdateRecord @@ -21,25 +17,15 @@ class UpdatesTransactionStatus extends AbstractUpdateRecord /** @var TransactionToVoucherifyProcessor */ private $transactionToVoucherifyProcessor; - /** @var CreatesKeyValuePair */ - private $createsKeyValuePair; - - /** @var UpdatesKeyValuePair */ - private $updatesKeyValuePair; - /** * UpdatesTransactionStatus constructor. * @param TransactionToPerfexCRMProcessorV2 $transactionToPerfexCRMProcessor * @param TransactionToVoucherifyProcessor $transactionToVoucherifyProcessor - * @param CreatesKeyValuePair $createsKeyValuePair - * @param UpdatesKeyValuePair $updatesKeyValuePair */ - public function __construct(TransactionToPerfexCRMProcessorV2 $transactionToPerfexCRMProcessor, TransactionToVoucherifyProcessor $transactionToVoucherifyProcessor, CreatesKeyValuePair $createsKeyValuePair, UpdatesKeyValuePair $updatesKeyValuePair) + public function __construct(TransactionToPerfexCRMProcessorV2 $transactionToPerfexCRMProcessor, TransactionToVoucherifyProcessor $transactionToVoucherifyProcessor) { $this->transactionToPerfexCRMProcessor = $transactionToPerfexCRMProcessor; $this->transactionToVoucherifyProcessor = $transactionToVoucherifyProcessor; - $this->createsKeyValuePair = $createsKeyValuePair; - $this->updatesKeyValuePair = $updatesKeyValuePair; } @@ -62,22 +48,6 @@ class UpdatesTransactionStatus extends AbstractUpdateRecord $this->transactionToVoucherifyProcessor->execute($transaction, "PAID"); } - if($status == ApprovalStatus::APPROVED && ($transaction->type == TransactionType::REFUND)){ - $this->updateOrCreateKeyValuePair($transaction, KVPKey::APPROVAL_DATE, now()); - } - return $result; } - - private function updateOrCreateKeyValuePair($transaction, $key, $value) - { - $keyValuePairObject = new KeyValuePairObject($key, $value); - $metadata = $transaction->attributesKVP()->where('key', $key)->first(); - - if ($metadata) { - $this->updatesKeyValuePair->execute($metadata, $keyValuePairObject); - } else { - $this->createsKeyValuePair->execute($transaction, $keyValuePairObject); - } - } } diff --git a/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php b/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php index b0fd0e1c..6e9b33fc 100644 --- a/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php +++ b/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php @@ -16,6 +16,8 @@ use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject; use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject; use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; use App\Classes\Modules\Accounts\Services\CreatesKeyValuePair; +use App\Classes\Modules\Accounts\Services\UpdatesKeyValuePair; +use App\Classes\ValueObjects\Constants\KVPKey; use App\Models\Transaction; class CreditWalletProcessor @@ -38,6 +40,10 @@ class CreditWalletProcessor /** @var CreatesKeyValuePair */ private $createsKeyValuePair; + /** @var UpdatesKeyValuePair */ + private $updatesKeyValuePair; + + /** * CreateWalletLogic constructor. * @param GeneratesWalletCode $generatesWalletCode @@ -46,6 +52,7 @@ class CreditWalletProcessor * @param CreatesTransaction $createsTransaction * @param UpdatesWallet $updatesWallet * @param CreatesKeyValuePair $createsKeyValuePair + * @param UpdatesKeyValuePair $updatesKeyValuePair */ public function __construct( GeneratesWalletCode $generatesWalletCode, @@ -53,7 +60,8 @@ class CreditWalletProcessor GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, UpdatesWallet $updatesWallet, - CreatesKeyValuePair $createsKeyValuePair + CreatesKeyValuePair $createsKeyValuePair, + UpdatesKeyValuePair $updatesKeyValuePair ) { $this->generatesWalletCode = $generatesWalletCode; @@ -62,6 +70,7 @@ class CreditWalletProcessor $this->createsTransaction = $createsTransaction; $this->updatesWallet = $updatesWallet; $this->createsKeyValuePair = $createsKeyValuePair; + $this->updatesKeyValuePair = $updatesKeyValuePair; } @@ -86,9 +95,15 @@ class CreditWalletProcessor $billNumber = $this->generatesTransactionBillNumber->execute($transactionType === 2 ? 'DEBIT-NOTE-' : 'CREDIT-NOTE-'); - $transaction_object = new TransactionObject($billNumber, $transactionType === 2 ? TransactionType::DEBIT_NOTE : TransactionType::CREDIT_NOTE, 1, $wallet->owner->id, 1, PaymentMethodType::CASH, $amount, $amount, 1, 1, 1, 0, 0, null, ApprovalStatus::APPROVED, [], $reference); + $status = ApprovalStatus::APPROVED; + + $transaction_object = new TransactionObject($billNumber, $transactionType === 2 ? TransactionType::DEBIT_NOTE : TransactionType::CREDIT_NOTE, 1, $wallet->owner->id, 1, PaymentMethodType::CASH, $amount, $amount, 1, 1, 1, 0, 0, null, $status, [], $reference); $transaction = $this->createsTransaction->execute($wallet, $transaction_object); + if($status === ApprovalStatus::APPROVED){ + $this->updateOrCreateKeyValuePair($transaction, KVPKey::CREDIT_NOTE_APPROVAL_DATE, now()); + } + $updateWalletAmount = $transactionType === 2 ? ($wallet->amount - $transaction->amount) : ($wallet->amount + $transaction->amount); $walletObject = new WalletObject($wallet->owner->id, $wallet->currency_id, $wallet->code, $updateWalletAmount); @@ -107,4 +122,16 @@ class CreditWalletProcessor } return $wallet; } + + private function updateOrCreateKeyValuePair($transaction, $key, $value) + { + $keyValuePairObject = new KeyValuePairObject($key, $value); + $metadata = $transaction->attributesKVP()->where('key', $key)->first(); + + if ($metadata) { + $this->updatesKeyValuePair->execute($metadata, $keyValuePairObject); + } else { + $this->createsKeyValuePair->execute($transaction, $keyValuePairObject); + } + } } diff --git a/app/Classes/ValueObjects/Constants/KVPKey.php b/app/Classes/ValueObjects/Constants/KVPKey.php index d3526ba9..a15f7d91 100644 --- a/app/Classes/ValueObjects/Constants/KVPKey.php +++ b/app/Classes/ValueObjects/Constants/KVPKey.php @@ -10,6 +10,8 @@ class KVPKey public const AUTOCOUNT_EINVOICE_VALIDATION_LINK = 'AUTOCOUNT_EINVOICE_VALIDATION_LINK'; - public const APPROVAL_DATE = 'APPROVAL_DATE'; + public const CREDIT_NOTE_APPROVAL_DATE = 'CREDIT_NOTE_APPROVAL_DATE'; + + public const TRANSACTION_MODEL_CLASS = 'App\Models\Transaction'; } From b0fb5e4ac91b1d7a6e3754c4ce7839b01aa49d45 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Thu, 31 Jul 2025 23:56:37 +0800 Subject: [PATCH 3/5] E-Invoice - Automapping Issues, AR Credit Note Report (Export) --- .../Exports/Services/ExportsARCreditNoteReport.php | 9 ++++++--- 1 file changed, 6 insertions(+), 3 deletions(-) diff --git a/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php b/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php index 240c9d9e..2b7d41b9 100644 --- a/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php @@ -74,6 +74,7 @@ class ExportsARCreditNoteReport implements FromQuery, WithHeadings, WithHeadingR $booking = null; $autoCountSalesInvoiceId = null; $formattedDocumentDate = null; + $refundRemark = null; $company = $transaction->owner->owner; $kvps = KeyValuePair::where('value', $transaction->id) @@ -83,7 +84,9 @@ class ExportsARCreditNoteReport implements FromQuery, WithHeadings, WithHeadingR foreach ($kvps as $kvp) { if ($kvp && $kvp->owner && $kvp->owner->owner && $kvp->owner->owner->type === 1) { - $booking = $kvp->owner->owner->booking; + $refundTransaction = $kvp->owner; + $refundRemark = $refundTransaction->remarks && $refundTransaction->remarks->first() ? $refundTransaction->remarks->first()->content : null; + $booking = $refundTransaction->owner->booking; if($booking){ $metadata = $booking->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO)->first(); if($metadata){ @@ -109,8 +112,8 @@ class ExportsARCreditNoteReport implements FromQuery, WithHeadings, WithHeadingR $formattedDocumentDate, //DocDate $company->debtor, //DebtorCode $booking ? $booking->marking : '', //Ref - $transaction->payment_reference, //Description - $transaction->payment_reference, //Reason + $refundRemark ?? '', //Description + $refundRemark ?? '', //Reason 'C', //DeptNo '1', //Qty number_format($transaction->amount, 2), //UnitPrice From ad4ef09efc477b3c0ffb81588bd7edb28234e46b Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Fri, 1 Aug 2025 10:36:36 +0800 Subject: [PATCH 4/5] E-Invoice - Automapping Issues, AR Credit Note Report (Export) --- .../Modules/Exports/Services/ExportsARCreditNoteReport.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php b/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php index 2b7d41b9..9592cd93 100644 --- a/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php +++ b/app/Classes/Modules/Exports/Services/ExportsARCreditNoteReport.php @@ -105,7 +105,7 @@ class ExportsARCreditNoteReport implements FromQuery, WithHeadings, WithHeadingR if($company->e_invoice === 1){ $documentDate = $documentDate->copy()->endOfMonth(); } - $formattedDocumentDate = Carbon::parse($documentDate)->format('d/m/Y'); + $formattedDocumentDate = Carbon::parse($documentDate)->format('m/d/Y'); return [ '<>', //DocNo From a6328fabd62bf786059ec38adde48a253bed6f30 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Fri, 1 Aug 2025 11:24:58 +0800 Subject: [PATCH 5/5] E-Invoice - Automapping Issues, AR Credit Note Report (Export) --- .../GenerateCreditNotePdfV2Logic.php | 25 +++++++++++++++++-- 1 file changed, 23 insertions(+), 2 deletions(-) diff --git a/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php b/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php index 71cf667c..7168a175 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php @@ -88,7 +88,28 @@ class GenerateCreditNotePdfV2Logic if ($bookingCreatedDate->isAfter($eInvoiceStartDate)) { $eInvoiceStarted = true; } - // $eInvoiceStarted = false; //cief todo: 90 - for testing + + if($eInvoiceStarted) { + $eInvoiceStarted = false; //reset to re-evaluate second time + $autoCountInvoiceId = ''; + $autoCountEInvoiceValidationLink = ''; + + $metadata = $booking->attributesKVP()->where('key', KVPKey::AUTOCOUNT_DOCNO)->first(); + if($metadata){ + $autoCountInvoiceId = $metadata->value; + } + $metadata = $booking->attributesKVP()->where('key', KVPKey::AUTOCOUNT_EINVOICE_VALIDATION_LINK)->first(); + if($metadata){ + $autoCountEInvoiceValidationLink = $metadata->value; + } + + Log::info('autoCountInvoiceId: ' . $autoCountInvoiceId); + Log::info('autoCountEInvoiceValidationLink: ' . $autoCountEInvoiceValidationLink); + + if($autoCountInvoiceId && $autoCountEInvoiceValidationLink){ + $eInvoiceStarted = true; + } + } if($eInvoiceStarted) { @@ -103,7 +124,7 @@ class GenerateCreditNotePdfV2Logic } } else{ - Log::info('Based on booking created date, E-Credit Note not yet started'); + Log::info('Based on booking created date, E-Credit Note not yet started. / Not Yet Ready.'); } $pdf = LaravelMpdf::loadView($pdfTemplateName, ['transaction' => $transaction, 'booking' => $booking, 'supplier' => $supplier, 'date' => $date, 'brn' => $brn,]);