From 893631064b60ad138b13a2fa8e19a003bc4ebf79 Mon Sep 17 00:00:00 2001 From: Dillon Ngo Date: Fri, 6 Jun 2025 03:17:52 +0800 Subject: [PATCH] E-Invoice - Partial completion of => Doc Delivery - E-INVOICE, E-CN, E-RN --- .../CreateBookingRefundLogic.php | 11 +- .../RegenerateInvoiceBookingLogic.php | 17 +- .../GenerateCreditNotePdfLogic.php | 4 + .../GenerateCreditNotePdfV2Logic.php | 115 ++++++++++++ .../UpdateRefundTransactionStatusLogic.php | 21 ++- .../CreateInvoiceDocumentProcessor.php | 16 +- .../CreateInvoiceTransactionProcessor.php | 39 +++- ...voiceTransactionWithInvoiceNoProcessor.php | 6 +- .../Processors/CreditWalletProcessor.php | 28 ++- .../ValueObjects/Constants/DocumentType.php | 1 + .../Constants/RemarkRefundReason.php | 16 ++ .../RegenerateBookingEInvoiceController.php | 20 ++ .../Remarks/ListRefundRemarksController.php | 29 +++ .../GenerateCreditNotePdfController.php | 6 +- app/Http/Resources/BookingResource.php | 8 +- config/qr.php | 5 + .../elements/PaymentHistoryComponent.vue | 107 ++++++++--- .../elements/RequestCreditNoteComponent.vue | 175 ++++++++++++++++++ .../forms/RegenerateEInvoiceComponent.vue | 41 ++++ .../BookingDetailsSectionComponent.vue | 36 +++- .../CustomerWalletTransactionComponent.vue | 4 +- .../views/pages/pdfs/credit_note_v2.blade.php | 118 ++++++++++++ .../views/pages/pdfs/e_credit_note.blade.php | 147 +++++++++++++++ .../views/pages/pdfs/e_invoice.blade.php | 115 ++++++++++++ resources/views/pages/pdfs/invoice.blade.php | 2 +- resources/views/vendor/head.blade.php | 5 +- routes/booking.php | 5 +- routes/remark.php | 3 + routes/web.php | 8 +- 29 files changed, 1036 insertions(+), 72 deletions(-) create mode 100644 app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php create mode 100644 app/Classes/ValueObjects/Constants/RemarkRefundReason.php create mode 100644 app/Http/Controllers/Bookings/RegenerateBookingEInvoiceController.php create mode 100644 app/Http/Controllers/Remarks/ListRefundRemarksController.php create mode 100644 config/qr.php create mode 100644 resources/assets/vue/components/bookings/elements/RequestCreditNoteComponent.vue create mode 100644 resources/assets/vue/components/bookings/forms/RegenerateEInvoiceComponent.vue create mode 100644 resources/views/pages/pdfs/credit_note_v2.blade.php create mode 100644 resources/views/pages/pdfs/e_credit_note.blade.php create mode 100644 resources/views/pages/pdfs/e_invoice.blade.php diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php index 6148291c..b57a398d 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingRefundLogic.php @@ -93,9 +93,10 @@ class CreateBookingRefundLogic extends AbstractControllerLogic $invoice = $booking->transactions()->where('type', TransactionType::INVOICE)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->first(); - if(auth()->user()->type === 3) { - throw new MalformedRequestException('You do not have the permission to refund the order.'); - } + //cief todo: 90 - move this into rules + // if(auth()->user()->type === 3) { + // throw new MalformedRequestException('You do not have the permission to refund the order.'); + // } $billNumber = $this->generatesTransactionBillNumber->execute('RFD-'); @@ -113,7 +114,7 @@ class CreateBookingRefundLogic extends AbstractControllerLogic $refundAmount = $transaction->original_amount / $transaction->currency_rate; $service_charges_to_refund = $transaction->service_charge; } else { - // partial refund + // partial refund $refundAmount = bcdiv($request->input('amount'), $transaction->currency_rate, 7); $bookingAmountBeforeCurrentRefund = $booking->fix_amount - $refundInPending; @@ -157,7 +158,7 @@ class CreateBookingRefundLogic extends AbstractControllerLogic $refund_transaction = $this->createsTransaction->execute($transaction, $object); - $bookingInWhiteForm = $transaction->transactions()->bills()->first(); + $bookingInWhiteForm = $transaction->transactions()->bills()->first(); // if no white form created yet can approve right away // create supplier refund if ($bookingInWhiteForm) { diff --git a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php index 5d067fd5..450c9f7d 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php @@ -9,7 +9,6 @@ use App\Classes\Modules\Bookings\Services\UpdatesBookingStatus; use App\Classes\Modules\Transactions\Services\DeletesTransaction; use App\Classes\Modules\Documents\Services\DeletesDocument; use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionProcessor; -use App\Classes\Modules\Transactions\Processors\CreateInvoiceTransactionWithInvoiceNoProcessor; use Illuminate\Support\Str; use App\Classes\ValueObjects\Constants\DocumentType; use App\Http\Resources\BookingResource; @@ -52,9 +51,6 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic /** @var CreateInvoiceTransactionProcessor */ private $createInvoiceTransactionProcessor; - /** @var CreateInvoiceTransactionWithInvoiceNoProcessor */ - private $createInvoiceTransactionWithInvoiceNoProcessor; - /** * FetchBookingLogic constructor. * @param CanFetchBooking $canFetchBooking @@ -63,7 +59,6 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic * @param UpdatesBookingStatus $updatesBookingStatus * @param DeletesDocument $deletesDocument * @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor - * @param CreateInvoiceTransactionWithInvoiceNoProcessor $createInvoiceTransactionWithInvoiceNoProcessor */ public function __construct( CanFetchBooking $canFetchBooking, @@ -71,8 +66,7 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic DeletesTransaction $deletesTransaction, UpdatesBookingStatus $updatesBookingStatus, DeletesDocument $deletesDocument, - CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor, - CreateInvoiceTransactionWithInvoiceNoProcessor $createInvoiceTransactionWithInvoiceNoProcessor + CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor ) { $this->canFetchBooking = $canFetchBooking; $this->fetchesBooking = $fetchesBooking; @@ -80,7 +74,6 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic $this->updatesBookingStatus = $updatesBookingStatus; $this->deletesDocument = $deletesDocument; $this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor; - $this->createInvoiceTransactionWithInvoiceNoProcessor = $createInvoiceTransactionWithInvoiceNoProcessor; } @@ -119,8 +112,10 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic // update currentInvoice bill_no to '-deleted-' $currentInvoice = $booking->transactions()->where('type', TransactionType::INVOICE)->first(); - $currentInvoice->bill_no = $currentInvoice->bill_no ."-deleted-" . (string)(Carbon::now()->timestamp); - $currentInvoice->save(); + if($currentInvoice){ + $currentInvoice->bill_no = $currentInvoice->bill_no ."-deleted-" . (string)(Carbon::now()->timestamp); + $currentInvoice->save(); + } $transactionWithSameBillNo = Transaction::where('bill_no', $firstBillNo)->withTrashed()->get(); if ($transactionWithSameBillNo) { @@ -140,7 +135,7 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic $this->deletesDocument->execute($row); } - $this->createInvoiceTransactionWithInvoiceNoProcessor->execute($booking, $firstBillNo); + $this->createInvoiceTransactionProcessor->execute($booking, $firstBillNo); return $this->resourceResponse(new BookingResource($booking)); } diff --git a/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfLogic.php index 4a0af327..4241ac91 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfLogic.php @@ -13,6 +13,10 @@ use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\General\AWSS3Helper; use Illuminate\Support\Facades\Storage; +/** + * @deprecated This class is deprecated and should not be used. + * Use `GenerateCreditNotePdfV2Logic` instead + */ class GenerateCreditNotePdfLogic { diff --git a/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php b/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php new file mode 100644 index 00000000..824d5528 --- /dev/null +++ b/app/Classes/Modules/Transactions/ControllersLogic/GenerateCreditNotePdfV2Logic.php @@ -0,0 +1,115 @@ +fetchesTransaction = $fetchesTransaction; + $this->fetchesCompany = $fetchesCompany; + } + + /** + * @param Request $request + * @return string|\Symfony\Component\HttpFoundation\Response + * @throws \App\Classes\Exceptions\MalformedRequestException + */ + public function execute(Request $request) + { + $pdfTemplateName = 'pages.pdfs.credit_note_v2'; //default since e-invoice implementation + $transaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]); + + if($transaction->type === TransactionType::REFUND){ + //Retrieve TransactionType::CREDIT_NOTE + $booking = $transaction->owner->booking; + $kvp = $transaction->attributesKVP()->latest()->first(); + if($kvp){ + if($kvp->key === 'App\Models\Transaction'){ + $transaction = $this->fetchesTransaction->execute(['id' => $kvp->value ]); + } + } + } + else{ + //For Old Cases + $booking = $transaction->booking; + $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(); + if($kvp){ + $kvpOwner = $kvp->owner; + if($kvpOwner && $kvpOwner instanceof Transaction && $kvpOwner->type === TransactionType::REFUND){ + $booking = $kvpOwner->owner->booking; + } + } + } + + $date = $transaction->created_at; + $supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]); + $brn = $supplier->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first(); + + $eInvoiceStarted = false; + $eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00')); + $bookingCreatedDate = Carbon::parse($booking->created_at); + + if ($bookingCreatedDate->isAfter($eInvoiceStartDate)) { + $eInvoiceStarted = true; + } + // $eInvoiceStarted = false; //cief todo: 90 - for testing + + if($eInvoiceStarted) + { + 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(); + $pdfTemplateName = 'pages.pdfs.e_credit_note'; + } + else{ + Log::info('Based on booking created date, E-Credit Note started and company do not wants e-invoice'); + $pdfTemplateName = 'pages.pdfs.credit_note_v2'; + } + } + else{ + Log::info('Based on booking created date, E-Credit Note not yet started'); + } + + $pdf = LaravelMpdf::loadView($pdfTemplateName, ['transaction' => $transaction, 'booking' => $booking, 'supplier' => $supplier, 'date' => $date, 'brn' => $brn,]); + + $exportFileName = 'CreditNote.pdf'; + $filesystemDriver = Storage::getDefaultDriver(); + if($filesystemDriver === 's3'){ + $pdfContent = $pdf->output(); + return response([ 'src' => AWSS3Helper::S3PDF($exportFileName, $pdfContent) ]); + } + else{ + return $pdf->stream($exportFileName); + } + } +} diff --git a/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php index d2b921d1..4b1620da 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/UpdateRefundTransactionStatusLogic.php @@ -16,6 +16,7 @@ use Illuminate\Http\Request; use App\Classes\Modules\Wallets\Processors\CreditWalletProcessor; use App\Classes\Modules\Bookings\Services\CalculatesBookingPayableAmount; use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount; +use App\Classes\ValueObjects\Constants\RemarkRefundReason; use App\Classes\ValueObjects\Constants\TransactionType; use Illuminate\Support\Facades\Auth; @@ -86,9 +87,10 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic */ public function logic(Request $request) : JsonResponse { - if(auth()->user()->type === 3) { - throw new MalformedRequestException('You do not have the permission to refund the order.'); - } + //cief todo: 90 - move this into rules + // if(auth()->user()->type === 3) { + // throw new MalformedRequestException('You do not have the permission to refund the order.'); + // } $refundTransaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]); @@ -100,14 +102,21 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic $booking = $paymentTransaction->owner; - $reference = $paymentTransaction->amount - $refundTransaction->amount < 0.01 ? 'Fully Refund for Ref. ' . $booking->marking : 'Partially Refund for Ref. ' . $booking->marking; + // $reference = $paymentTransaction->amount - $refundTransaction->amount < 0.01 ? 'Fully Refund for Ref. ' . $booking->marking : 'Partially Refund for Ref. ' . $booking->marking; + if ($paymentTransaction->amount - $refundTransaction->amount < 0.01) { + $reference = 'Return Inward for Ref. ' . $booking->marking; + } else { + $remarkGroup = RemarkRefundReason::REFUND_REASONS[$request->input('refundRemark')] ?? ''; + $reference = $remarkGroup ? $remarkGroup . ' for Ref. ' . $booking->marking : $request->input('refundRemark'). ' for Ref. ' . $booking->marking; + } $refundAmount = $this->calculatesBookingRefundAmount->calculateRefundAmount($paymentTransaction, $booking->fix_currency_id); $paidAmount = $paymentTransaction->original_amount - $refundAmount; if ($refundTransaction->status == ApprovalStatus::APPROVED) { - $this->creditWalletProcessor->execute($booking->company, $refundTransaction->type, $refundTransaction->amount, $reference); + $this->creditWalletProcessor->execute($booking->company, $refundTransaction->type, $refundTransaction->amount, $reference, $refundTransaction); + $po_transaction = $booking->transactions()->where('type', TransactionType::PURCHASE_ORDER)->first(); if ($po_transaction) { @@ -129,4 +138,4 @@ class UpdateRefundTransactionStatusLogic extends AbstractControllerLogic return $this->response([]); } -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php index 550e6148..8bb2c797 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceDocumentProcessor.php @@ -48,13 +48,23 @@ class CreateInvoiceDocumentProcessor // calculate current Paid Amount $booking = $transaction->owner_type == Booking::class ? $transaction->owner : null; $currentPaidAmount = null; - $lastPaymentDate = $supplier->segments->whereIn('id', [23])->first() ? \Carbon\Carbon::now() : $purchaseOrder->booking->created_at; + $brn = $supplier->documents->where('document_type', DocumentType::SSM_REGISTRATION)->first(); + $documentDate = $supplier->segments->whereIn('id', [23])->first() ? \Carbon\Carbon::now() : $purchaseOrder->booking->created_at; $eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00')); if ($booking) { $bookingCreatedDate = Carbon::parse($booking->created_at); if ($bookingCreatedDate->isAfter($eInvoiceStartDate)) { - $lastPaymentDate = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->latest()->first()->created_at; + $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($document_type === DocumentType::EINVOICE){ + $lastDayOfMonth = $documentDate->copy()->endOfMonth(); + $documentDate = $lastDayOfMonth; } $payment = $booking->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED])->first(); $refundAmount = $payment->transactions()->refunds()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED])->sum('amount'); @@ -64,7 +74,7 @@ class CreateInvoiceDocumentProcessor $lowercaseDocumentType = strtolower($document_type); - $order_pdf = LaravelMpdf::loadView('pages.pdfs.' . $lowercaseDocumentType, ['transaction' => $transaction, 'po_order_transaction' => $purchaseOrder, 'supplier' => $supplier, 'voucher_redemption' => $voucherRedemption, 'current_paid_amount' => $currentPaidAmount, 'last_payment_date' => $lastPaymentDate ]); + $order_pdf = LaravelMpdf::loadView('pages.pdfs.' . $lowercaseDocumentType, ['transaction' => $transaction, 'po_order_transaction' => $purchaseOrder, 'supplier' => $supplier, 'voucher_redemption' => $voucherRedemption, 'current_paid_amount' => $currentPaidAmount, 'document_date' => $documentDate, 'brn' => $brn, 'autocountId' => null]); //cief todo: 90 - autocount id to be updated if($purchaseOrder && $purchaseOrder->booking->service_id === 4) { $purchaseOrderDocuments = $purchaseOrder->booking->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->get(); diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php index 7f105dc8..ad1077c2 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessor.php @@ -20,6 +20,7 @@ use App\Classes\ValueObjects\Constants\TransactionType; use App\Classes\ValueObjects\Constants\DocumentType; use App\Models\Booking; use App\Models\SegmentConstant; +use Carbon\Carbon; class CreateInvoiceTransactionProcessor { @@ -83,10 +84,11 @@ class CreateInvoiceTransactionProcessor /** * @param Booking $booking + * @param String $invoiceNo * @return void * @throws MalformedRequestException */ - public function execute(Booking $booking) + public function execute(Booking $booking, String $invoiceNo= "") { if ($booking->status === ApprovalStatus::COMPLETED) { @@ -121,10 +123,26 @@ class CreateInvoiceTransactionProcessor // ->first(); $transaction = $booking->transactions() - ->where('type', TransactionType::PAYMENT) - ->latest()->get()[0]; + ->where('type', TransactionType::PAYMENT) + ->latest()->get()[0]; + $supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]); - $billNumber = $this->generatesTransactionBillNumber->execute('INV-'); + // Check if eInvoice implementation has started and company opted in for eInvoice + $eInvoice = false; + $eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00')); + $bookingCreatedDate = Carbon::parse($booking->created_at); + if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $supplier->e_invoice === 1) { + $eInvoice = true; + } + // $eInvoice = true; //cief todo: 90 - for testing + + if($invoiceNo){ + $billNumber = $invoiceNo; + } + else{ + $billNUmberPrefix = $eInvoice ? 'EINV-' : 'INV-'; + $billNumber = $this->generatesTransactionBillNumber->execute($billNUmberPrefix); + } $booking_currency_average_rate = $this->calculatesBookingCurrencyAverageRate->execute($booking, TransactionType::PAYMENT); @@ -138,6 +156,7 @@ class CreateInvoiceTransactionProcessor ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]) ->sum('tax'); + $transaction_object = new TransactionObject( $billNumber, TransactionType::INVOICE, @@ -159,16 +178,22 @@ class CreateInvoiceTransactionProcessor $voucherRedemption = $transaction->voucherRedemption; - $supplier = $this->fetchesCompany->execute(['id' => $transaction->receiver]); - // purchase order $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::PURCHASE_ORDER, $voucherRedemption); // deliver order $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::DELIVER_ORDER, $voucherRedemption); + // e-invoice + if ($eInvoice) + { + $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::EINVOICE, $voucherRedemption); + } // invoice - $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::INVOICE, $voucherRedemption); + else + { + $this->invoiceDocumentProcessor->execute($invoice_transaction, $purchaseOrder, $supplier, DocumentType::INVOICE, $voucherRedemption); + } $billNumber = $this->generatesTransactionBillNumber->execute('SPDO-'); diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionWithInvoiceNoProcessor.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionWithInvoiceNoProcessor.php index 612033f8..3bb33f28 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionWithInvoiceNoProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionWithInvoiceNoProcessor.php @@ -21,6 +21,10 @@ use App\Classes\ValueObjects\Constants\DocumentType; use App\Models\Booking; use App\Models\SegmentConstant; +/** + * @deprecated This class is deprecated and should not be used. + * Use `CreateInvoiceTransactionProcessor` instead or write a new one based on CreateInvoiceTransactionProcessor + */ class CreateInvoiceTransactionWithInvoiceNoProcessor { @@ -53,7 +57,7 @@ class CreateInvoiceTransactionWithInvoiceNoProcessor /** - * CreateInvoiceTransactionProcessor constructor. + * CreateInvoiceTransactionWithInvoiceNoProcessor constructor. * @param ListsTransactions $listsTransactions * @param CreatesTransaction $createsTransaction * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber diff --git a/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php b/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php index 65f3b9b6..b0fd0e1c 100644 --- a/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php +++ b/app/Classes/Modules/Wallets/Processors/CreditWalletProcessor.php @@ -2,6 +2,7 @@ namespace App\Classes\Modules\Wallets\Processors; +use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject; use App\Models\Wallet; use App\Models\Company; use App\Classes\ValueObjects\Constants\ApprovalStatus; @@ -14,6 +15,8 @@ use App\Classes\Modules\Transactions\Services\CreatesTransaction; 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\Models\Transaction; class CreditWalletProcessor { @@ -32,6 +35,9 @@ class CreditWalletProcessor /** @var UpdatesWallet */ private $updatesWallet; + /** @var CreatesKeyValuePair */ + private $createsKeyValuePair; + /** * CreateWalletLogic constructor. * @param GeneratesWalletCode $generatesWalletCode @@ -39,13 +45,15 @@ class CreditWalletProcessor * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber * @param CreatesTransaction $createsTransaction * @param UpdatesWallet $updatesWallet + * @param CreatesKeyValuePair $createsKeyValuePair */ public function __construct( GeneratesWalletCode $generatesWalletCode, CreatesWallet $createsWallet, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatesTransaction $createsTransaction, - UpdatesWallet $updatesWallet + UpdatesWallet $updatesWallet, + CreatesKeyValuePair $createsKeyValuePair ) { $this->generatesWalletCode = $generatesWalletCode; @@ -53,6 +61,7 @@ class CreditWalletProcessor $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; $this->createsTransaction = $createsTransaction; $this->updatesWallet = $updatesWallet; + $this->createsKeyValuePair = $createsKeyValuePair; } @@ -61,10 +70,11 @@ class CreditWalletProcessor * @param int $transactionType * @param float $amount * @param string $reference + * @param $relatedTransaction * @return \Illuminate\Database\Eloquent\Model * @throws \App\Classes\Exceptions\MalformedRequestException */ - public function execute(Company $company, int $transactionType, float $amount, string $reference) + public function execute(Company $company, int $transactionType, float $amount, string $reference, $relatedTransaction = null) { if (!$company->wallets()->first()) { $object = new WalletObject($company->id, 1, $this->generatesWalletCode->execute()); @@ -75,16 +85,26 @@ class CreditWalletProcessor $wallet = $company->wallets()->first(); $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); $transaction = $this->createsTransaction->execute($wallet, $transaction_object); - + $updateWalletAmount = $transactionType === 2 ? ($wallet->amount - $transaction->amount) : ($wallet->amount + $transaction->amount); $walletObject = new WalletObject($wallet->owner->id, $wallet->currency_id, $wallet->code, $updateWalletAmount); $wallet = $this->updatesWallet->execute($wallet, $walletObject); + if($relatedTransaction && $relatedTransaction instanceof Transaction){ + $kvp = $relatedTransaction->attributesKVP()->where('key', 'App\Models\Transaction')->where('value', $transaction->id)->latest()->first(); + if(!$kvp){ + $keyValuePairObject = new KeyValuePairObject( + "App\Models\Transaction", + $transaction->id + ); + $this->createsKeyValuePair->execute($relatedTransaction, $keyValuePairObject); + } + } return $wallet; } } diff --git a/app/Classes/ValueObjects/Constants/DocumentType.php b/app/Classes/ValueObjects/Constants/DocumentType.php index 4728acbe..b11b6874 100644 --- a/app/Classes/ValueObjects/Constants/DocumentType.php +++ b/app/Classes/ValueObjects/Constants/DocumentType.php @@ -29,4 +29,5 @@ final class DocumentType { public const BILL_GROUP_PAYMENT_PROOF = 'BILL_GROUP_PAYMENT_PROOF'; public const RECEIPT_VOUCHER = 'RECEIPT_VOUCHER'; + public const EINVOICE = 'E_INVOICE'; //cief todo: 90 - why is there no E-CREDITNOTE } diff --git a/app/Classes/ValueObjects/Constants/RemarkRefundReason.php b/app/Classes/ValueObjects/Constants/RemarkRefundReason.php new file mode 100644 index 00000000..d8143b21 --- /dev/null +++ b/app/Classes/ValueObjects/Constants/RemarkRefundReason.php @@ -0,0 +1,16 @@ + 'Return Inward', + 'Goods Damage/ Loss Compensation' => 'Return Inward', + 'Cancel Partial Order' => 'Return Inward', + 'Overpaid due to Supplier amend price' => 'Discount Allowed', + 'Defective Item' => 'Discount Allowed', + 'Cancel Full Order' => 'Return Inward', + 'Others' => '', + ]; +} diff --git a/app/Http/Controllers/Bookings/RegenerateBookingEInvoiceController.php b/app/Http/Controllers/Bookings/RegenerateBookingEInvoiceController.php new file mode 100644 index 00000000..0b07d938 --- /dev/null +++ b/app/Http/Controllers/Bookings/RegenerateBookingEInvoiceController.php @@ -0,0 +1,20 @@ +execute($request); + } +} diff --git a/app/Http/Controllers/Remarks/ListRefundRemarksController.php b/app/Http/Controllers/Remarks/ListRefundRemarksController.php new file mode 100644 index 00000000..7d4e9db9 --- /dev/null +++ b/app/Http/Controllers/Remarks/ListRefundRemarksController.php @@ -0,0 +1,29 @@ + $category) { + // $returnArray[] = [ + // 'name' => $reason + // ]; + // } + // $row['payload']["data"] = $returnArray; + + $allReasons = RemarkRefundReason::REFUND_REASONS; + $row['payload']['data'] = array_keys($allReasons); + return response()->json($row); + } +} diff --git a/app/Http/Controllers/Transactions/GenerateCreditNotePdfController.php b/app/Http/Controllers/Transactions/GenerateCreditNotePdfController.php index 11d27cdd..f58d419f 100644 --- a/app/Http/Controllers/Transactions/GenerateCreditNotePdfController.php +++ b/app/Http/Controllers/Transactions/GenerateCreditNotePdfController.php @@ -5,11 +5,15 @@ namespace App\Http\Controllers\Transactions; use Illuminate\Http\Request; use App\Classes\Modules\Transactions\ControllersLogic\GenerateCreditNotePdfLogic; -use Illuminate\Http\JsonResponse; +use App\Classes\Modules\Transactions\ControllersLogic\GenerateCreditNotePdfV2Logic; class GenerateCreditNotePdfController { public function download(Request $request, GenerateCreditNotePdfLogic $logic) { return $logic->execute($request); } + + public function downloadV2(Request $request, GenerateCreditNotePdfV2Logic $logic) { + return $logic->execute($request); + } } diff --git a/app/Http/Resources/BookingResource.php b/app/Http/Resources/BookingResource.php index 79d7c466..449c6a59 100644 --- a/app/Http/Resources/BookingResource.php +++ b/app/Http/Resources/BookingResource.php @@ -27,9 +27,14 @@ class BookingResource extends JsonResource $eInvoice = false; $eInvoiceStartDate = Carbon::parse(env('E_INVOICE_START_DATE', '2025-07-01 00:00:00')); $bookingCreatedDate = Carbon::parse($this->created_at); - if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $this->company->e_invoice === 1) { + $eInvoiceRequestedDate = Carbon::parse($this->company->e_invoice_requested_at); + //cief todo: 90 - for testing + if ($bookingCreatedDate->isAfter($eInvoiceStartDate) && $this->company->e_invoice === 1) { //&& $bookingCreatedDate->diffInMinutes($eInvoiceRequestedDate) <= 480 cief todo: 90 $eInvoice = true; } + // if ($this->company->e_invoice === 1) { + // $eInvoice = true; + // } return [ 'id' => $this->id, 'company' => new CompanyResource($this->company), @@ -48,6 +53,7 @@ class BookingResource extends JsonResource 'purchase_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::PURCHASE_ORDER)->first()), 'delivery_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::DELIVER_ORDER)->first()), 'invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::INVOICE)->first()), + 'e_invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::EINVOICE)->latest()->first()), 'supplier_delivery_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::SUPPLIER_DELIVER_ORDER)->first()), 'proforma_invoice' => new DocumentResource($this->documents()->where('document_type', DocumentType::PROFORMA_INVOICE)->whereNotIn('status', [ApprovalStatus::REJECTED, ApprovalStatus::EXPIRED])->orderByDesc('id')->first()), 'ecommerce_purchase_order' => new DocumentResource($this->documents()->where('document_type', DocumentType::ECOMMERCE_PURCHASE_ORDER)->first()), diff --git a/config/qr.php b/config/qr.php new file mode 100644 index 00000000..e42be03a --- /dev/null +++ b/config/qr.php @@ -0,0 +1,5 @@ + 'https://api.qrserver.com/v1/create-qr-code/?size=150x150&data=', +]; diff --git a/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue b/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue index 8b776ce5..f7d1f91e 100644 --- a/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue +++ b/resources/assets/vue/components/bookings/elements/PaymentHistoryComponent.vue @@ -6,7 +6,7 @@
-
+
Status
{{ item.status === 7 ? 'Refunded' : (item.status === 1 ? 'Pending Verification' : item.status === 4 ? 'Rejected' : 'Payment Approved')}} @@ -15,13 +15,13 @@ {{ item.status === 1 ? 'Pending Verification' : item.status === 4 ? 'Rejected' : 'Processing Payment'}}
-
+
Payment Amount
{{item.original_currency.short_code}} {{(Math.round((item.original_amount - item.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
-
+
Refunded Amount
{{item.original_currency.short_code}} {{(Math.round((item.refunded_amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}} @@ -45,7 +45,7 @@
-
+
+
+ + + +