From 67ea1c7de4aec6229e1eb8d0429e9163ffbf0d2c Mon Sep 17 00:00:00 2001 From: Steve Ng Date: Sat, 30 Sep 2023 19:29:36 +0800 Subject: [PATCH 1/8] fixing code in statement module --- .../GroupApproveStatementTransactionLogic.php | 9 ++------- app/Classes/ValueObjects/Constants/SystemType.php | 12 ++++++++++++ app/Http/Resources/BankStatementDetailResource.php | 4 ++++ .../BankStatementTransactionOwnerResource.php | 2 +- .../sections/TransactionsMappingComponent.vue | 1 + .../forms/GeneralConfirmationFormComponent.vue | 10 +++++++++- 6 files changed, 29 insertions(+), 9 deletions(-) diff --git a/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php index 3b220146..f9eb9c7b 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php @@ -57,13 +57,8 @@ class GroupApproveStatementTransactionLogic extends AbstractControllerLogic public function logic(Request $request): JsonResponse { - $filters = [ - "min_amount" => 0, - "is_mapped" => true, - "is_mapped_with_multiple" => false, - "statement_transaction_owner_type_in" => [1, 2], - "statement_transaction_owner_status_in" => [1] - ]; + $filters = $request->except(['per_page','order_by']); + $statementTransactions = $this->listsBankStatementTransactions->execute($filters); foreach ($statementTransactions as $statementTransaction) { diff --git a/app/Classes/ValueObjects/Constants/SystemType.php b/app/Classes/ValueObjects/Constants/SystemType.php index dd948f13..76f6bffa 100644 --- a/app/Classes/ValueObjects/Constants/SystemType.php +++ b/app/Classes/ValueObjects/Constants/SystemType.php @@ -8,9 +8,21 @@ final class SystemType { public const SHIPPING_PORTAL = 'SHIPPING_PORTAL'; + public const CNTR = 'CNTR'; + + public const LITE = 'LITE'; + + public const PROBASHI = 'PROBASHI'; + + public const PETS = 'PETS'; + public const SYSTEM_NAMES = [ 'exchange' => self::EXCHANGE, 'shipping_portal' => self::SHIPPING_PORTAL, 'izyim' => self::SHIPPING_PORTAL, + 'lite' => self::LITE, + 'cntr' => self::CNTR, + 'probashi' => self::PROBASHI, + 'pets' => self::PETS ]; } diff --git a/app/Http/Resources/BankStatementDetailResource.php b/app/Http/Resources/BankStatementDetailResource.php index 5087b00b..c5bfba28 100644 --- a/app/Http/Resources/BankStatementDetailResource.php +++ b/app/Http/Resources/BankStatementDetailResource.php @@ -21,6 +21,10 @@ class BankStatementDetailResource extends JsonResource 'id' => $this->id, 'date' => Carbon::parse($transaction->posting_date)->format('Y-m-d'), 'transaction_description_1' => $transaction->transaction_description, + 'transaction_description_2' => $transaction->transaction_description_2, + 'transaction_description_3' => $transaction->transaction_description_3, + 'transaction_description_4' => $transaction->transaction_description_4, + 'transaction_description_5' => $transaction->transaction_description_5, 'pay_for' => $transaction->transaction_description_2, 'system_references' => $this->system, 'amount' => $transaction->amount, diff --git a/app/Http/Resources/BankStatementTransactionOwnerResource.php b/app/Http/Resources/BankStatementTransactionOwnerResource.php index 468d9ec5..3b67eed4 100644 --- a/app/Http/Resources/BankStatementTransactionOwnerResource.php +++ b/app/Http/Resources/BankStatementTransactionOwnerResource.php @@ -28,7 +28,7 @@ class BankStatementTransactionOwnerResource extends JsonResource } if($this->type === StatementTransactionOwnerType::WALLET_TOP_UP){ - $referenceLink = route('booking.details', $this->owner_reference); + $referenceLink = route('wallet.details', $this->owner_reference); } } } diff --git a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue index 7bbf87aa..4b676e04 100644 --- a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue +++ b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue @@ -68,6 +68,7 @@ class="text-center" :apiRoute="route('api.accounting.statement_transaction.owner.groupApprove')" apiMethod="post" + :params="filter" :section="section" > diff --git a/resources/assets/vue/components/general/forms/GeneralConfirmationFormComponent.vue b/resources/assets/vue/components/general/forms/GeneralConfirmationFormComponent.vue index 0b5c92ec..cdb477ee 100644 --- a/resources/assets/vue/components/general/forms/GeneralConfirmationFormComponent.vue +++ b/resources/assets/vue/components/general/forms/GeneralConfirmationFormComponent.vue @@ -15,7 +15,7 @@
Cancel
-
{{ buttonText }}
+
{{ buttonText }}
@@ -32,6 +32,10 @@ type: String, required: true }, + params: { + type: Array, + required: false + }, modalType: { type: String, default: 'confirm' @@ -50,6 +54,10 @@ }, }, methods: { + submitForm() { + if (this.params) this.parameters = this.params; + return this.submit(this.apiRoute, this.apiMethod, this.section, true, true); + } }, mixins: [componentHandler, ModalFormHandler] From 28feae50c152bcb1365b434182cbf6ff2f136c6a Mon Sep 17 00:00:00 2001 From: Jia Sheng Lee Date: Tue, 3 Oct 2023 00:35:35 +0800 Subject: [PATCH 2/8] invoice adjustment --- resources/views/pages/pdfs/invoice.blade.php | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/resources/views/pages/pdfs/invoice.blade.php b/resources/views/pages/pdfs/invoice.blade.php index db6c42c5..9a862fe2 100644 --- a/resources/views/pages/pdfs/invoice.blade.php +++ b/resources/views/pages/pdfs/invoice.blade.php @@ -80,8 +80,9 @@ @foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail) @php $exactUnitPrice = bcdiv($transaction_detail->price, $transaction->currency_rate, 7); + $displayUnitPrice = round($exactUnitPrice, 2); $itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5); - $displayedItemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 2); + $displayedItemTotal = round(bcmul($displayUnitPrice, $transaction_detail->quantity, 7), 2); $displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2); $subtotal = bcadd($subtotal, $itemTotal, 5); @endphp @@ -91,10 +92,10 @@ {{ $transaction_detail->product_name }} {{ $transaction_detail->quantity }} - {{ number_format($exactUnitPrice, 2) }} + {{ $displayUnitPrice }} - {{ number_format($itemTotal, 2) }} + {{ $displayedItemTotal }} @endforeach @@ -106,7 +107,7 @@ Subtotal - {{ number_format($subtotal, 2) }} + {{ number_format($displayedSubtotal, 2) }} @@ -130,9 +131,9 @@ @endif @php - $displayedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); + $displayedTotal = bcadd(bcadd(bcadd($displayedSubtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); $expectedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); - $discrepancy = bcsub($displayedTotal, $expectedTotal, 5); + $discrepancy = bcsub($expectedTotal, $displayedTotal, 5); $total = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); @endphp From 9938615fe4ce4311371e1238967c5b0569c27c68 Mon Sep 17 00:00:00 2001 From: Steve Ng Date: Tue, 3 Oct 2023 15:20:11 +0800 Subject: [PATCH 3/8] enhance the code in ApproveDuplicateBankStatementDetailsStatusLogic class to dynamic for update status to approve and revert back pending --- ...plicateBankStatementDetailsStatusLogic.php | 112 ++++++++---------- app/Models/StatementTransactionOwner.php | 6 + .../StatementTransactionComponent.vue | 38 +++++- .../sections/TransactionsMappingComponent.vue | 2 +- routes/accounting.php | 2 +- 5 files changed, 96 insertions(+), 64 deletions(-) diff --git a/app/Classes/Modules/Accounting/ControllersLogic/ApproveDuplicateBankStatementDetailsStatusLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/ApproveDuplicateBankStatementDetailsStatusLogic.php index e7d1a7c9..3872039b 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/ApproveDuplicateBankStatementDetailsStatusLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/ApproveDuplicateBankStatementDetailsStatusLogic.php @@ -135,7 +135,7 @@ class ApproveDuplicateBankStatementDetailsStatusLogic extends AbstractController public function logic(Request $request): JsonResponse { // Determine the approval status - $status = $this->getApprovalStatus($request); + $status = $this->getConstantStatus($request->route('status')); // Find the statement transaction owner $owner = $this->getOwner($request); @@ -143,21 +143,33 @@ class ApproveDuplicateBankStatementDetailsStatusLogic extends AbstractController // Update owner status $this->updateOwnerStatus($owner, $status); - // If the status is 'approved', handle the approval process - if ($status === ApprovalStatus::APPROVED) { - $this->handleApprovedStatus($owner); - } + // handle the siblings process + $this->handleSiblingsStatus($owner, $this->getSiblingsStatus($status)); // Check and approve remaining matches if any - $this->checkAndApproveRemainingMatches($owner); + $this->checkAndApproveRemainingMatches($owner, $status); // Return an empty response return $this->response([]); } - private function getApprovalStatus(Request $request): int + private function getConstantStatus(String $statusName=null): int { - return $request->route('status') == 'approve' ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED; + switch ($statusName) { + case 'approve': + return ApprovalStatus::APPROVED; + + case 'pending_verification': + return ApprovalStatus::PENDING_VERIFICATION; + + default: + return ApprovalStatus::REJECTED; + } + } + + private function getSiblingsStatus(int $status): int + { + return $status == ApprovalStatus::APPROVED ? ApprovalStatus::REJECTED : ApprovalStatus::PENDING_VERIFICATION; } private function getOwner(Request $request): StatementTransactionOwner @@ -170,23 +182,24 @@ class ApproveDuplicateBankStatementDetailsStatusLogic extends AbstractController $this->updatesBankStatementTransactionOwnerStatus->execute($owner, $status); } - private function handleApprovedStatus(StatementTransactionOwner $owner): void + private function handleSiblingsStatus(StatementTransactionOwner $owner, int $siblingStatus): void { - // Reject all other owners with the same system, owner type, and owner ID - $this->rejectOtherOwners($owner); + // update all other owners with the same system, owner type, and owner ID + $this->updateOtherOwners($owner, $siblingStatus); // Find all siblings and process them $siblings = $this->getSiblings($owner); - $this->processSiblings($siblings); + + foreach ($siblings as $sibling) { + $this->processSibling($sibling, $siblingStatus); + } } - private function rejectOtherOwners(StatementTransactionOwner $owner): void + private function updateOtherOwners(StatementTransactionOwner $owner, int $status): void { - StatementTransactionOwner::where('system', $owner->system) - ->where('owner_type', $owner->owner_type) - ->where('owner_id', $owner->owner_id) + StatementTransactionOwner::getSiblingsOwner() ->where('id', '!=', $owner->id) - ->update(['status' => ApprovalStatus::REJECTED]); + ->update(['status' => $status]); } private function getSiblings(StatementTransactionOwner $owner): Collection @@ -196,86 +209,65 @@ class ApproveDuplicateBankStatementDetailsStatusLogic extends AbstractController ->get(); } - private function processSiblings(Collection $siblings): void - { - foreach ($siblings as $sibling) { - $this->processSibling($sibling); - } - } - - private function processSibling(StatementTransactionOwner $sibling): void + private function processSibling(StatementTransactionOwner $sibling, int $siblingStatus): void { // Reject the sibling and save the changes - $sibling->status = ApprovalStatus::REJECTED; + $sibling->status = $siblingStatus; $sibling->save(); - + // Find all twins and process them $twins = $this->getTwins($sibling); - $this->processTwins($twins); - } - private function getTwins(StatementTransactionOwner $sibling): Collection - { - return StatementTransactionOwner::where('system', $sibling->system) - ->where('owner_type', $sibling->owner_type) - ->where('owner_id', $sibling->owner_id) - ->where('id', '!=', $sibling->id) - ->get(); - } - - private function processTwins(Collection $twins): void - { foreach ($twins as $twin) { $this->processTwin($twin); } } + private function getTwins(StatementTransactionOwner $sibling): Collection + { + return StatementTransactionOwner::getSiblingsOwner() + ->where('id', '!=', $sibling->id) + ->get(); + } + private function processTwin(StatementTransactionOwner $twin): void { // Find all owners with the same statement transaction ID as the twin - $owners = $this->getOwners($twin); + $owners = $this->getSiblings($twin); // If there is only one owner (the twin itself), approve it if ($owners->count() === 1) { - $this->updateOwnerStatus($twin, ApprovalStatus::APPROVED); + $this->updateOwnerStatus($twin, $this->getConstantStatus(request()->route('status'))); } } - private function getOwners(StatementTransactionOwner $transactionOwner): Collection - { - return StatementTransactionOwner::where('statement_transaction_id', $transactionOwner->statement_transaction_id) - ->where('id', '!=', $transactionOwner->id) - ->get(); - } - - private function checkAndApproveRemainingMatches(StatementTransactionOwner $owner): void + private function checkAndApproveRemainingMatches(StatementTransactionOwner $owner, int $status): void { // Find all remaining matching owners for the related transaction - $remainingMatches = $this->getRemainingMatches($owner); + $checkStatus = ($status == ApprovalStatus::APPROVED ? ApprovalStatus::PENDING_VERIFICATION : ApprovalStatus::APPROVED); + $remainingMatches = $this->getRemainingMatches($owner, $checkStatus); // Process each remaining match foreach ($remainingMatches as $match) { - $this->processRemainingMatch($match); + $this->processRemainingMatch($match, $status); } } - private function getRemainingMatches(StatementTransactionOwner $owner): Collection + private function getRemainingMatches(StatementTransactionOwner $owner, int $checkStatus): Collection { - return StatementTransactionOwner::where('system', $owner->system) - ->where('owner_type', $owner->owner_type) - ->where('owner_id', $owner->owner_id) - ->where('status', ApprovalStatus::PENDING_VERIFICATION) + return StatementTransactionOwner::getSiblingsOwner() + ->where('status', $checkStatus) ->get(); } - private function processRemainingMatch(StatementTransactionOwner $match): void + private function processRemainingMatch(StatementTransactionOwner $match, int $status): void { // Find all owners with the same statement transaction ID as the match - $owners = $this->getOwners($match); + $owners = $this->getSiblings($match); // If there is only one owner (the match itself), approve it if ($owners->count() === 1) { - $this->updateOwnerStatus($match, ApprovalStatus::APPROVED); + $this->updateOwnerStatus($match, $status); } } diff --git a/app/Models/StatementTransactionOwner.php b/app/Models/StatementTransactionOwner.php index 52e8d1fc..5bfe6f82 100644 --- a/app/Models/StatementTransactionOwner.php +++ b/app/Models/StatementTransactionOwner.php @@ -26,4 +26,10 @@ class StatementTransactionOwner extends Model { return $this->belongsTo(StatementTransaction::class, 'statement_transaction_id', 'id'); } + + public function scopeGetSiblingsOwner($query) { + $query->where('system', $this->system) + ->where('owner_type', $this->owner_type) + ->where('owner_id', $this->owner_id); + } } diff --git a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue index db2fc252..d36c149f 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -11,6 +11,36 @@ + + +
+
+
{{item.owners.approved[0].system}}
+
{{ typeString(item.owners.approved[0].type) }}
+
+ +
+
+
+
@@ -52,7 +82,8 @@
-
+ +
{{ item.amount }}
-
{{ [6, 7, 8, 9, 10, 11, 12, 13, 14].include(item.owners.approved[0].type) ? 'Miscellaneous' : 'Approved' }}
+
{{ [6, 7, 8, 9, 10, 11, 12, 13, 14].includes(item.owners.approved[0].type) ? 'Miscellaneous' : 'Approved' }}
Pending...
-
+
diff --git a/routes/accounting.php b/routes/accounting.php index c7112947..4fe0a1ad 100644 --- a/routes/accounting.php +++ b/routes/accounting.php @@ -10,7 +10,7 @@ Route::group(['prefix' => 'accounting', 'as' => 'accounting.', 'namespace' => 'A Route::put('/details/update', 'BankStatementController@update')->name('details.update'); }); - Route::post('bankStatement/{id}/details/{status}', 'ApproveDuplicateBankStatementDetailsStatusController@update')->where('status', 'approve|reject')->name('bankStatement.details.status.update'); + Route::post('bankStatement/{id}/details/{status}', 'ApproveDuplicateBankStatementDetailsStatusController@update')->where('status', 'approve|reject|pending_verification')->name('bankStatement.details.status.update'); Route::group(['prefix' => 'statement_transaction', 'as' => 'statement_transaction.'], function () { Route::post('/owner/group-approve', 'GroupApproveStatementTransactionController@approve')->name('owner.groupApprove'); From a0f600037b86781744632de6c664458bc237694b Mon Sep 17 00:00:00 2001 From: Jia Sheng Lee Date: Tue, 3 Oct 2023 22:35:37 +0800 Subject: [PATCH 4/8] import purchase order function --- .../ImportPurchaseOrderTransactionLogic.php | 111 ++++++++++++++++++ ...portPurchaseOrderTransactionController.php | 21 ++++ .../forms/PurchaseOrderFormComponent.vue | 42 ++++++- routes/transaction.php | 1 + 4 files changed, 174 insertions(+), 1 deletion(-) create mode 100644 app/Classes/Modules/Transactions/ControllersLogic/ImportPurchaseOrderTransactionLogic.php create mode 100644 app/Http/Controllers/Transactions/ImportPurchaseOrderTransactionController.php diff --git a/app/Classes/Modules/Transactions/ControllersLogic/ImportPurchaseOrderTransactionLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/ImportPurchaseOrderTransactionLogic.php new file mode 100644 index 00000000..3617bcfe --- /dev/null +++ b/app/Classes/Modules/Transactions/ControllersLogic/ImportPurchaseOrderTransactionLogic.php @@ -0,0 +1,111 @@ + 'Update Purchase Order', + 'message' => 'You have successfully updated you booking\'s purchase order' + ]; + } + + /** @var FetchesBooking */ + private $fetchesBooking; + + /** @var GeneratesTransactionBillNumber */ + private $generatesTransactionBillNumber; + + /** @var CreatePurchaseOrderTransactionProcessor */ + private $createPurchaseOrderTransactionProcessor; + + /** + * CreatePurchaseOrderTransactionLogic constructor. + * @param FetchesBooking $fetchesBooking + * @param GeneratesTransactionBillNumber $generatesTransactionBillNumber + * @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor + */ + public function __construct(FetchesBooking $fetchesBooking, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor) + { + $this->fetchesBooking = $fetchesBooking; + $this->generatesTransactionBillNumber = $generatesTransactionBillNumber; + $this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor; + } + + /** + * @param Request $request + * @param string $id + * @return JsonResponse + * @throws \App\Classes\Exceptions\MalformedRequestException + */ + public function logic(Request $request, $id = '') : JsonResponse + { + $files = $request->file('files'); + + $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); + foreach ($object->getFiles() as $file){ + $collection = Excel::toCollection(null, json_decode($file)->file_info->original->file, null, null, true); + + $sheet = $collection->first()->skip(1); + + $products = $sheet->map(function ($row) { + Log::info($row); + $stockCode = $row[0]; + $description = $row[1]; + $quantity = $row[2]; + $unit_price = $row[3]; + + return [ + 'stockCode' => $stockCode, + 'description' => $description, + 'quantity' => $quantity, + 'unit_price' => $unit_price + ]; + })->all(); + } + + // dd($products); + + /** @var Booking $booking */ + $booking = $this->fetchesBooking->execute(['id' => $request->route('id') ?? $id]); + + $billNumber = $this->generatesTransactionBillNumber->execute('PO-'); + + $total = collect($products)->sum(function($product){ + return $product['quantity'] * floatval(str_replace(',', '', $product['unit_price'])); + }); + + $object = new TransactionObject($billNumber, TransactionType::PURCHASE_ORDER, $booking->company->id, 1, + 1, PaymentMethodType::CASH, + $total, $total, $booking->fix_currency_id, $booking->fix_currency_id, + 1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, $products); + + + $transaction = $this->createPurchaseOrderTransactionProcessor->execute($booking, $object); + + return $this->resourceResponse(new TransactionResource($transaction)); + + } +} diff --git a/app/Http/Controllers/Transactions/ImportPurchaseOrderTransactionController.php b/app/Http/Controllers/Transactions/ImportPurchaseOrderTransactionController.php new file mode 100644 index 00000000..78caf5a4 --- /dev/null +++ b/app/Http/Controllers/Transactions/ImportPurchaseOrderTransactionController.php @@ -0,0 +1,21 @@ +execute($request); + } +} diff --git a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue index 7b7ec3d4..1ea2ecf8 100644 --- a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue +++ b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue @@ -81,6 +81,24 @@
+
+
+ + + +
+
+
+
+
+
+ +
+
+
+
@@ -175,6 +193,8 @@