From df193fd737f4004090b95ae03c04d0137893ae44 Mon Sep 17 00:00:00 2001
From: Dillon Ngo
Date: Thu, 15 May 2025 23:46:36 +0800
Subject: [PATCH 04/38] E-Invoice - Do not allow customer to edit PO when
customer already has made partial payment
---
.../CreateBookingPaymentLogic.php | 14 ++--
.../DataTransferObjects/ConfirmBookingDTO.php | 2 +-
.../UpdateCompanyEInvoiceInfoLogic.php | 6 +-
.../UpdateCompanyEInvoiceRequestLogic.php | 2 +-
.../DataTransferObjects/EInvoiceInfoDTO.php | 2 +-
.../EInvoiceRequestDTO.php | 2 +-
.../CheckEInvoiceRuleLogic.php | 8 +--
.../CheckPurchaseOrderRuleLogic.php | 8 +--
...le.php => CanPassEInvoicePromptedRule.php} | 6 +-
.../Standards/Rules/CanPassEditingPORule.php | 67 +++++++++++++++++++
...rRule.php => CanPassPurchaseOrderRule.php} | 4 +-
...nProceedTINRule.php => CanPassTINRule.php} | 4 +-
.../CreatePurchaseOrderTransactionLogic.php | 30 +++++++--
.../CreatePurchaseOrderDTO.php | 25 +++++++
.../forms/PurchaseOrderFormComponent.vue | 8 ++-
15 files changed, 152 insertions(+), 36 deletions(-)
rename app/Classes/Modules/{Rules => Bookings}/DataTransferObjects/ConfirmBookingDTO.php (89%)
rename app/Classes/Modules/{Rules => Companies}/DataTransferObjects/EInvoiceInfoDTO.php (95%)
rename app/Classes/Modules/{Rules => Companies}/DataTransferObjects/EInvoiceRequestDTO.php (89%)
rename app/Classes/Modules/Rules/Standards/Rules/{CanProceedEInvoicePromptedRule.php => CanPassEInvoicePromptedRule.php} (85%)
create mode 100644 app/Classes/Modules/Rules/Standards/Rules/CanPassEditingPORule.php
rename app/Classes/Modules/Rules/Standards/Rules/{CanProceedPurchaseOrderRule.php => CanPassPurchaseOrderRule.php} (96%)
rename app/Classes/Modules/Rules/Standards/Rules/{CanProceedTINRule.php => CanPassTINRule.php} (93%)
create mode 100644 app/Classes/Modules/Transactions/DataTransferObjects/CreatePurchaseOrderDTO.php
diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php
index 6b75dd49..ce8bec20 100644
--- a/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php
+++ b/app/Classes/Modules/Bookings/ControllersLogic/CreateBookingPaymentLogic.php
@@ -16,10 +16,10 @@ use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Wallets\Services\UpdatesWalletBalance;
use App\Classes\Modules\Currencies\DataTransferObjects\CurrencyConversionObject;
use App\Classes\Modules\Bookings\Services\CalculatesBookingRefundAmount;
-use App\Classes\Modules\Rules\DataTransferObjects\ConfirmBookingDTO;
-use App\Classes\Modules\Rules\Standards\Rules\CanProceedEInvoicePromptedRule;
-use App\Classes\Modules\Rules\Standards\Rules\CanProceedPurchaseOrderRule;
-use App\Classes\Modules\Rules\Standards\Rules\CanProceedTINRule;
+use App\Classes\Modules\Bookings\DataTransferObjects\ConfirmBookingDTO;
+use App\Classes\Modules\Rules\Standards\Rules\CanPassEInvoicePromptedRule;
+use App\Classes\Modules\Rules\Standards\Rules\CanPassPurchaseOrderRule;
+use App\Classes\Modules\Rules\Standards\Rules\CanPassTINRule;
use App\Classes\Modules\Transactions\Processors\CreateCashBackTransactionProcessor;
use App\Classes\Modules\Vouchers\Processors\Voucherify\BookingToVoucherifyProcessor;
use App\Classes\Modules\Wallets\Services\RecalculatesWalletBalance;
@@ -131,9 +131,9 @@ class CreateBookingPaymentLogic extends AbstractControllerLogic
{
$dto = new ConfirmBookingDTO($request->all());
$result = $this->ruleEvaluator->evaluate([
- App()->make(CanProceedEInvoicePromptedRule::class),
- App()->make(CanProceedTINRule::class),
- App()->make(CanProceedPurchaseOrderRule::class),
+ App()->make(CanPassEInvoicePromptedRule::class),
+ App()->make(CanPassTINRule::class),
+ App()->make(CanPassPurchaseOrderRule::class),
], $dto);
if ($result->failed()) {
diff --git a/app/Classes/Modules/Rules/DataTransferObjects/ConfirmBookingDTO.php b/app/Classes/Modules/Bookings/DataTransferObjects/ConfirmBookingDTO.php
similarity index 89%
rename from app/Classes/Modules/Rules/DataTransferObjects/ConfirmBookingDTO.php
rename to app/Classes/Modules/Bookings/DataTransferObjects/ConfirmBookingDTO.php
index 2c154833..49f7e727 100644
--- a/app/Classes/Modules/Rules/DataTransferObjects/ConfirmBookingDTO.php
+++ b/app/Classes/Modules/Bookings/DataTransferObjects/ConfirmBookingDTO.php
@@ -1,6 +1,6 @@
all());
$result = $this->ruleEvaluator->evaluate([
- App()->make(CanProceedEInvoicePromptedRule::class),
+ App()->make(CanPassEInvoicePromptedRule::class),
], $dto);
if ($result->failed()) {
diff --git a/app/Classes/Modules/Companies/ControllersLogic/UpdateCompanyEInvoiceRequestLogic.php b/app/Classes/Modules/Companies/ControllersLogic/UpdateCompanyEInvoiceRequestLogic.php
index 86051447..09700f5d 100644
--- a/app/Classes/Modules/Companies/ControllersLogic/UpdateCompanyEInvoiceRequestLogic.php
+++ b/app/Classes/Modules/Companies/ControllersLogic/UpdateCompanyEInvoiceRequestLogic.php
@@ -6,7 +6,7 @@ namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Companies\Services\UpdatesCompanyEInvoiceRequest;
use App\Classes\Modules\Companies\Services\FetchesCompany;
-use App\Classes\Modules\Rules\DataTransferObjects\EInvoiceRequestDTO;
+use App\Classes\Modules\Companies\DataTransferObjects\EInvoiceRequestDTO;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
diff --git a/app/Classes/Modules/Rules/DataTransferObjects/EInvoiceInfoDTO.php b/app/Classes/Modules/Companies/DataTransferObjects/EInvoiceInfoDTO.php
similarity index 95%
rename from app/Classes/Modules/Rules/DataTransferObjects/EInvoiceInfoDTO.php
rename to app/Classes/Modules/Companies/DataTransferObjects/EInvoiceInfoDTO.php
index f768b2c1..2717bf7c 100644
--- a/app/Classes/Modules/Rules/DataTransferObjects/EInvoiceInfoDTO.php
+++ b/app/Classes/Modules/Companies/DataTransferObjects/EInvoiceInfoDTO.php
@@ -1,6 +1,6 @@
all());
$result = $this->ruleEvaluator->evaluate([
- App()->make(CanProceedEInvoicePromptedRule::class),
- App()->make(CanProceedTINRule::class),
+ App()->make(CanPassEInvoicePromptedRule::class),
+ App()->make(CanPassTINRule::class),
], $dto);
if ($result->failed()) {
diff --git a/app/Classes/Modules/Rules/ControllersLogic/CheckPurchaseOrderRuleLogic.php b/app/Classes/Modules/Rules/ControllersLogic/CheckPurchaseOrderRuleLogic.php
index 577e4618..41f24c22 100644
--- a/app/Classes/Modules/Rules/ControllersLogic/CheckPurchaseOrderRuleLogic.php
+++ b/app/Classes/Modules/Rules/ControllersLogic/CheckPurchaseOrderRuleLogic.php
@@ -7,8 +7,8 @@ use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Rules\DataTransferObjects\CheckPurchaseOrderRuleDTO;
use App\Classes\Modules\Rules\Services\RuleEvaluator;
-use App\Classes\Modules\Rules\Standards\Rules\CanProceedEInvoicePromptedRule;
-use App\Classes\Modules\Rules\Standards\Rules\CanProceedPurchaseOrderRule;
+use App\Classes\Modules\Rules\Standards\Rules\CanPassEInvoicePromptedRule;
+use App\Classes\Modules\Rules\Standards\Rules\CanPassPurchaseOrderRule;
use App\Http\Resources\RuleResource;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -49,8 +49,8 @@ class CheckPurchaseOrderRuleLogic extends AbstractControllerLogic
$dto = new CheckPurchaseOrderRuleDTO($request->all());
$result = $this->ruleEvaluator->evaluate([
- App()->make(CanProceedEInvoicePromptedRule::class),
- App()->make(CanProceedPurchaseOrderRule::class),
+ App()->make(CanPassEInvoicePromptedRule::class),
+ App()->make(CanPassPurchaseOrderRule::class),
], $dto);
if ($result->failed()) {
diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanProceedEInvoicePromptedRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassEInvoicePromptedRule.php
similarity index 85%
rename from app/Classes/Modules/Rules/Standards/Rules/CanProceedEInvoicePromptedRule.php
rename to app/Classes/Modules/Rules/Standards/Rules/CanPassEInvoicePromptedRule.php
index dcddbcdd..5ab57fdf 100644
--- a/app/Classes/Modules/Rules/Standards/Rules/CanProceedEInvoicePromptedRule.php
+++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassEInvoicePromptedRule.php
@@ -6,14 +6,14 @@ use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Companies\Services\FetchesCompany;
-class CanProceedEInvoicePromptedRule extends AbstractRule
+class CanPassEInvoicePromptedRule extends AbstractRule
{
/** @var FetchesCompany */
private $fetchesCompany;
/**
- * CanProceedEInvoicePromptedRule constructor.
+ * CanPassEInvoicePromptedRule constructor.
* @param FetchesCompany $fetchesCompany
*/
public function __construct(FetchesCompany $fetchesCompany)
@@ -48,7 +48,7 @@ class CanProceedEInvoicePromptedRule extends AbstractRule
//Check if account requires E-Invoice
$company = $this->fetchesCompany->execute(['id' => $object->companyId]);
if($company->e_invoice === null){
- throw new CriteriaNotFulfilledException("Please refresh page to answer question related to E-Invoice.");
+ throw new CriteriaNotFulfilledException("Please refresh page and click 'Make Payment' first to answer question related to E-Invoice.");
}
return true;
}
diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanPassEditingPORule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassEditingPORule.php
new file mode 100644
index 00000000..62293b6d
--- /dev/null
+++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassEditingPORule.php
@@ -0,0 +1,67 @@
+fetchesBooking = $fetchesBooking;
+ $this->fetchesCompany = $fetchesCompany;
+ }
+
+ /**
+ * @return bool
+ */
+ protected function authorized($object): bool
+ {
+ return true;
+
+ }
+
+ /**
+ * @return bool
+ */
+ protected function validators($object): bool
+ {
+ return true;
+
+ }
+
+
+ /**
+ * @return bool
+ */
+ protected function criteria($object): bool
+ {
+ //Check if user is allow to edit purchase order
+ $booking = $this->fetchesBooking->execute(['id' => $object->bookingId]);
+
+ $paidAmount = floatval((App()->make(CalculatesBookingPayableAmount::class))->execute($booking, $booking->fix_currency_id)) - floatval((App()->make(CalculatesBookingRefundAmount::class))->execute($booking, $booking->fix_currency_id));
+
+ if($paidAmount > 0){
+ throw new CriteriaNotFulfilledException("Purchase order form is no longer allow to be edited.");
+ }
+ return true;
+ }
+}
diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanProceedPurchaseOrderRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassPurchaseOrderRule.php
similarity index 96%
rename from app/Classes/Modules/Rules/Standards/Rules/CanProceedPurchaseOrderRule.php
rename to app/Classes/Modules/Rules/Standards/Rules/CanPassPurchaseOrderRule.php
index f9483835..c6782cf5 100644
--- a/app/Classes/Modules/Rules/Standards/Rules/CanProceedPurchaseOrderRule.php
+++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassPurchaseOrderRule.php
@@ -13,7 +13,7 @@ use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\ServiceType;
use Illuminate\Support\Facades\Log;
-class CanProceedPurchaseOrderRule extends AbstractRule
+class CanPassPurchaseOrderRule extends AbstractRule
{
/** @var FetchesBooking */
@@ -23,7 +23,7 @@ class CanProceedPurchaseOrderRule extends AbstractRule
private $fetchesCompany;
/**
- * CanProceedPurchaseOrderRule constructor.
+ * CanPassPurchaseOrderRule constructor.
* @param FetchesBooking $fetchesBooking
* @param FetchesCompany $fetchesCompany
*/
diff --git a/app/Classes/Modules/Rules/Standards/Rules/CanProceedTINRule.php b/app/Classes/Modules/Rules/Standards/Rules/CanPassTINRule.php
similarity index 93%
rename from app/Classes/Modules/Rules/Standards/Rules/CanProceedTINRule.php
rename to app/Classes/Modules/Rules/Standards/Rules/CanPassTINRule.php
index a4adc674..3f767912 100644
--- a/app/Classes/Modules/Rules/Standards/Rules/CanProceedTINRule.php
+++ b/app/Classes/Modules/Rules/Standards/Rules/CanPassTINRule.php
@@ -7,14 +7,14 @@ use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Companies\Services\FetchesCompany;
-class CanProceedTINRule extends AbstractRule
+class CanPassTINRule extends AbstractRule
{
/** @var FetchesCompany */
private $fetchesCompany;
/**
- * CanProceedTINRule constructor.
+ * CanPassTINRule constructor.
* @param FetchesCompany $fetchesCompany
*/
public function __construct(FetchesCompany $fetchesCompany)
diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php
index 9bab107f..862945f0 100644
--- a/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php
+++ b/app/Classes/Modules/Transactions/ControllersLogic/CreatePurchaseOrderTransactionLogic.php
@@ -3,9 +3,11 @@
namespace App\Classes\Modules\Transactions\ControllersLogic;
+use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Bookings\Services\FetchesBooking;
use App\Classes\Modules\Companies\Services\FetchesCompany;
+use App\Classes\Modules\Transactions\DataTransferObjects\CreatePurchaseOrderDTO;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Processors\CreatePurchaseOrderTransactionProcessor;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
@@ -15,6 +17,8 @@ use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\Services\UpdatesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
+use App\Classes\Modules\Rules\Services\RuleEvaluator;
+use App\Classes\Modules\Rules\Standards\Rules\CanPassEditingPORule;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\TransactionType;
@@ -46,17 +50,27 @@ class CreatePurchaseOrderTransactionLogic extends AbstractControllerLogic
/** @var CreatePurchaseOrderTransactionProcessor */
private $createPurchaseOrderTransactionProcessor;
+ /** @var RuleEvaluator */
+ private $ruleEvaluator;
+
+ /** @var CanPassEditingPORule */
+ private $canPassEditingPORule;
+
/**
* CreatePurchaseOrderTransactionLogic constructor.
* @param FetchesBooking $fetchesBooking
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor
+ * @param RuleEvaluator $ruleEvaluator
+ * @param CanPassEditingPORule $canPassEditingPORule
*/
- public function __construct(FetchesBooking $fetchesBooking, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor)
+ public function __construct(FetchesBooking $fetchesBooking, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor, RuleEvaluator $ruleEvaluator, CanPassEditingPORule $canPassEditingPORule)
{
$this->fetchesBooking = $fetchesBooking;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor;
+ $this->ruleEvaluator = $ruleEvaluator;
+ $this->canPassEditingPORule = $canPassEditingPORule;
}
/**
@@ -64,9 +78,20 @@ class CreatePurchaseOrderTransactionLogic extends AbstractControllerLogic
* @param string $id
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
+ * @throws \App\Classes\Exceptions\CriteriaNotFulfilledException
*/
public function logic(Request $request, $id = '') : JsonResponse
{
+
+ $dto = new CreatePurchaseOrderDTO($request->all());
+ $result = $this->ruleEvaluator->evaluate([
+ $this->canPassEditingPORule
+ ], $dto);
+
+ if ($result->failed()) {
+ throw new CriteriaNotFulfilledException("- " . implode(" - ", $result->messages()));
+ }
+
/** @var Booking $booking */
$booking = $this->fetchesBooking->execute(['id' => $request->route('id') ?? $id]);
@@ -87,7 +112,4 @@ class CreatePurchaseOrderTransactionLogic extends AbstractControllerLogic
return $this->resourceResponse(new TransactionResource($transaction));
}
-
-
-
}
diff --git a/app/Classes/Modules/Transactions/DataTransferObjects/CreatePurchaseOrderDTO.php b/app/Classes/Modules/Transactions/DataTransferObjects/CreatePurchaseOrderDTO.php
new file mode 100644
index 00000000..074640ad
--- /dev/null
+++ b/app/Classes/Modules/Transactions/DataTransferObjects/CreatePurchaseOrderDTO.php
@@ -0,0 +1,25 @@
+bookingId = $data['booking_id'];
+ $this->companyId = $data['company_id'];
+ }
+
+ public function toArray(): array
+ {
+ return [
+ 'booking_id' => $this->bookingId,
+ 'company_id' => $this->companyId,
+ ];
+ }
+}
diff --git a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue
index de4e496b..4636db2a 100644
--- a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue
+++ b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue
@@ -188,12 +188,12 @@
Your Purchase Order {{data.purchase_order.status === 1 ? 'is Being Processed for Verification' : 'has been Approved' }}
-
+
If you would like to still edit your Purchase Order you can do that by clicking on the edit button below, but your purchase order verification request will be reset.
Your Purchase Order {{data.purchase_order.status === 1 ? 'is Being Processed for Verification' : 'has been Approved' }}
-
+
If you would like to still edit your Purchase Order you can do that by clicking on the edit button below, but your purchase order verification request will be reset.
-
+
@@ -246,6 +246,12 @@
return this.products.reduce(function(last, product) {
return last + product.total;
}, 0);
+ },
+ allowPOEditing() {
+ const noPaymentsMade = Math.round((this.data.paid_amount + Number.EPSILON) * 100) / 100 === 0;
+ const noPendingVerifications = this.data.payment_history.every(payment => payment.status !== 1);
+
+ return noPaymentsMade && noPendingVerifications;
}
},
watch: {
From ec9587b91cd3e77662b8da35987b9658798ec4ee Mon Sep 17 00:00:00 2001
From: Dillon Ngo
Date: Sat, 31 May 2025 22:22:58 +0800
Subject: [PATCH 14/38] E-Invoice - New business rule, transfer now has
duration limit, apply on payment verification document upload by user
---
...CreatePaymentVerificationDocumentLogic.php | 28 +++++++++++++++++--
.../CreatePaymentVerificationDocumentDTO.php | 25 +++++++++++++++++
.../PaymentVerificationFormComponent.vue | 8 ++++--
3 files changed, 55 insertions(+), 6 deletions(-)
create mode 100644 app/Classes/Modules/Bookings/DataTransferObjects/CreatePaymentVerificationDocumentDTO.php
diff --git a/app/Classes/Modules/Bookings/ControllersLogic/CreatePaymentVerificationDocumentLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/CreatePaymentVerificationDocumentLogic.php
index bfd0229d..cd39e81a 100644
--- a/app/Classes/Modules/Bookings/ControllersLogic/CreatePaymentVerificationDocumentLogic.php
+++ b/app/Classes/Modules/Bookings/ControllersLogic/CreatePaymentVerificationDocumentLogic.php
@@ -2,8 +2,9 @@
namespace App\Classes\Modules\Bookings\ControllersLogic;
-
+use App\Classes\Exceptions\CriteriaNotFulfilledException;
use App\Classes\General\Abstracts\AbstractControllerLogic;
+use App\Classes\Modules\Bookings\DataTransferObjects\CreatePaymentVerificationDocumentDTO;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Companies\Services\UpdatesCompanyStatus;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
@@ -11,6 +12,8 @@ use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
+use App\Classes\Modules\Rules\Services\RuleEvaluator;
+use App\Classes\Modules\Rules\Standards\Rules\CanPassOrderDurationLimitRule;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\CompanyType;
use App\Classes\ValueObjects\Constants\DocumentType;
@@ -44,19 +47,29 @@ class CreatePaymentVerificationDocumentLogic extends AbstractControllerLogic
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
+ /** @var RuleEvaluator */
+ private $ruleEvaluator;
+
+ /** @var CanPassOrderDurationLimitRule */
+ private $canPassOrderDurationLimitRule;
+
/**
* CreatePaymentVerificationDocumentLogic constructor.
* @param FetchesTransaction $fetchesTransaction
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFile
* @param UpdatesTransactionStatus $updatesTransactionStatus
+ * @param RuleEvaluator $ruleEvaluator
+ * @param CanPassOrderDurationLimitRule $canPassOrderDurationLimitRule
*/
- public function __construct(FetchesTransaction $fetchesTransaction, CreatesDocument $createsDocument, CreatesFiles $createsFile, UpdatesTransactionStatus $updatesTransactionStatus)
+ public function __construct(FetchesTransaction $fetchesTransaction, CreatesDocument $createsDocument, CreatesFiles $createsFile, UpdatesTransactionStatus $updatesTransactionStatus, RuleEvaluator $ruleEvaluator, CanPassOrderDurationLimitRule $canPassOrderDurationLimitRule)
{
$this->fetchesTransaction = $fetchesTransaction;
$this->createsDocument = $createsDocument;
$this->createsFile = $createsFile;
$this->updatesTransactionStatus = $updatesTransactionStatus;
+ $this->ruleEvaluator = $ruleEvaluator;
+ $this->canPassOrderDurationLimitRule = $canPassOrderDurationLimitRule;
}
/**
@@ -66,6 +79,15 @@ class CreatePaymentVerificationDocumentLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
+ $dto = new CreatePaymentVerificationDocumentDTO($request->all());
+
+ $result = $this->ruleEvaluator->evaluate([
+ $this->canPassOrderDurationLimitRule,
+ ], $dto);
+
+ if ($result->failed()) {
+ throw new CriteriaNotFulfilledException("- " . implode(" - ", $result->messages()));
+ }
$transaction = $this->fetchesTransaction->execute(['id' => $request->route('payment_id')]);
@@ -80,4 +102,4 @@ class CreatePaymentVerificationDocumentLogic extends AbstractControllerLogic
return $this->response([]);
}
-}
\ No newline at end of file
+}
diff --git a/app/Classes/Modules/Bookings/DataTransferObjects/CreatePaymentVerificationDocumentDTO.php b/app/Classes/Modules/Bookings/DataTransferObjects/CreatePaymentVerificationDocumentDTO.php
new file mode 100644
index 00000000..ab0b7c96
--- /dev/null
+++ b/app/Classes/Modules/Bookings/DataTransferObjects/CreatePaymentVerificationDocumentDTO.php
@@ -0,0 +1,25 @@
+bookingId = $data['booking_id'];
+ $this->companyId = $data['company_id'];
+ }
+
+ public function toArray(): array
+ {
+ return [
+ 'booking_id' => $this->bookingId,
+ 'company_id' => $this->companyId,
+ ];
+ }
+}
diff --git a/resources/assets/vue/components/bookings/forms/PaymentVerificationFormComponent.vue b/resources/assets/vue/components/bookings/forms/PaymentVerificationFormComponent.vue
index 4e47728a..abb3c07c 100644
--- a/resources/assets/vue/components/bookings/forms/PaymentVerificationFormComponent.vue
+++ b/resources/assets/vue/components/bookings/forms/PaymentVerificationFormComponent.vue
@@ -120,13 +120,15 @@
submitForm(){
this.parameters = {
- files: this.files
+ files: this.files,
+ booking_id: this.id,
+ company_id: this.data.booking.company.id,
};
- this.submit(this.route('api.booking.payment.verification.create', this.id, this.data.id), 'post', this.section, true, false)
+ this.submit(this.route('api.booking.payment.verification.create', this.id, this.data.id), 'post', this.section, true, true);
}
},
mixins: [ModalFromHandler]
}
-
\ No newline at end of file
+
From 094e60e9c3f47ca0a4bddbf1c5d422a6630b927d Mon Sep 17 00:00:00 2001
From: Dillon Ngo
Date: Sat, 31 May 2025 22:46:42 +0800
Subject: [PATCH 15/38] E-Invoice - Minor validation on postcode input from
user
---
.../vue/components/address/forms/EInvoiceInfoFormComponent.vue | 2 +-
1 file changed, 1 insertion(+), 1 deletion(-)
diff --git a/resources/assets/vue/components/address/forms/EInvoiceInfoFormComponent.vue b/resources/assets/vue/components/address/forms/EInvoiceInfoFormComponent.vue
index 0b8c20e5..5ca69ee9 100644
--- a/resources/assets/vue/components/address/forms/EInvoiceInfoFormComponent.vue
+++ b/resources/assets/vue/components/address/forms/EInvoiceInfoFormComponent.vue
@@ -213,7 +213,7 @@
street_two: {},
district_id: { required },
state_id: { required },
- post_code: { required, notZero},
+ post_code: { notZero, fiveDigits},
tin: {
...(companyType === 0
? {
From 893631064b60ad138b13a2fa8e19a003bc4ebf79 Mon Sep 17 00:00:00 2001
From: Dillon Ngo
Date: Fri, 6 Jun 2025 03:17:52 +0800
Subject: [PATCH 16/38] 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 @@
+ CIEF WORLDWIDE SDN BHD
+ (1134596-M)
+ No. 72-3, Jalan Jalil 1,
+ The Earth Bukit Jalil,
+ 57000 Kuala Lumpur
+ Tel: 03-8082 1252
+ TIN: C23880226040, MSIC: 46909
+ SST: W10-2403-32000643
+
diff --git a/resources/assets/vue/components/bookings/forms/EditBookingAmountFormV2Component.vue b/resources/assets/vue/components/bookings/forms/EditBookingAmountFormV2Component.vue
new file mode 100644
index 00000000..a7001a99
--- /dev/null
+++ b/resources/assets/vue/components/bookings/forms/EditBookingAmountFormV2Component.vue
@@ -0,0 +1,69 @@
+
+
+
+
+
+
+
+
Edit Booking Amount
+
To ensure both updates take effect, please update the purchase order details with the equivalent booking amount immediately after this update. If not done in sequence, neither update will be applied.