diff --git a/app/Classes/General/Eloquent/Filters/CreatedAfterOrEqual.php b/app/Classes/General/Eloquent/Filters/CreatedAfterOrEqual.php index 7e563aee..9df98f40 100644 --- a/app/Classes/General/Eloquent/Filters/CreatedAfterOrEqual.php +++ b/app/Classes/General/Eloquent/Filters/CreatedAfterOrEqual.php @@ -16,6 +16,8 @@ class CreatedAfterOrEqual implements Filter */ public static function apply(Builder $builder, $value) { - return $builder->where('created_at', '>=', Carbon::parse($value)); + $table = $builder->getModel()->getTable(); + $startDate = Carbon::createFromFormat('d-m-Y', $value)->startOfDay(); + return $builder->where("{$table}.created_at", '>=', $startDate); } } \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/CreatedBeforeOrEqual.php b/app/Classes/General/Eloquent/Filters/CreatedBeforeOrEqual.php index ed97b48f..5b349540 100644 --- a/app/Classes/General/Eloquent/Filters/CreatedBeforeOrEqual.php +++ b/app/Classes/General/Eloquent/Filters/CreatedBeforeOrEqual.php @@ -15,6 +15,8 @@ class CreatedBeforeOrEqual implements Filter */ public static function apply(Builder $builder, $value) { - return $builder->where('created_at', '<=', Carbon::parse($value)); + $table = $builder->getModel()->getTable(); + $endDate = Carbon::createFromFormat('d-m-Y', $value)->endOfDay(); + return $builder->where("{$table}.created_at", '<=', $endDate); } } diff --git a/app/Classes/General/Eloquent/Filters/GroupByImportedDate.php b/app/Classes/General/Eloquent/Filters/GroupByImportedDate.php new file mode 100644 index 00000000..25f20fa3 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/GroupByImportedDate.php @@ -0,0 +1,18 @@ +groupby('imported_date'); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/ImportedDateFrom.php b/app/Classes/General/Eloquent/Filters/ImportedDateFrom.php new file mode 100644 index 00000000..140bbb20 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/ImportedDateFrom.php @@ -0,0 +1,18 @@ +whereDate('imported_date', '>=', date('Y-m-d',strtotime($value))); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/ImportedDateTo.php b/app/Classes/General/Eloquent/Filters/ImportedDateTo.php new file mode 100644 index 00000000..11bd3857 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/ImportedDateTo.php @@ -0,0 +1,18 @@ +whereDate('imported_date', '<=', date('Y-m-d',strtotime($value))); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php b/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php new file mode 100644 index 00000000..c0eb9e74 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php @@ -0,0 +1,23 @@ +where(function($q) use ($value) { + $q->whereDoesntHave('owners'); + $q->orwhereDoesntHave('owner_status'); + }); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/OwnerId.php b/app/Classes/General/Eloquent/Filters/OwnerId.php index eac7e32d..c2dfa685 100644 --- a/app/Classes/General/Eloquent/Filters/OwnerId.php +++ b/app/Classes/General/Eloquent/Filters/OwnerId.php @@ -14,7 +14,8 @@ class OwnerId implements Filter */ public static function apply(Builder $builder, $value) { - return $builder->where('owner_id', $value); + $table = $builder->getModel()->getTable(); + return $builder->where("{$table}.owner_id", $value); } } \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/OwnerType.php b/app/Classes/General/Eloquent/Filters/OwnerType.php index 6a13fb08..3feedccd 100644 --- a/app/Classes/General/Eloquent/Filters/OwnerType.php +++ b/app/Classes/General/Eloquent/Filters/OwnerType.php @@ -14,7 +14,8 @@ class OwnerType implements Filter */ public static function apply(Builder $builder, $value) { - return $builder->where('owner_type', $value); + $table = $builder->getModel()->getTable(); + return $builder->where("{$table}.owner_type", $value); } } \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionInvoiceReference.php b/app/Classes/General/Eloquent/Filters/StatementTransactionInvoiceReference.php new file mode 100644 index 00000000..9e3ba1e9 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionInvoiceReference.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->where('Invoice_reference', $value); + }); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerInvoiceOrReceiptRefNotNull.php b/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerInvoiceOrReceiptRefNotNull.php new file mode 100644 index 00000000..f6a23389 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerInvoiceOrReceiptRefNotNull.php @@ -0,0 +1,24 @@ +whereHas('owners', function ($query) { + return $query->where(function ($q) { + $q->orWhereNotNull('invoice_reference')->orWhereNotNull('receipt_reference'); + }); + }); + } +} diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerReference.php b/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerReference.php new file mode 100644 index 00000000..c0a7beaf --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerReference.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->where('owner_reference', $value); + }); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionPostingEnd.php b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingEnd.php new file mode 100644 index 00000000..e837245e --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingEnd.php @@ -0,0 +1,18 @@ +whereDate('posting_date', '<=', date('Y-m-d',strtotime($value))); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionPostingStart.php b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingStart.php new file mode 100644 index 00000000..c3560357 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingStart.php @@ -0,0 +1,18 @@ +whereDate('posting_date', '>=', date('Y-m-d',strtotime($value))); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionReceiptReference.php b/app/Classes/General/Eloquent/Filters/StatementTransactionReceiptReference.php new file mode 100644 index 00000000..f808f784 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionReceiptReference.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->where('receipt_reference', $value); + }); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/StatusIn.php b/app/Classes/General/Eloquent/Filters/StatusIn.php index cbfdfbd0..85425802 100644 --- a/app/Classes/General/Eloquent/Filters/StatusIn.php +++ b/app/Classes/General/Eloquent/Filters/StatusIn.php @@ -14,7 +14,8 @@ class StatusIn implements Filter */ public static function apply(Builder $builder, $value) { - return $builder->whereIn('status', $value); + $table = $builder->getModel()->getTable(); + return $builder->whereIn("{$table}.status", $value); } } \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNotNull.php b/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNotNull.php new file mode 100644 index 00000000..b10fd92d --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNotNull.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->whereNotNull($value); + }); + } + +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNull.php b/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNull.php new file mode 100644 index 00000000..a9317771 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/WhereHasOwnersAndNull.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->whereNull($value); + }); + } + +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/WithBookingMarkingLike.php b/app/Classes/General/Eloquent/Filters/WithBookingMarkingLike.php new file mode 100644 index 00000000..ed35cc31 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/WithBookingMarkingLike.php @@ -0,0 +1,29 @@ +join('transactions as t2', 't2.payment_reference', '=', 'transactions.bill_no') + ->join('bookings', function ($join) use ($value) { + $join->on('bookings.id', '=', 't2.owner_id') + ->where('bookings.marking', 'LIKE', '%'.$value.'%'); + }) + ->addSelect(['transactions.*','t2.owner_id as bookingId', 'bookings.marking as bookingMarking']); + } +} \ No newline at end of file diff --git a/app/Classes/Jobs/CreateBankStatementTransactionOwners.php b/app/Classes/Jobs/CreateBankStatementTransactionOwners.php index e7797210..caab846f 100644 --- a/app/Classes/Jobs/CreateBankStatementTransactionOwners.php +++ b/app/Classes/Jobs/CreateBankStatementTransactionOwners.php @@ -13,9 +13,15 @@ class CreateBankStatementTransactionOwners implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; + private $transactions; + + public function __construct($transactions) { + $this->transactions = $transactions; + } + public function handle() { - (App()->make(CreateBankStatementTransactionOwnersProcessor::class))->execute(); + (App()->make(CreateBankStatementTransactionOwnersProcessor::class))->execute($this->transactions); } public function delay($delay) 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/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php index 3b220146..7ae8a2ae 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php @@ -57,17 +57,12 @@ 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) { - $owners = $statementTransaction->owners; + $owners = $statementTransaction->owners()->where('status', ApprovalStatus::PENDING_VERIFICATION)->get(); if (count($owners)) { $this->updatesBankStatementTransactionOwnerStatus->execute($owners->first(), ApprovalStatus::APPROVED); diff --git a/app/Classes/Modules/Accounting/ControllersLogic/HistoryImportedTransactionMappedControllerLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/HistoryImportedTransactionMappedControllerLogic.php new file mode 100644 index 00000000..2f96c613 --- /dev/null +++ b/app/Classes/Modules/Accounting/ControllersLogic/HistoryImportedTransactionMappedControllerLogic.php @@ -0,0 +1,49 @@ + 'Retrieved History Imported Invoices', + 'message' => 'You have successfully retrieved history imported invoices' + ]; + } + + /** @var ListTransactionMappingLogs */ + private $listTransactionMappingLogs; + + /** + * UpdateAnnouncementLogic constructor. + * @param ListTransactionMappingLogs $listTransactionMappingLogs + */ + public function __construct( + ListTransactionMappingLogs $listTransactionMappingLogs + ) { + $this->listTransactionMappingLogs = $listTransactionMappingLogs; + } + + /** + * @param Request $request + * @return JsonResponse + */ + public function logic(Request $request): JsonResponse + { + $query = $this->listTransactionMappingLogs->execute($this->listTransactionMappingLogs->deserializeFilters($request->input('filters'))); + + return $this->collectionResponse(TransactionMappingLogResource::collection($query)); + } +} diff --git a/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php index d9eab3db..70186ce1 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php @@ -19,6 +19,9 @@ use App\Models\Wallet; use Exception; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; +use App\Classes\Modules\Accounting\Services\UpdatesBankStatementTransactionOwnerStatus; +use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Models\StatementTransactionOwner; class UpdateBankStatementDetailLogic extends AbstractControllerLogic { @@ -40,14 +43,21 @@ class UpdateBankStatementDetailLogic extends AbstractControllerLogic /** @var ChecksBillNumber */ private $checksBillNumber; + /** @var UpdatesBankStatementTransactionOwnerStatus */ + private $updatesBankStatementTransactionOwnerStatus; + /** * @param FetchesBankStatementTransaction $fetchesBankStatementTransaction * @param ChecksBillNumber $checksBillNumber */ - public function __construct(FetchesBankStatementTransaction $fetchesBankStatementTransaction, ChecksBillNumber $checksBillNumber) + public function __construct( + FetchesBankStatementTransaction $fetchesBankStatementTransaction, + ChecksBillNumber $checksBillNumber, + UpdatesBankStatementTransactionOwnerStatus $updatesBankStatementTransactionOwnerStatus) { $this->fetchesBankStatementTransaction = $fetchesBankStatementTransaction; $this->checksBillNumber = $checksBillNumber; + $this->updatesBankStatementTransactionOwnerStatus = $updatesBankStatementTransactionOwnerStatus; } public function logic(Request $request): JsonResponse @@ -129,7 +139,10 @@ class UpdateBankStatementDetailLogic extends AbstractControllerLogic $system = $systemReference != null ? SystemType::SYSTEM_NAMES[$systemReference] : ''; - $this->createBankStatementTransactionOwner($bankStatementTransaction, $statementTransactionOwnerType, $system, $owner_type, $owner_id, $owner_reference); + $statementTransactionOwner = $this->createBankStatementTransactionOwner($bankStatementTransaction, $statementTransactionOwnerType, $system, $owner_type, $owner_id, $owner_reference); + + // this for edit a transaction already mapped + if ($request->has('editMapped')) $this->editAccountMapped($statementTransactionOwner); return $this->response([]); } @@ -144,9 +157,26 @@ class UpdateBankStatementDetailLogic extends AbstractControllerLogic 'owner_reference' => $owner_reference, ]; - $bankStatementTransaction->owners()->firstOrCreate($ownerData); - + return $bankStatementTransaction->owners()->where('status','<>',ApprovalStatus::REJECTED)->firstOrCreate($ownerData); } + private function editAccountMapped(StatementTransactionOwner $owner){ + $this->updateOwnerStatus($owner, ApprovalStatus::APPROVED); + + // update all other owners with the same system, owner type, and owner ID + $this->updateOtherOwners($owner, ApprovalStatus::REJECTED); + } + + private function updateOwnerStatus(StatementTransactionOwner $owner, int $status) + { + $this->updatesBankStatementTransactionOwnerStatus->execute($owner, $status); + } + + private function updateOtherOwners(StatementTransactionOwner $owner, int $status): void + { + StatementTransactionOwner::where('statement_transaction_id', $owner->statement_transaction_id) + ->where('id', '!=', $owner->id) + ->update(['status' => $status]); + } } diff --git a/app/Classes/Modules/Accounting/ControllersLogic/UpdateStatementTransactionStatusLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/UpdateStatementTransactionStatusLogic.php index 3a006e9e..b208c2e3 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/UpdateStatementTransactionStatusLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/UpdateStatementTransactionStatusLogic.php @@ -2,16 +2,14 @@ namespace App\Classes\Modules\Accounting\ControllersLogic; -use App\Classes\General\Abstracts\AbstractControllerLogic; -use App\Classes\Modules\Accounting\Services\FetchesBankStatementTransaction; -use App\Http\Resources\BankStatementTransactionResource; -use App\Classes\Modules\Accounting\Services\UpdatesBankStatementTransactionOwnerStatus; -use App\Classes\ValueObjects\Constants\ApprovalStatus; -use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType; -use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; -use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus; - +use Illuminate\Http\JsonResponse; +use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\General\Abstracts\AbstractControllerLogic; +use App\Http\Resources\BankStatementTransactionOwnerResource; +use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType; +use App\Classes\Modules\Accounting\Services\FetchesBankStatementTransactionOwner; +use App\Classes\Modules\Accounting\Services\UpdatesBankStatementTransactionOwnerStatus; class UpdateStatementTransactionStatusLogic extends AbstractControllerLogic { @@ -27,29 +25,23 @@ class UpdateStatementTransactionStatusLogic extends AbstractControllerLogic ]; } - /** @var FetchesBankStatementTransaction */ - private $fetchesBankStatementTransaction; + /** @var FetchesBankStatementTransactionOwner */ + private $fetchesBankStatementTransactionOwner; /** @var UpdatesBankStatementTransactionOwnerStatus */ private $updatesBankStatementTransactionOwnerStatus; - /** @var UpdatesTransactionStatus */ - private $updatesTransactionStatus; - /** * UpdateAnnouncementLogic constructor. - * @param FetchesBankStatementTransaction $fetchesBankStatementTransaction + * @param FetchesBankStatementTransactionOwner $fetchesBankStatementTransactionOwner * @param UpdatesBankStatementTransactionOwnerStatus $updatesBankStatementTransactionOwnerStatus - * @param UpdatesTransactionStatus $updatesTransactionStatus */ public function __construct( - FetchesBankStatementTransaction $fetchesBankStatementTransaction, - UpdatesBankStatementTransactionOwnerStatus $updatesBankStatementTransactionOwnerStatus, - UpdatesTransactionStatus $updatesTransactionStatus + FetchesBankStatementTransactionOwner $fetchesBankStatementTransactionOwner, + UpdatesBankStatementTransactionOwnerStatus $updatesBankStatementTransactionOwnerStatus ) { - $this->fetchesBankStatementTransaction = $fetchesBankStatementTransaction; + $this->fetchesBankStatementTransactionOwner = $fetchesBankStatementTransactionOwner; $this->updatesBankStatementTransactionOwnerStatus = $updatesBankStatementTransactionOwnerStatus; - $this->updatesTransactionStatus = $updatesTransactionStatus; } /** @@ -61,21 +53,10 @@ class UpdateStatementTransactionStatusLogic extends AbstractControllerLogic */ public function logic(Request $request): JsonResponse { - $statementTrasaction = $this->fetchesBankStatementTransaction->execute(['id' => $request->route('id')]); - - $statementTrasactionOwner = $statementTrasaction->owners->first(); + $statementTrasactionOwner = $this->fetchesBankStatementTransactionOwner->execute(['id' => $request->route('id')]); $this->updatesBankStatementTransactionOwnerStatus->execute($statementTrasactionOwner, $request->route('status') == 'approve' ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED); - // todo-new: approve payments status, need to check the owner(if system is shipping, need to api with shipping portal) - // if ($request->route('status') == 'approve') { - // if ($statementTrasactionOwner->transaction->type === StatementTransactionOwnerType::SALES) { - // if ($statementTrasactionOwner->owner->status === ApprovalStatus::PENDING_VERIFICATION) { - // $this->updatesTransactionStatus->execute($statementTrasactionOwner->owner, ApprovalStatus::APPROVED); - // } - // } - // } - - return $this->resourceResponse(new BankStatementTransactionResource($statementTrasaction)); + return $this->resourceResponse(new BankStatementTransactionOwnerResource($statementTrasactionOwner)); } } diff --git a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php index ccc70032..6f7efe5e 100644 --- a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php +++ b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php @@ -23,15 +23,12 @@ class CreateBankStatementTransactionOwnersProcessor /** * @return void */ - public function execute() { - - $transactions = StatementTransaction::whereDoesntHave('owners', function($query){ - return $query->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); - })->orderBy('posting_date')->get(); + public function execute($transactions) { // $transactions = StatementTransaction::whereDoesntHave('owners')->where('amount', '<', 0)->get(); foreach ($transactions as $transaction) { + $mapped = false; $keywords = array_filter(explode(" ", $transaction->transaction_description . " " . $transaction->transaction_description_2)); if($transaction->amount > 0){ @@ -40,7 +37,7 @@ class CreateBankStatementTransactionOwnersProcessor $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($creditTransactions as $creditTransaction) { $isArray = is_array($creditTransaction); - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SALES, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, @@ -49,12 +46,11 @@ class CreateBankStatementTransactionOwnersProcessor ]); } - // Shipping Portal Sales - $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), 2, PaymentMethodType::WALLET); + $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), [2], PaymentMethodType::WALLET); foreach ($creditTransactions as $creditTransaction) { if($creditTransaction['owner_type'] === Wallet::class) continue; - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SALES, 'system' => 'SHIPPING_PORTAL', 'owner_type' => $creditTransaction['owner_type'], @@ -67,7 +63,7 @@ class CreateBankStatementTransactionOwnersProcessor $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($creditTransactions as $creditTransaction) { $isArray = is_array($creditTransaction); - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, @@ -76,9 +72,9 @@ class CreateBankStatementTransactionOwnersProcessor ]); } - $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), 5, null); + $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), [5,15], null); foreach ($creditTransactions as $creditTransaction) { - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, 'system' => 'SHIPPING_PORTAL', 'owner_type' => $creditTransaction['owner_type'], @@ -89,7 +85,7 @@ class CreateBankStatementTransactionOwnersProcessor // fpx charge refund if($transaction->transaction_description === 'DUITNOW S/CHRG REFUND'){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::FPX_CHARGE_REFUND ]); } @@ -98,7 +94,7 @@ class CreateBankStatementTransactionOwnersProcessor // INTERNAL_BANK_TRANSFER_IN if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_IN ]); } @@ -123,7 +119,7 @@ class CreateBankStatementTransactionOwnersProcessor ->where('amount', '<=', (($transaction->amount * -1) + 0.01))->whereDate('created_at', '>=', $paymentDateStart)->whereDate('created_at', '<=', $paymentDateEnd)->get(); foreach ($debitTransactions as $debitTransaction) { - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SUPPLIER_PAYMENT, 'system' => 'EXCHANGE', 'owner_type' => Group::class, @@ -139,7 +135,7 @@ class CreateBankStatementTransactionOwnersProcessor $debitTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::DEBIT_NOTE, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($debitTransactions as $debitTransaction) { $isArray = is_array($creditTransaction); - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_WITHDRAWAL, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, @@ -152,50 +148,52 @@ class CreateBankStatementTransactionOwnersProcessor // STATUTORY if(str_contains($transaction->transaction_description_2, 'PEMBANGUNAN SUMBER') || str_contains($transaction->transaction_description_2, 'HASIL') || str_contains($transaction->transaction_description_2, 'PERTUBUHAN KESELAMAT') || str_contains($transaction->transaction_description_2, 'KUMPULAN WANG SIMPAN')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::STATUTORY ]); } // FPX_CHARGE if($transaction->transaction_description === 'DR DUITNOW S/CHRG' || str_contains($transaction->transaction_description, 'Manual FPX') || str_contains($transaction->transaction_description, 'CMS - DR FPX CHG')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::FPX_CHARGE ]); } // BANK_CHARGE if($transaction->transaction_description === 'CMS - DR CORP CHG' || $transaction->transaction_description === 'MONTHLY PROFIT DEBIT'){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::BANK_CHARGE ]); } // CREDIT_CARD_PAYMENT if(str_contains($transaction->transaction_description_2, 'VISA CARD')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::CREDIT_CARD_PAYMENT ]); } // INTERNAL_BANK_TRANSFER_OUT if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE') || str_contains($transaction->transaction_description_2, 'CIEF WORLWIDE') || str_contains($transaction->transaction_description_2, 'IZYIM GLOBAL')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_OUT ]); } // non-operational charges if(str_contains($transaction->transaction_description_2, 'HIRE PURCHASE') || str_contains($transaction->transaction_description_2, 'TENAGA NASIONAL') || str_contains($transaction->transaction_description, 'CABLE CHARGE') || str_contains($transaction->transaction_description_2, 'CTOS DATA SYSTEMS') || str_contains($transaction->transaction_description_2, 'MAXIS')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::NON_OPERATIONAL ]); } } + if (isset($data) && $data->wasRecentlyCreated) $mapped = true; + $this->updateMappedRate($transaction, $mapped); } - } + } - private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $keywords, $model = Transaction::class) { + private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $keywords, $model = Transaction::class) { $dateRange = $this->getDateRange($date, 4); if (App::environment(['production'])) { $query = $model::whereIn('status', $statuses) @@ -322,7 +320,7 @@ class CreateBankStatementTransactionOwnersProcessor try{ $client = new \GuzzleHttp\Client(['verify' => false]); - $response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2]'.$paymentMethodFilter.',"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in":['.$type.']}'); + $response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2]'.$paymentMethodFilter.',"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in":'.json_encode($type).'}'); $body = $response->getBody(); $data = json_decode($body, true); $payload = $data['payload']; @@ -349,4 +347,11 @@ class CreateBankStatementTransactionOwnersProcessor 'end_date' => $nextDay, ]; } + + private function updateMappedRate($transaction, $mapped) { + $statement = $transaction->statement; + $statement->total_rows = StatementTransaction::where('account_statement_id',$transaction->account_statement_id)->count(); + $statement->mapped_rows = $mapped ? $statement->mapped_rows+1 : $statement->mapped_rows; + $statement->save(); + } } diff --git a/app/Classes/Modules/Accounting/Processors/ListShippingPortalTransactions.php b/app/Classes/Modules/Accounting/Processors/ListShippingPortalTransactions.php index f80c3c0e..18ec9c36 100644 --- a/app/Classes/Modules/Accounting/Processors/ListShippingPortalTransactions.php +++ b/app/Classes/Modules/Accounting/Processors/ListShippingPortalTransactions.php @@ -13,6 +13,7 @@ class ListShippingPortalTransactions { try { $url = 'https://izyim.cief-malaysia.com/public/api/v1/transactions/mappable/query/with-details'; + // $url = 'http://127.0.0.1:8001/public/api/v1/transactions/mappable/query/with-details'; $client = new \GuzzleHttp\Client(['verify' => false]); $response = $client->request('GET', $url . '?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters=' . json_encode($filters)); $body = $response->getBody(); diff --git a/app/Classes/Modules/Accounting/Services/FetchesBankStatementTransactionOwner.php b/app/Classes/Modules/Accounting/Services/FetchesBankStatementTransactionOwner.php new file mode 100644 index 00000000..17c620f5 --- /dev/null +++ b/app/Classes/Modules/Accounting/Services/FetchesBankStatementTransactionOwner.php @@ -0,0 +1,31 @@ +repository = $repository; + } + + /** + * @return Builder + */ + public function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} diff --git a/app/Classes/Modules/Accounting/Services/ListTransactionMappingLogs.php b/app/Classes/Modules/Accounting/Services/ListTransactionMappingLogs.php new file mode 100644 index 00000000..fdeff835 --- /dev/null +++ b/app/Classes/Modules/Accounting/Services/ListTransactionMappingLogs.php @@ -0,0 +1,32 @@ +repository = $repository; + } + + + /** + * @return Builder + */ + public function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/ExpireBookingPaymentControllerLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/ExpireBookingPaymentControllerLogic.php new file mode 100644 index 00000000..8ee2bbfa --- /dev/null +++ b/app/Classes/Modules/Bookings/ControllersLogic/ExpireBookingPaymentControllerLogic.php @@ -0,0 +1,57 @@ + 'Expire Payment', + 'message' => 'You have successfully expire the Payment' + ]; + } + + /** @var FetchesBooking */ + private $fetchesBooking; + + /** + * DeletePurchaseOrderPdfLogic constructor. + * @param FetchesBooking $fetchesBooking + */ + public function __construct(fetchesBooking $fetchesBooking) + { + $this->fetchesBooking = $fetchesBooking; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws \App\Classes\Exceptions\MalformedRequestException + */ + public function logic(Request $request) : JsonResponse + { + $booking = $this->fetchesBooking->execute(['id' => $request->route('id')]); + + $payment = $booking->transactions() + ->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]) + ->first(); + + $payment->status = ApprovalStatus::EXPIRED; + $payment->save(); + + return $this->response([]); + } + +} diff --git a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php index 252412a2..5d067fd5 100644 --- a/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php +++ b/app/Classes/Modules/Bookings/ControllersLogic/RegenerateInvoiceBookingLogic.php @@ -9,13 +9,16 @@ 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; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\TransactionType; +use App\Models\Transaction; +use Illuminate\Support\Carbon; class RegenerateInvoiceBookingLogic extends AbstractControllerLogic { @@ -23,7 +26,8 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic /** * @return array */ - protected function notification():array { + protected function notification(): array + { return [ 'title' => 'Regenerate Booking Invoice', 'message' => 'You have successfully regenerate booking invoice' @@ -48,6 +52,9 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic /** @var CreateInvoiceTransactionProcessor */ private $createInvoiceTransactionProcessor; + /** @var CreateInvoiceTransactionWithInvoiceNoProcessor */ + private $createInvoiceTransactionWithInvoiceNoProcessor; + /** * FetchBookingLogic constructor. * @param CanFetchBooking $canFetchBooking @@ -56,6 +63,7 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic * @param UpdatesBookingStatus $updatesBookingStatus * @param DeletesDocument $deletesDocument * @param CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor + * @param CreateInvoiceTransactionWithInvoiceNoProcessor $createInvoiceTransactionWithInvoiceNoProcessor */ public function __construct( CanFetchBooking $canFetchBooking, @@ -63,15 +71,16 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic DeletesTransaction $deletesTransaction, UpdatesBookingStatus $updatesBookingStatus, DeletesDocument $deletesDocument, - CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor - ) - { + CreateInvoiceTransactionProcessor $createInvoiceTransactionProcessor, + CreateInvoiceTransactionWithInvoiceNoProcessor $createInvoiceTransactionWithInvoiceNoProcessor + ) { $this->canFetchBooking = $canFetchBooking; $this->fetchesBooking = $fetchesBooking; $this->deletesTransaction = $deletesTransaction; $this->updatesBookingStatus = $updatesBookingStatus; $this->deletesDocument = $deletesDocument; $this->createInvoiceTransactionProcessor = $createInvoiceTransactionProcessor; + $this->createInvoiceTransactionWithInvoiceNoProcessor = $createInvoiceTransactionWithInvoiceNoProcessor; } @@ -82,18 +91,45 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic * @throws \App\Classes\Exceptions\MalformedRequestException * @throws \App\Classes\Exceptions\RequestValidationException */ - public function logic(Request $request) : JsonResponse + public function logic(Request $request): JsonResponse { $this->canFetchBooking->passes(); - $booking = $this->fetchesBooking->execute([ - 'id' => $request->route('id'), - 'status' => ApprovalStatus::COMPLETED, - 'with_transactions' => true] + $booking = $this->fetchesBooking->execute( + [ + 'id' => $request->route('id'), + 'status' => ApprovalStatus::COMPLETED, + 'with_transactions' => true + ] ); $this->updatesBookingStatus->execute($booking, ApprovalStatus::APPROVED); + $firstInvoice = $booking->transactions() + ->whereIn('type', [TransactionType::INVOICE]) + ->withTrashed() + ->orderBy('created_at', 'asc') + ->first(); + + // get the first bill_no + $firstBillNo = $firstInvoice->bill_no; + if (strpos($firstBillNo, '-deleted') !== false) { + $firstBillNo = substr($firstBillNo, 0, strpos($firstBillNo, '-deleted')); + } + + // 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(); + + $transactionWithSameBillNo = Transaction::where('bill_no', $firstBillNo)->withTrashed()->get(); + if ($transactionWithSameBillNo) { + foreach ($transactionWithSameBillNo as $transaction) { + $transaction->bill_no = $transaction->bill_no . "-deleted-" . Str::random(10); + $transaction->save(); + } + } + $transaction = $booking->transactions()->whereIn('type', [TransactionType::INVOICE, TransactionType::SUPPLIER_DELIVER])->get(); foreach ($transaction as $key => $row) { $this->deletesTransaction->execute($row); @@ -104,9 +140,8 @@ class RegenerateInvoiceBookingLogic extends AbstractControllerLogic $this->deletesDocument->execute($row); } - $this->createInvoiceTransactionProcessor->execute($booking); + $this->createInvoiceTransactionWithInvoiceNoProcessor->execute($booking, $firstBillNo); return $this->resourceResponse(new BookingResource($booking)); } - } diff --git a/app/Classes/Modules/Companies/ControllersLogic/BulkDownloadCustomerInvoicesLogic.php b/app/Classes/Modules/Companies/ControllersLogic/BulkDownloadCustomerInvoicesLogic.php new file mode 100644 index 00000000..41a64ecf --- /dev/null +++ b/app/Classes/Modules/Companies/ControllersLogic/BulkDownloadCustomerInvoicesLogic.php @@ -0,0 +1,94 @@ +input('marking'))->first(); + + if (!$company) { + return response()->json([ + 'status' => 'Failed', + 'message' => 'Customer not found.', + ]); + } + + $startDate = Carbon::createFromFormat('d-m-Y', $request->input('startDate'))->startOfDay(); + $endDate = Carbon::createFromFormat('d-m-Y', $request->input('endDate'))->endOfDay(); + + $invoicebookings = $company->bookings() + ->whereDate('created_at', '>=', $startDate) + ->whereDate('created_at', '<=', $endDate) + ->whereHas('transactions', function ($query) { + $query->where('transactions.type', TransactionType::INVOICE) + ->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + }) + ->orderBy('created_at') + ->get(); + + if ($invoicebookings->isEmpty()) { + return response()->json([ + 'status' => 'Failed', + 'message' => 'No invoices found for this customer in the given date range.', + ]); + } + + $zipDirectory = storage_path('app/bulk_invoice'); // Update this with the actual directory path + + if (!file_exists($zipDirectory)) { + mkdir($zipDirectory, 0755, true); + } + + $zip_file = "{$zipDirectory}/invoices_{$request->input('startDate')}_to_{$request->input('endDate')}_{$company->reference}.zip"; + + $zip = new ZipArchive(); + if ($zip->open($zip_file, ZipArchive::CREATE | ZipArchive::OVERWRITE)) { + foreach ($invoicebookings as $booking) { + $invoice_file = $booking->documents()->where('document_type', DocumentType::INVOICE)->whereNull('deleted_at')->first()->files()->first(); + $zip->addFile(Storage::disk('documents')->path($invoice_file->file->file_info->original->file), 'invoice-' . $booking->created_at->format('d_m_Y') . '_' . $booking->marking . '.pdf'); + } + + $zip->close(); + + while (ob_get_level()) { + ob_end_clean(); + } + + return response()->download($zip_file); + } else { + return response()->json([ + 'status' => 'Error', + 'message' => 'Failed to create the Zip archive.', + ]); + } + } catch (\Exception $e) { + // Log the exception for debugging + Log::error('Error in BulkDownloadCustomerInvoicesLogic: ' . $e->getMessage()); + + return response()->json([ + 'status' => 'Error', + 'message' => 'An error occurred while processing the request.', + ]); + } + } +} diff --git a/app/Classes/Modules/Companies/ControllersLogic/BulkDownloadSupplierWhiteFormsLogic.php b/app/Classes/Modules/Companies/ControllersLogic/BulkDownloadSupplierWhiteFormsLogic.php new file mode 100644 index 00000000..87f0ad83 --- /dev/null +++ b/app/Classes/Modules/Companies/ControllersLogic/BulkDownloadSupplierWhiteFormsLogic.php @@ -0,0 +1,78 @@ +input('startDate'))->startOfDay(); + $endDate = Carbon::createFromFormat('d-m-Y', $request->input('endDate'))->endOfDay(); + + $companyReference = Company::find($request->input('supplier'))->reference; + $groups = Group::where('issuer', $request->input('supplier')) + ->whereDate('created_at', '>=', $startDate) + ->whereDate('created_at', '<=', $endDate) + ->orderBy('created_at', 'DESC') + ->get(); + + if (count($groups) > 0) { + + $zipDirectory = storage_path('app/bulk_whiteform'); // Update this with the actual directory path + + if (!file_exists($zipDirectory)) { + mkdir($zipDirectory, 0755, true); + } + + $zip_file = "{$zipDirectory}/currency_vendor_orders_{$request->input('startDate')}_to_{$request->input('endDate')}_{$companyReference}.zip"; + + $zip = new ZipArchive(); + if ($zip->open($zip_file, ZIPARCHIVE::CREATE | ZipArchive::OVERWRITE)) { + foreach($groups as $group) { + $document = $group->documents()->where('document_type', DocumentType::CURRENCY_VENDOR_ORDER)->whereNull('deleted_at')->first()->files()->first(); + $created_at = $group->created_at->format('Y-m-d'); + $zip->addFile(Storage::disk('documents')->path($document->file->file_info->original->file), $created_at . "_" . $group->amount . "_" . $group->reference . '.pdf'); + } + + $zip->close(); + while (ob_get_level()) { + ob_end_clean(); + } + + return response()->download($zip_file); + } + } + + return response()->json([ + 'status' => 'Failed', + 'message' => 'No white form found for this supplier in the given date range.', + ]); + + } catch (\Exception $e) { + // Log the exception for debugging + Log::error('Error in BulkDownloadSupplierWhiteFormsLogic: ' . $e->getMessage()); + + return response()->json([ + 'status' => 'Error', + 'message' => 'An error occurred while processing the request.', + ]); + } + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php b/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php new file mode 100644 index 00000000..ead22543 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php @@ -0,0 +1,79 @@ +dateTime = $request->input('date').' '.$request->input('time'); + $this->count = 0; + } + + public function headings(): array + { + return [ + 'No', + 'Doc No', + 'Date', + 'Debtor Code', + 'Debtor Name', + 'Shipping Info', + 'Net Total', + 'Cancelled', + 'Mapped Status', + 'Mapped Reference No', + 'MapPayment Received Date' + ]; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + return TransactionMappingLog::where('imported_date', $this->dateTime); + } + + /** + * @param Transaction $transaction + * + * @return array + */ + public function map($transaction): array + { + $this->count += 1; + $data = $transaction->data; + return [ + $this->count, + Arr::get($data,'doc_no'), + Arr::get($data,'date'), + Arr::get($data,'debtor_code'), + Arr::get($data,'debtor_name'), + Arr::get($data,'shipping_info'), + Arr::get($data,'net_total'), + Arr::get($data,'cancelled'), + Arr::get($data,'mapped_status'), + Arr::get($data,'mapped_result_reference'), + Arr::get($data,'payment_received_date'), + ]; + + } +} diff --git a/app/Classes/Modules/Exports/Services/ExportsImportedReceiptMappeds.php b/app/Classes/Modules/Exports/Services/ExportsImportedReceiptMappeds.php new file mode 100644 index 00000000..efe95fd3 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsImportedReceiptMappeds.php @@ -0,0 +1,86 @@ +dateTime = $request->input('date').' '.$request->input('time'); + $this->count = 0; + } + + public function headings(): array + { + return [ + 'Check', + 'Doc No', + 'Doc Date', + 'Debtor Code', + 'Company Name', + 'Description', + 'Payment Amount', + 'Created User', + 'Curr.', + 'To Home Rate', + 'Local Payment Amount', + 'Cancelled', + 'Mapped Status', + 'Mapped Reference No', + ]; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + return TransactionMappingLog::where('imported_date', $this->dateTime); + } + + /** + * @param Transaction $transaction + * + * @return array + */ + public function map($transaction): array + { + $this->count += 1; + $data = $transaction->data; + return [ + $this->count, + Arr::get($data,'doc_no'), + Arr::get($data,'doc_date'), + Arr::get($data,'debtor_code'), + Arr::get($data,'company_name'), + Arr::get($data,'description'), + Arr::get($data,'payment_amount'), + Arr::get($data,'created_user'), + Arr::get($data,'curr'), + Arr::get($data,'to_home_rate'), + Arr::get($data,'local_payment_amount'), + Arr::get($data,'cancelled'), + Arr::get($data,'2nd_doc_no'), + Arr::get($data,'mapped_status'), + Arr::get($data,'mapped_result_reference'), + ]; + + } +} diff --git a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php index 90780750..62a2c13e 100644 --- a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php +++ b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php @@ -4,7 +4,6 @@ namespace App\Classes\Modules\Exports\Services; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType; -use App\Models\StatementTransactionOwner; use App\Models\Transaction; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\FromQuery; @@ -18,6 +17,8 @@ use App\Classes\Modules\Accounting\Processors\ListShippingPortalTransactions; use App\Classes\ValueObjects\Constants\ShippingTransactionType; use App\Classes\ValueObjects\Constants\TransactionType; use Illuminate\Support\Facades\Log; +use App\Classes\General\Eloquent\ApplyFiltersToQuery; +use App\Models\StatementTransaction; class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize { @@ -33,7 +34,7 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading public function headings(): array { - return [ + $header = [ 'DocNo', 'DocDate', 'DebtorCode', @@ -49,6 +50,7 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading 'AccNo', 'DeptNo' ]; + return $header; } /** @@ -56,9 +58,10 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading */ public function query() { - return StatementTransactionOwner::whereNull('invoice_reference') - ->whereIn('type', [StatementTransactionOwnerType::SALES, StatementTransactionOwnerType::WALLET_TOP_UP]) - ->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED]); + $data = (new ApplyFiltersToQuery())->execute(StatementTransaction::query(), json_decode($this->request->input('filter'), true)); + if ($this->request->has('bankStatementTransactionId')) $data = $data->whereIn('id',json_decode($this->request->input('bankStatementTransactionId'), true)); + + return $data; } /** @@ -68,11 +71,12 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading */ public function map($transaction): array { + $statementTransactionOwner = $transaction->owners()->whereIn('status', [ApprovalStatus::APPROVED])->first(); $logArray = [ 'counter' => $this->counter, - 'system' => $transaction->system, - 'StatementTransactionOwner_id' => $transaction->id, - 'transaction_table_id' => $transaction->owner_id, + 'system' => $statementTransactionOwner->system, + 'StatementTransactionOwner_id' => $statementTransactionOwner->id, + 'transaction_table_id' => $statementTransactionOwner->owner_id, ]; $this->counter += 1; $logArray = json_encode($logArray); @@ -82,8 +86,8 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' ' . $logArray . PHP_EOL; file_put_contents($filePath, $textToAppend, FILE_APPEND); - if ($transaction->system == 'EXCHANGE') { - $row = (App()->make($transaction->owner_type))->where('id', $transaction->owner_id)->first(); + if ($statementTransactionOwner->system == 'EXCHANGE') { + $row = (App()->make($statementTransactionOwner->owner_type))->where('id', $statementTransactionOwner->owner_id)->first(); $company = $row->type === TransactionType::PAYMENT ? $row->owner->company : $row->owner->owner; $booking = $row->owner; @@ -104,46 +108,61 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading '500-0000', 'CIEF' ]; - } else { + } elseif ($statementTransactionOwner->owner_id) { $row = (App()->make(ListShippingPortalTransactions::class))->execute([ - 'id' => $transaction->owner_id, + 'id' => $statementTransactionOwner->owner_id, 'with_company' => true, ]); - if (empty($row) || $row[0]['status'] != 'success') { + if (!empty($row) && $row[0]['status'] != 'success') { $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' Fetch Shipping Transaction Fail ' . json_encode([ - 'id' => $transaction->owner_id, + 'id' => $statementTransactionOwner->owner_id, 'with_company' => true, - 'StatementTransactionOwner_id' => $transaction->id, + 'StatementTransactionOwner_id' => $statementTransactionOwner->id, ]) . PHP_EOL; file_put_contents($errorFilePath, $textToAppend, FILE_APPEND); $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' Shipping Portal Respnose ' . json_encode($row) . PHP_EOL; file_put_contents($errorFilePath, $textToAppend, FILE_APPEND); - Log::info('Error in Exports Invoice Transactions ' . $this->counter); + return [ + '<>', + Carbon::parse($row['created_at'])->format('m/d/Y H:m'), + $row['debtor_code'], + $row['type'] === ShippingTransactionType::PAYMENT ? $row['order_reference'] : $row['marking'], + '', + 'MYR', + $row['type'] === ShippingTransactionType::PAYMENT ? $row['order_reference'] : $row['bill_no'], + $row['type'] === ShippingTransactionType::PAYMENT ? '' : 'W1', + $row['type'] === ShippingTransactionType::PAYMENT ? 'PLEASE REFER TO THE ATTACHED APPENDIX REF `' . $row['order_reference'] : 'CREDIT SALES', + '', + 1, + round($row['amount'], 2), + '500-0000', + 'CIEF' + ]; - return []; } - - $row = $row[0]; - - return [ - '<>', - Carbon::parse($row['updated_at'])->format('m/d/Y H:m'), - $row['debtor_code'], - $row['type'] === ShippingTransactionType::PAYMENT ? $row['order_reference'] : $row['marking'], - '', - 'MYR', - $row['type'] === ShippingTransactionType::PAYMENT ? $row['order_reference'] : $row['bill_no'], - $row['type'] === ShippingTransactionType::PAYMENT ? '' : 'W1', - $row['type'] === ShippingTransactionType::PAYMENT ? 'PLEASE REFER TO THE ATTACHED APPENDIX REF `' . $row['order_reference'] : 'CREDIT SALES', - '', - 1, - round($row['amount'], 2), - '500-0000', - 'CIEF' - ]; } + + return [ + 'Transaction Not Found', + $transaction->posting_date->format('m/d/Y H:m'), + $transaction->transaction_description.' - '.$transaction->transaction_description_2, + $statementTransactionOwner->system, + '', + '', + '', + '', + '', + '', + 0, + $transaction->amount, + '', + '', + '', + '' + ]; } + } diff --git a/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php b/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php new file mode 100644 index 00000000..bde46225 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php @@ -0,0 +1,199 @@ +request = $request; + } + + public function startCell(): string + { + return 'A2'; + } + + public function registerEvents(): array { + + return [ + AfterSheet::class => function(AfterSheet $event) { + $sheet = $event->sheet; + + $sheet->mergeCells('A1:A1'); + $sheet->setCellValue('A1', '"'); + + $sheet->mergeCells('M1:Y1'); + $sheet->setCellValue('M1', "Payment Detail Column"); + + $sheet->mergeCells('Z1:AB1'); + $sheet->setCellValue('Z1', "Knock Off Detail"); + + $styleArray = [ + 'alignment' => [ + 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, + ], + ]; + + $cellRange = 'A1:AB1'; + $event->sheet->getDelegate()->getStyle($cellRange)->applyFromArray($styleArray); + }, + ]; + } + + public function headings(): array + { + $header = [ + [ + ' ', + '(20 chars)', + '(Date: dd/MM/yyyy)', + '(12 chars)', + '(40 chars)', + '(25 chars)', + '(10 chars)', + '(10 chars)', + '(5 chars)', + '(Number, use System Currency Rate Decimal)', + '(Number, use System Currency Rate Decimal)', + '(Rich Text)', + '(20 chars)', + '(20 chars)', + '(Number, use System Currency Decimal)', + '(Number, use System Currency Decimal)', + '(Number, use System Currency Rate Decimal)', + '(14 chars)', + '(30 chars)', + '(10 chars)', + '(10 chars)', + '(20 chars)', + '(Integer)', + '(Boolean. Indicate T for stock control or F for non stock control)', + '(Returned Cheque Date: dd/MM/yyyy)', + '(2 chars, RI for Invoice, RD for D/N)', + '', + '(Number, use System Currency Decimal)', + ], + [ + 'DocNo', + 'DocDate', + 'DebtorCode', + 'Description', + 'DocNo2', + 'ProjNo', + 'DeptNo', + 'CurrencyCode', + 'ToHomeRate', + 'ToDebtorRate', + 'Note', + 'PaymentMethod', + 'ChequeNo', + 'PaymentAmt', + 'BankCharge', + 'ToBankRate', + 'BankChargeTaxType', + 'BankChargeTaxRefNo', + 'BankChargeProjNo', + 'BankChargeDeptNo', + 'PaymentBy', + 'FloatDay', + 'IsRCHQ', + 'RCHQDate', + 'KnockOffDocType', + 'KnockOffDocNo', + 'KnockOffAmt', + '', + ] + ]; + return $header; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + $data = (new ApplyFiltersToQuery())->execute(StatementTransaction::query(), json_decode($this->request->input('filter'), true)); + if ($this->request->has('bankStatementTransactionId')) $data = $data->whereIn('id',json_decode($this->request->input('bankStatementTransactionId'), true)); + + return $data; + } + + /** + * @param StatementTransaction $transaction + * + * @return array + */ + public function map($transaction): array + { + $statementTransactionOwner = $transaction->owners()->whereIn('status', [ApprovalStatus::APPROVED])->first(); + $logArray = [ + 'counter' => $this->counter, + 'system' => $statementTransactionOwner->system, + 'StatementTransactionOwner_id' => $statementTransactionOwner->id, + 'transaction_table_id' => $statementTransactionOwner->owner_id, + ]; + $this->counter += 1; + $logArray = json_encode($logArray); + + $filePath = storage_path('logs/exports_receipt_transactions.log'); + $errorFilePath = storage_path('logs/exports_receipt_transactions_error.log'); + $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' ' . $logArray . PHP_EOL; + file_put_contents($filePath, $textToAppend, FILE_APPEND); + + $company = Company::where('name',$transaction->transaction_description_2)->first(); + + return [ + '<>', + Carbon::parse($transaction->posting_date)->format('d/m/Y'), + ($company ? $company->debtor : null), + 'Payment for '.$transaction->transaction_description, + '', + '', + '', + 'MYR', + 1, + 1, + '', + 'MBB', + '', + $transaction->amount, + '', + 1, + '', + '', + '', + '', + '', + '0', + '', + '', + 'RI', + $transaction->transaction_ref, + $transaction->amount, + '', + ]; + } +} 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/Classes/Modules/Transactions/ControllersLogic/ListWalletTransactionsLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/ListWalletTransactionsLogic.php index 0b70b484..649b3309 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/ListWalletTransactionsLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/ListWalletTransactionsLogic.php @@ -44,7 +44,19 @@ class ListWalletTransactionsLogic extends AbstractControllerLogic $query = $this->listsTransactions->execute($this->listsTransactions->deserializeFilters($request->input('filters'))); if (str_contains($request->input('filters'), "owner_id") && $query->count() > 0) { - $currentWalletBalance = Wallet::find($query->first()->owner_id)->amount; + $wallet_total_incoming = Transaction::where('owner_type', $query->first()->owner_type) + ->where('owner_id', $query->first()->owner_id) + ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]) + ->whereIn('type', [TransactionType::TOP_UP, TransactionType::CREDIT_NOTE]) + ->sum('amount'); + + $wallet_total_outgoing = Transaction::where('owner_type', $query->first()->owner_type) + ->where('owner_id', $query->first()->owner_id) + ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]) + ->whereIn('type', [TransactionType::PAYMENT, TransactionType::DEBIT_NOTE]) + ->sum('amount'); + + $currentWalletBalance = $wallet_total_incoming - $wallet_total_outgoing; $incoming = Transaction::where('owner_type', $query->first()->owner_type) ->where('owner_id', $query->first()->owner_id) ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]) diff --git a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessorWithInvoiceNo.php b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionWithInvoiceNoProcessor.php similarity index 99% rename from app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessorWithInvoiceNo.php rename to app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionWithInvoiceNoProcessor.php index 27dfbe59..612033f8 100644 --- a/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionProcessorWithInvoiceNo.php +++ b/app/Classes/Modules/Transactions/Processors/CreateInvoiceTransactionWithInvoiceNoProcessor.php @@ -21,7 +21,7 @@ use App\Classes\ValueObjects\Constants\DocumentType; use App\Models\Booking; use App\Models\SegmentConstant; -class CreateInvoiceTransactionProcessorWithInvoiceNo +class CreateInvoiceTransactionWithInvoiceNoProcessor { /** @var CreatesTransaction */ diff --git a/app/Classes/Modules/Transactions/Services/GeneratesTransactionBillNumber.php b/app/Classes/Modules/Transactions/Services/GeneratesTransactionBillNumber.php index 57b68277..6a49c941 100644 --- a/app/Classes/Modules/Transactions/Services/GeneratesTransactionBillNumber.php +++ b/app/Classes/Modules/Transactions/Services/GeneratesTransactionBillNumber.php @@ -35,7 +35,7 @@ class GeneratesTransactionBillNumber $attempt = 0; while ($attempt < 10) { // Retry up to 10 times // $billNumber = $prefix . $date->format('Y') . $date->format('m') . '-' . intval(microtime(true)); - $billNumber = $prefix . $date->format('Y') . $date->format('m') . '-' . mt_rand(1000000000, 9999999999); + $billNumber = $prefix . $date->format('Y') . $date->format('m') . '-' . mt_rand(1000000, 9999999); if (!$this->checksIfTransactionBillNumberExists->execute($billNumber)) { return $billNumber; } 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/Console/Commands/DeleteBulkInvoiceFiles.php b/app/Console/Commands/DeleteBulkInvoiceFiles.php new file mode 100644 index 00000000..a6e8dab1 --- /dev/null +++ b/app/Console/Commands/DeleteBulkInvoiceFiles.php @@ -0,0 +1,44 @@ +info(Carbon::now() . ' Start cleaning - ' . $directory); + + if (File::isDirectory($directory)) { + File::cleanDirectory($directory); + $this->info('All files have been deleted.'); + } else { + $this->info('Directory does not exist.'); + } + + $end = new Carbon(); + $elapsedTime = $start->diff($end)->format('%H:%I:%S'); + + $this->info(Carbon::now() . ' Process ended. ElapsedTime: ' . $elapsedTime); + } + } +} diff --git a/app/Console/Kernel.php b/app/Console/Kernel.php index cb9cf060..d6557046 100644 --- a/app/Console/Kernel.php +++ b/app/Console/Kernel.php @@ -38,10 +38,10 @@ class Kernel extends ConsoleKernel ->dailyAt('01:00') ->appendOutputTo(storage_path().'/logs/soft-delete-seasonal-segmant-company.log') ->withoutOverlapping(); - - $schedule->command('regenerateInvoice') - ->everyMinute() - ->appendOutputTo(storage_path().'/logs/regenerateInvoice.log') + + $schedule->command('delete:bulk-download-files') + ->hourly() + ->appendOutputTo(storage_path().'/logs/delete-bulk-download-files.log') ->withoutOverlapping(); } diff --git a/app/Http/Controllers/Accounting/BankStatementController.php b/app/Http/Controllers/Accounting/BankStatementController.php index ff1324b4..ac631ece 100644 --- a/app/Http/Controllers/Accounting/BankStatementController.php +++ b/app/Http/Controllers/Accounting/BankStatementController.php @@ -22,6 +22,7 @@ use App\Http\Controllers\Controller; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use DateTime; +use App\Models\StatementTransaction; class BankStatementController extends Controller { @@ -88,7 +89,9 @@ class BankStatementController extends Controller public function rerun() { - CreateBankStatementTransactionOwners::dispatch(); + foreach (StatementTransaction::doesntMapStatement()->get()->chunk(30) as $key => $transaction) { + CreateBankStatementTransactionOwners::dispatch($transaction); + } return redirect()->back()->with('success', 'Rerun triggered successfully'); } @@ -129,7 +132,7 @@ class BankStatementController extends Controller ->download($statement->date_from->format('Y-m-d') . '_' . $statement->date_to->format('Y-m-d') . '_statement.csv'); } - public function fetch(Request $request, ListBankStatementDetailsLogic $logic): JsonResponse + public function fetch(Request $request, ListBankStatementTransactionsLogic $logic): JsonResponse { return $logic->execute($request); } diff --git a/app/Http/Controllers/Accounting/HistoryImportedTransactionMappedController.php b/app/Http/Controllers/Accounting/HistoryImportedTransactionMappedController.php new file mode 100644 index 00000000..8b4a2cde --- /dev/null +++ b/app/Http/Controllers/Accounting/HistoryImportedTransactionMappedController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Bookings/ExpireBookingPaymentController.php b/app/Http/Controllers/Bookings/ExpireBookingPaymentController.php new file mode 100644 index 00000000..f09fa38a --- /dev/null +++ b/app/Http/Controllers/Bookings/ExpireBookingPaymentController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Companies/BulkDownloadCustomerInvoicesController.php b/app/Http/Controllers/Companies/BulkDownloadCustomerInvoicesController.php new file mode 100644 index 00000000..4d6944d4 --- /dev/null +++ b/app/Http/Controllers/Companies/BulkDownloadCustomerInvoicesController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Companies/BulkDownloadSupplierWhiteFormsController.php b/app/Http/Controllers/Companies/BulkDownloadSupplierWhiteFormsController.php new file mode 100644 index 00000000..21984e5f --- /dev/null +++ b/app/Http/Controllers/Companies/BulkDownloadSupplierWhiteFormsController.php @@ -0,0 +1,20 @@ +execute($request); + } + +} \ No newline at end of file diff --git a/app/Http/Controllers/Exports/ExportCustomersToExcelController.php b/app/Http/Controllers/Exports/ExportCustomersToExcelController.php index 74384157..0f351c7d 100644 --- a/app/Http/Controllers/Exports/ExportCustomersToExcelController.php +++ b/app/Http/Controllers/Exports/ExportCustomersToExcelController.php @@ -15,6 +15,10 @@ use App\Models\User; use Illuminate\Http\Request; use Illuminate\Support\Facades\Auth; use Maatwebsite\Excel\Excel; +use App\Classes\Modules\Exports\Services\ExportsImportedInvoiceMappeds; +use App\Models\TransactionMappingLog; +use App\Classes\Modules\Exports\Services\ExportsReceiptTransactions; +use App\Classes\Modules\Exports\Services\ExportsImportedReceiptMappeds; class ExportCustomersToExcelController { @@ -64,6 +68,13 @@ class ExportCustomersToExcelController return $response; } + public function receiptTransactions(Request $request){ + $exportsTransactions = new ExportsReceiptTransactions($request); + $response = $exportsTransactions->download('receipt-transactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + ob_end_clean(); + return $response; + } + public function bookingTransactions(ExportsBookingTransactions $exportsBookingTransactions, Request $request){ $response = $exportsBookingTransactions->download('bookingTransactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); ob_end_clean(); @@ -75,4 +86,16 @@ class ExportCustomersToExcelController ob_end_clean(); return $response; } + + public function importedInvoiceMapped(ExportsImportedInvoiceMappeds $exportsImportedInvoiceMappeds, Request $request) { + $response = $exportsImportedInvoiceMappeds->download($request->input('fileName').'.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + ob_end_clean(); + return $response; + } + + public function importedReceiptMapped(ExportsImportedReceiptMappeds $exportsImportedReceiptMappeds, Request $request) { + $response = $exportsImportedReceiptMappeds->download($request->input('fileName').'.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + ob_end_clean(); + return $response; + } } \ No newline at end of file diff --git a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php index a59f9463..e4c35eb5 100644 --- a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php +++ b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php @@ -2,94 +2,194 @@ namespace App\Http\Controllers\Imports; -use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; -use App\Classes\Modules\Imports\Services\GenericImport; -use App\Classes\Modules\Segments\DataTransferObjects\SeasonalSegmentObject; -use App\Classes\ValueObjects\Constants\ApprovalStatus; -use App\Models\Segment; -use App\Models\User; -use Carbon\Carbon; use DateTime; +use Carbon\Carbon; +use App\Models\User; +use App\Models\Company; +use App\Models\Segment; +use App\Models\Transaction; use Illuminate\Http\Request; +use App\Models\SeasonalSegment; +use Illuminate\Http\JsonResponse; +use Illuminate\Support\Facades\DB; use Maatwebsite\Excel\Facades\Excel; +use App\Models\TransactionMappingLog; +use App\Classes\ValueObjects\Constants\HttpStatus; +use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\Modules\Imports\Services\GenericImport; +use App\Classes\ValueObjects\Response\ApiResponseObject; +use App\Classes\Modules\Accounting\Processors\ChecksBillNumber; use App\Classes\Modules\Segments\Services\CreatesSeasonalSegment; use App\Classes\Modules\Companies\Processors\AssignSegmentProcessor; -use App\Models\Company; -use App\Models\SeasonalSegment; -use App\Models\Transaction; +use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; +use App\Classes\Modules\Segments\DataTransferObjects\SeasonalSegmentObject; class ImportStatementInvoiceController { + private $responseTitle; + private $responseMessage; + + public function __construct() { + $this->responseTitle = 'Import Invoice Mapping'; + $this->responseMessage = 'You have successfully imported invoice mapping'; + } + + public function mapping($row) { + // Shipping Info + // TOPUP -> map with transaction.bill_no + if (str_starts_with($row['shipping_info'], 'TOPUP')) { + // find in exchange first, if cannont then find in izyim + foreach (['exchange','izyim'] as $system) { + [$returnReference, $transactionDate] = $this->mappingTopUp($row, $system); + if ($returnReference) { + // $row['mapped_result_reference'] = $data['owner_reference']; + // $row['payment_received_date'] = date('Y-m-d', strtotime($data['created_at'])); + $row['mapped_result_reference'] = $returnReference; + $row['payment_received_date'] = $transactionDate ? date('d-m-Y', strtotime($transactionDate)) : null; + $row['mapped_status'] = 'success'; + return $row; + } + } + } + + [$returnReference, $transactionDate] = $this->mappingExchange($row); + if ($returnReference) { + $row['mapped_result_reference'] = $returnReference; + $row['payment_received_date'] = date('d-m-Y', strtotime($transactionDate)); + $row['mapped_status'] = 'success'; + return $row; + } + + // if still unable to map, will try to check the shipping_info without TOPUP + // foreach (['exchange','izyim'] as $system) { + // $returnReference = $this->mappingTopUp($row, $system); + // if ($returnReference) { + // $row['mapped_result_reference'] = $returnReference; + // $row['mapped_status'] = 'success'; + // } + // } + + return $row; + } + /** * @param Request $request * @return array - * @throws \App\Classes\Exceptions\MalformedRequestException */ - public function import(Request $request) + public function import(Request $request) : JsonResponse { - ini_set('memory_limit', '-1'); + try { + ini_set('memory_limit', '-1'); + $importDate = date('Y-m-d H:i:s'); + $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); + $file = json_decode($object->getFiles()[0])->file_info->original->file; - $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); - $file = json_decode($object->getFiles()[0])->file_info->original->file; + $import = new GenericImport(); + Excel::import($import, $file); + $excelRows = $import->rows; + $excelRows = $excelRows->toArray(); - $import = new GenericImport(); - Excel::import($import, $file); - $excelRows = $import->rows; - $excelRows = $excelRows->toArray(); + $data = []; + foreach ($excelRows as $row) { + $row['mapped_result_reference'] = null; + $row['payment_received_date'] = null; + $row['mapped_status'] = 'failed'; + $row['date'] = in_array(gettype($row['date']), ['integer', 'double']) ? $this->changeExcelDate($row['date']) : date('Y-m-d', strtotime($row['date'])); + + $row = $this->mapping($row); + + TransactionMappingLog::create([ + 'imported_date'=>$importDate, + 'type' => 'invoices', + 'data'=>$row, + ]); + array_push($data, $row); + + + // if 5 digits -> exchange booking reference + // find transation + // find statement_transaction_owners, and fill up the details + + // if <5 digits, find the transaction id (order number in izyim), find the payment in izyim + // find transation + // find statement_transaction_owners, and fill up the details + + // dd([ + // 'type' => $statementTransactionOwnerType, + // 'system' => $system, + // // 'owner_type' => Transaction::class, + // // todo-new: make sure owner_type is a class + // 'owner_type' => $owner_type, + // 'owner_id' => $owner_id, + // 'owner_reference' => $owner_reference + // ]); + + // $bankStatementTransaction->owners()->firstOrCreate([ + // 'type' => $statementTransactionOwnerType, + // 'system' => $system, + // // 'owner_type' => Transaction::class, + // // todo-new: make sure owner_type is a class + // 'owner_type' => $owner_type, + // 'owner_id' => $owner_id, + // 'owner_reference' => $owner_reference + // ]); - foreach ($excelRows as $row) { - dd($row); - // $row['debtor_code'] - - // attempt 1 - try map by amount and date - // $transactionDate = $this->changeExcelDate($row['date']); - // $transaction = Transaction::where('original_amount', $row['total'])->whereDate('created_at', $transactionDate)->get(); - // if ($transaction) { - // // check company - // // $company = Company::where('debtor', $row['debtor_code'])->first(); - // // dd($company); - // // try to verify is it the correct transaction - // } - // Shipping Info - // TOPUP -> map with transaction.bill_no - if (str_starts_with($row['shipping_info'], 'TOPUP')) { - // find in exchange first, if cannont then find in izyim - // (App()->make(ChecksBillNumber::class))->execute($bill_no, 'exchange'); } - - // if 5 digits -> exchange booking reference - // find transation - // find statement_transaction_owners, and fill up the details - - // if <5 digits, find the transaction id (order number in izyim), find the payment in izyim - // find transation - // find statement_transaction_owners, and fill up the details - - // dd([ - // 'type' => $statementTransactionOwnerType, - // 'system' => $system, - // // 'owner_type' => Transaction::class, - // // todo-new: make sure owner_type is a class - // 'owner_type' => $owner_type, - // 'owner_id' => $owner_id, - // 'owner_reference' => $owner_reference - // ]); - - // $bankStatementTransaction->owners()->firstOrCreate([ - // 'type' => $statementTransactionOwnerType, - // 'system' => $system, - // // 'owner_type' => Transaction::class, - // // todo-new: make sure owner_type is a class - // 'owner_type' => $owner_type, - // 'owner_id' => $owner_id, - // 'owner_reference' => $owner_reference - // ]); - + return $this->response($this->responseTitle, $this->responseMessage, HttpStatus::OK_WITH_MESSAGE, ['data'=>$data,'importedDate'=>$importDate]); + } catch (\Exception $exception){ + return $this->response('import invoice failed',$exception->getMessage(), ($exception->getCode()? $exception->getCode() : HttpStatus::SERVER_ERROR)); } } + public function response(String $responseTitle, String $responseMessage, int $httpStatus, ?array $data = []) : JsonResponse { + return (new ApiResponseObject($responseTitle, $responseMessage, $httpStatus, $data))->handler(); + } + + private function mappingTopUp(Array $row, String $system) { + try { + if ($data = (App()->make(ChecksBillNumber::class))->execute($row['shipping_info'], $system)) { + // if ($system == 'izyim' && isset($data['owner_reference'])) return $data; + if ($system == 'izyim' && isset($data['owner_reference'])) return [$data['owner_reference'], null]; + + if ($system == 'exchange') return $this->updateTransactionOwnerReference($data, $row['doc_no']); + } + } catch (\Throwable $th) { + return false; + } + } + + private function mappingExchange(Array $row) { + $date = $row['date']; + $transaction = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where('owner_reference', $row['shipping_info'])->first(); + + if ($transaction && $transaction->count() == 0) { + $transaction = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where('statement_transactions.amount', $row['net_total'])->whereRaw("DATE(posting_date) = '$date'")->first(); + } + + if ($transaction && $transaction->count() == 0) { + $transaction = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where(DB::raw('FLOOR(statement_transactions.amount)'), floor($row['net_total']))->whereRaw("DATE(posting_date) = '$date'")->first(); + } + + if ($transaction && $transaction->count() > 0) { + return $this->updateTransactionOwnerReference($transaction, $row['doc_no']); + } + return [false, false]; + } + + public function updateTransactionOwnerReference($transaction, String $docNo) { + $transactionOwner = $transaction->transaction_owner; + if ($transactionOwner) { + $transactionOwner->update([ + 'invoice_reference'=>$docNo, + 'status'=>ApprovalStatus::COMPLETED + ]); + return [$transactionOwner->owner_reference, $transaction->created_at]; + } + return [false, false]; + } + public function changeExcelDate($date) { $unixTime = (($date - 25569) * 86400); diff --git a/app/Http/Controllers/Imports/ImportStatementReceiptsController.php b/app/Http/Controllers/Imports/ImportStatementReceiptsController.php index 22111881..6c117642 100644 --- a/app/Http/Controllers/Imports/ImportStatementReceiptsController.php +++ b/app/Http/Controllers/Imports/ImportStatementReceiptsController.php @@ -2,24 +2,40 @@ namespace App\Http\Controllers\Imports; -use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; -use App\Classes\Modules\Imports\Services\GenericImport; -use App\Classes\Modules\Segments\DataTransferObjects\SeasonalSegmentObject; -use App\Classes\ValueObjects\Constants\ApprovalStatus; -use App\Models\Segment; -use App\Models\User; -use Carbon\Carbon; use DateTime; +use Carbon\Carbon; +use App\Models\User; +use App\Models\Company; +use App\Models\Segment; +use App\Models\Transaction; use Illuminate\Http\Request; +use App\Models\SeasonalSegment; +use Illuminate\Http\JsonResponse; +use Illuminate\Support\Facades\DB; use Maatwebsite\Excel\Facades\Excel; +use App\Models\TransactionMappingLog; +use App\Models\StatementTransactionOwner; +use App\Classes\ValueObjects\Constants\HttpStatus; +use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\Modules\Imports\Services\GenericImport; +use App\Classes\ValueObjects\Response\ApiResponseObject; use App\Classes\Modules\Segments\Services\CreatesSeasonalSegment; use App\Classes\Modules\Companies\Processors\AssignSegmentProcessor; -use App\Models\Company; -use App\Models\SeasonalSegment; -use App\Models\Transaction; +use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject; +use App\Classes\Modules\Segments\DataTransferObjects\SeasonalSegmentObject; class ImportStatementReceiptsController { + private $responseTitle; + private $responseMessage; + + private $removeStr = 'Payment for '; + + public function __construct() { + $this->responseTitle = 'Import Receipt Mapping'; + $this->responseMessage = 'You have successfully imported receipt mapping'; + } + /** * @param Request $request * @return array @@ -27,20 +43,74 @@ class ImportStatementReceiptsController */ public function import(Request $request) { - $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); - $file = json_decode($object->getFiles()[0])->file_info->original->file; + try { + $importDate = date('Y-m-d H:i:s'); + $object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports'); + $file = json_decode($object->getFiles()[0])->file_info->original->file; - $import = new GenericImport(); - Excel::import($import, $file); - $excelRows = $import->rows; - $excelRows = $excelRows->toArray(); + $import = new GenericImport(); + Excel::import($import, $file); + $excelRows = $import->rows; + $excelRows = $excelRows->toArray(); - foreach ($excelRows as $row) { - // if has date column - // $transactionDate = $this->changeExcelDate($row['date']); + $data = []; + foreach ($excelRows as $row) { + $row['mapped_result_reference'] = null; + $row['mapped_status'] = 'failed'; + $row['date'] = in_array(gettype($row['doc_date']), ['integer', 'double']) ? $this->changeExcelDate($row['doc_date']) : date('Y-m-d', strtotime($row['doc_date'])); + + if ($invRefer = $this->getInvoiceReference($row['description'])) { + $returnReference = $this->mappingExchange($invRefer, $row['doc_no']); + if ($returnReference) { + $row['mapped_result_reference'] = $returnReference; + $row['mapped_status'] = 'success'; + } + } + + TransactionMappingLog::create([ + 'imported_date'=>$importDate, + 'type' => 'receipts', + 'data'=>$row, + ]); + array_push($data, $row); + } + + return $this->response($this->responseTitle, $this->responseMessage, HttpStatus::OK_WITH_MESSAGE, ['data'=>$data,'importedDate'=>$importDate]); + } catch (\Exception $exception){ + return $this->response('import invoice failed',$exception->getMessage(), ($exception->getCode()? $exception->getCode() : HttpStatus::SERVER_ERROR)); } } + private function getInvoiceReference($invRefer) { + $arrStr = explode($this->removeStr, $invRefer); + if (isset($arrStr[1])) return $arrStr[1]; + return null; + } + + public function response(String $responseTitle, String $responseMessage, int $httpStatus, ?array $data = []) : JsonResponse { + return (new ApiResponseObject($responseTitle, $responseMessage, $httpStatus, $data))->handler(); + } + + private function mappingExchange($invRefer, $docNo) { + $transactionOwner = StatementTransactionOwner::where('invoice_reference',$invRefer)->whereNull('receipt_reference')->where('status', ApprovalStatus::COMPLETED)->first(); + + if ($transactionOwner) { + return $this->updateTransactionOwnerReference($transactionOwner, $docNo); + } + return false; + } + + public function updateTransactionOwnerReference($transactionOwner, String $docNo) { + if ($transactionOwner) { + $transactionOwner->update([ + 'receipt_reference'=>$docNo, + 'status'=>ApprovalStatus::COMPLETED + ]); + return $transactionOwner->owner_reference; + } + return false; + } + public function changeExcelDate($date) { $unixTime = (($date - 25569) * 86400); 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/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/app/Http/Resources/BankStatementTransactionResource.php b/app/Http/Resources/BankStatementTransactionResource.php index 993b8c93..8f5e0193 100644 --- a/app/Http/Resources/BankStatementTransactionResource.php +++ b/app/Http/Resources/BankStatementTransactionResource.php @@ -34,7 +34,8 @@ class BankStatementTransactionResource extends JsonResource 'owners' => [ 'approved' => BankStatementTransactionOwnerResource::collection($this->owners()->whereIn('status', [ApprovalStatus::APPROVED])->get()), 'pending_verification' => BankStatementTransactionOwnerResource::collection($this->owners()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION])->get()), - 'rejected' => BankStatementTransactionOwnerResource::collection($this->owners()->whereIn('status', [ApprovalStatus::REJECTED])->get()) + 'rejected' => BankStatementTransactionOwnerResource::collection($this->owners()->whereIn('status', [ApprovalStatus::REJECTED])->get()), + 'completed' => BankStatementTransactionOwnerResource::collection($this->owners()->whereIn('status', [ApprovalStatus::COMPLETED])->get()), ] ]; } diff --git a/app/Http/Resources/TransactionDetailResource.php b/app/Http/Resources/TransactionDetailResource.php index 1b60cfce..4257a9fb 100644 --- a/app/Http/Resources/TransactionDetailResource.php +++ b/app/Http/Resources/TransactionDetailResource.php @@ -16,6 +16,7 @@ class TransactionDetailResource extends JsonResource { return [ + 'id' => $this->id, 'stockCode' => $this->product_code, 'description' => $this->product_name, 'quantity' => $this->quantity, diff --git a/app/Http/Resources/TransactionMappingLogResource.php b/app/Http/Resources/TransactionMappingLogResource.php new file mode 100644 index 00000000..954294f1 --- /dev/null +++ b/app/Http/Resources/TransactionMappingLogResource.php @@ -0,0 +1,23 @@ + $this->id, + 'imported_date' => $this->imported_date, + 'type' => $this->type + ]; + } +} diff --git a/app/Models/AccountStatement.php b/app/Models/AccountStatement.php index d9e53d60..2f5b0e8c 100644 --- a/app/Models/AccountStatement.php +++ b/app/Models/AccountStatement.php @@ -16,6 +16,8 @@ class AccountStatement extends Model 'total_amount', 'begin_balance', 'end_balance', + 'total_rows', + 'mapped_rows', ]; protected $casts = [ diff --git a/app/Models/Company.php b/app/Models/Company.php index 8b2e6081..54ae1e23 100644 --- a/app/Models/Company.php +++ b/app/Models/Company.php @@ -109,7 +109,7 @@ class Company extends AbstractModel implements Documentable { return $this->hasManyDeep(Transaction::class, [Booking::class], ['company_id', 'owner_id'], ['id', 'id']); } - + /** * @return HasMany */ @@ -130,13 +130,25 @@ class Company extends AbstractModel implements Documentable * @return Builder */ public function services(): Builder { - return ServiceType::where('status', ApprovalStatus::APPROVED)->whereHas('constants', function($query) { - $query->Where(function($query){ - $query->where('reference', SegmentConstants::SERVICE_TYPE)->where('detail->is_active', true); - })->orWhere(function($query) { - $query->where('reference', SegmentConstants::CUSTOM_SERVICE_TYPE)->where('detail->is_active', true)->whereIn('segment_id', $this->segments->pluck('id')); + + if ($this->business_type === 3) { + return ServiceType::where('status', ApprovalStatus::APPROVED)->whereHas('constants', function($query) { + $query->where(function($query) { + $query->where('reference', SegmentConstants::SERVICE_TYPE)->where('detail->is_active', true); + })->orWhere(function($query) { + $query->where('reference', SegmentConstants::CUSTOM_SERVICE_TYPE)->where('detail->is_active', true); + }); }); - }); + } else { + // Existing logic for other company types + return ServiceType::where('status', ApprovalStatus::APPROVED)->whereHas('constants', function($query) { + $query->Where(function($query){ + $query->where('reference', SegmentConstants::SERVICE_TYPE)->where('detail->is_active', true); + })->orWhere(function($query) { + $query->where('reference', SegmentConstants::CUSTOM_SERVICE_TYPE)->where('detail->is_active', true)->whereIn('segment_id', $this->segments->pluck('id')); + }); + }); + } } public function servicesConfigurations(): Collection { diff --git a/app/Models/StatementTransaction.php b/app/Models/StatementTransaction.php index 80d6759f..4bba7903 100644 --- a/app/Models/StatementTransaction.php +++ b/app/Models/StatementTransaction.php @@ -5,6 +5,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Staudenmeir\EloquentHasManyDeep\HasRelationships; +use App\Classes\ValueObjects\Constants\ApprovalStatus; class StatementTransaction extends Model { @@ -47,4 +48,16 @@ class StatementTransaction extends Model { return $this->hasMany(StatementTransactionOwner::class); } + + public function owner_status() + { + return $this->owners()->whereIn('status',[ApprovalStatus::APPROVED,ApprovalStatus::COMPLETED,ApprovalStatus::PENDING_VERIFICATION]); + } + + public function scopeDoesntMapStatement($query) + { + $query->whereDoesntHave('owners', function($query){ + return $query->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + })->orderBy('posting_date'); + } } diff --git a/app/Models/StatementTransactionOwner.php b/app/Models/StatementTransactionOwner.php index 52e8d1fc..bd96efff 100644 --- a/app/Models/StatementTransactionOwner.php +++ b/app/Models/StatementTransactionOwner.php @@ -5,6 +5,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\MorphTo; class StatementTransactionOwner extends Model { @@ -21,9 +22,20 @@ class StatementTransactionOwner extends Model 'receipt_reference', 'status', ]; + + public function owner(): morphTo + { + return $this->morphTo(); + } public function transaction(): BelongsTo { 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/app/Models/Transaction.php b/app/Models/Transaction.php index 05fbfde7..185fdb36 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -18,6 +18,7 @@ use Illuminate\Database\Eloquent\Relations\HasOneThrough; use Illuminate\Database\Eloquent\Relations\MorphMany; use Illuminate\Database\Eloquent\Relations\MorphTo; use Staudenmeir\EloquentHasManyDeep\HasTableAlias; +use App\Models\StatementTransactionOwner; class Transaction extends AbstractModel implements Documentable, Transactionable, Voucherifiable @@ -53,6 +54,14 @@ class Transaction extends AbstractModel implements Documentable, Transactionable return $this->MorphOne(Transaction::class, 'owner')->where('type', TransactionType::CREDIT_NOTE); } + /** + * @return \Illuminate\Database\Eloquent\Relations\MorphOne + */ + public function transaction_owner() + { + return $this->MorphOne(StatementTransactionOwner::class, 'owner','owner_type','owner_id'); + } + /** * @return BelongsTo */ @@ -69,6 +78,16 @@ class Transaction extends AbstractModel implements Documentable, Transactionable return $this->BelongsTo( Company::class, 'issuer', 'id'); } + /** + * Get the user that owns the Transaction + * + * @return BelongsTo + */ + public function receiverCompany(): BelongsTo + { + return $this->belongsTo(Company::class, 'receiver', 'id'); + } + /** * @return BelongsTo */ @@ -202,6 +221,22 @@ class Transaction extends AbstractModel implements Documentable, Transactionable return $query->whereIn('status', [ApprovalStatus::APPROVED]); } + /** + * @param Builder $query + * @return Builder + */ + public function scopeGetReceiverWithJoinStatementTransactionAndOwner(Builder $query, Array $row) { + $query->join('companies',function($q) use ($row) { + $q->on('companies.id','=','transactions.receiver'); + $q->where('debtor',$row['debtor_code']); + }) + ->join('statement_transaction_owners', function ($q) { + $q->on('statement_transaction_owners.owner_id','=','transactions.id'); + $q->where('statement_transaction_owners.owner_type','=',Transaction::class); + }) + ->join('statement_transactions','statement_transactions.id','=','statement_transaction_owners.statement_transaction_id'); + } + /** * @return MorphMany */ diff --git a/app/Models/TransactionMappingLog.php b/app/Models/TransactionMappingLog.php new file mode 100644 index 00000000..e9ddab33 --- /dev/null +++ b/app/Models/TransactionMappingLog.php @@ -0,0 +1,24 @@ + 'array', + ]; + + public static function boot() { + parent::boot(); + + static::creating(function ($model) { + $model->imported_by = auth()->user()->id; + }); + } + +} diff --git a/config/logging.php b/config/logging.php index fb872693..d0d0a009 100644 --- a/config/logging.php +++ b/config/logging.php @@ -104,6 +104,10 @@ return [ 'path' => storage_path('logs/regenerateInvoice.log'), 'level' => 'info', ], + 'guzzleShippingPortal' => [ + 'driver' => 'errorlog', + 'level' => 'debug', + ], ], ]; diff --git a/database/migrations/2023_10_04_212224_create_transaction_mapping_logs_table.php b/database/migrations/2023_10_04_212224_create_transaction_mapping_logs_table.php new file mode 100644 index 00000000..8989d8ae --- /dev/null +++ b/database/migrations/2023_10_04_212224_create_transaction_mapping_logs_table.php @@ -0,0 +1,35 @@ +id(); + $table->bigInteger('imported_by')->unsigned(); + $table->foreign('imported_by')->references('id')->on('users'); + $table->dateTime('imported_date')->nullable(); + $table->text('data')->nullable(); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('transaction_mapping_logs'); + } +} diff --git a/database/migrations/2023_10_22_140339_add_mapped_rate_to_account_statements_table.php b/database/migrations/2023_10_22_140339_add_mapped_rate_to_account_statements_table.php new file mode 100644 index 00000000..f6a8e7e7 --- /dev/null +++ b/database/migrations/2023_10_22_140339_add_mapped_rate_to_account_statements_table.php @@ -0,0 +1,34 @@ +integer('total_rows')->unsigned()->default(0)->after('end_balance'); + $table->integer('mapped_rows')->unsigned()->default(0)->after('end_balance'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('account_statements', function (Blueprint $table) { + $table->dropColumn('total_rows'); + $table->dropColumn('mapped_rows'); + }); + } +} diff --git a/database/migrations/2023_12_26_152448_add_type_to_transaction_mapping_logs_table.php b/database/migrations/2023_12_26_152448_add_type_to_transaction_mapping_logs_table.php new file mode 100644 index 00000000..3927920a --- /dev/null +++ b/database/migrations/2023_12_26_152448_add_type_to_transaction_mapping_logs_table.php @@ -0,0 +1,40 @@ +string('type',50)->default('invoices')->after('imported_date'); + }); + + foreach (DB::table('transaction_mapping_logs')->get() as $key => $value) { + $data = json_decode($value->data); + DB::table('transaction_mapping_logs')->where('id',$value->id)->update([ + 'type' => (isset($data->description) ? 'receipts' : 'invoices') + ]); + } + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('transaction_mapping_logs', function (Blueprint $table) { + $table->dropColumn('type'); + }); + } +} diff --git a/public/template/import-po-template.xlsx b/public/template/import-po-template.xlsx new file mode 100644 index 00000000..d1565aa8 Binary files /dev/null and b/public/template/import-po-template.xlsx differ diff --git a/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue b/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue index b3d50d7b..5d1341b1 100644 --- a/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue +++ b/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue @@ -77,6 +77,13 @@ import { required } from "vuelidate/lib/validators"; export default { + props:{ + editMapped: { + type: Boolean, + default: false, + required: false + } + }, data(){ return { error: '', @@ -116,6 +123,8 @@ system_references : this.system_references ? this.system_references.toLowerCase() : '', transaction_reference : this.transaction_reference }; + + if (this.editMapped) this.parameters['editMapped'] = true; this.submit(this.route('api.accounting.statement.details.update', this.data.id), 'put', this.section, true, true); }, diff --git a/resources/assets/vue/components/accounting/elements/HistoryImportedInvoices.vue b/resources/assets/vue/components/accounting/elements/HistoryImportedInvoices.vue new file mode 100644 index 00000000..d3d68cfb --- /dev/null +++ b/resources/assets/vue/components/accounting/elements/HistoryImportedInvoices.vue @@ -0,0 +1,39 @@ + + + diff --git a/resources/assets/vue/components/accounting/elements/HistoryImportedReceipts.vue b/resources/assets/vue/components/accounting/elements/HistoryImportedReceipts.vue new file mode 100644 index 00000000..00138fa5 --- /dev/null +++ b/resources/assets/vue/components/accounting/elements/HistoryImportedReceipts.vue @@ -0,0 +1,39 @@ + + + diff --git a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue index db2fc252..787f2f37 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -4,6 +4,8 @@
{{ item.posting_date }}
{{ item.transaction_description_1 + ' - ' + item.transaction_description_2 }}
+ +
{{item.owners.pending_verification[0].system}}
@@ -11,6 +13,47 @@
+ + +
+
+
{{item.owners.approved[0].system}}
+
{{ typeString(item.owners.approved[0].type) }}
+
+
+ {{item.owners.approved[0].reference}} +
+ + + + + + + + + + + + + +
+
+
+
+
+ +
@@ -31,7 +74,7 @@
{{ owner.reference }} -
+
@@ -46,13 +89,30 @@ > + + + + + +
-
+ + +
{{ 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...
-
+
@@ -68,11 +68,38 @@ class="text-center" :apiRoute="route('api.accounting.statement_transaction.owner.groupApprove')" apiMethod="post" + :params="filter" :section="section" >
+ + +
+
+
+ + + + +
+
+ + + + +
+
+
+ + Search + +
+
+
+
+
@@ -86,19 +113,23 @@
Amount
+
+
Select +
- + +
-
-
Export Receipts To AutoCount
+
Export Receipts To AutoCount
+
Nest Step

@@ -153,7 +192,7 @@
-
Import Receipts
+
Import Receipts

Nest Step

@@ -161,6 +200,13 @@ Learn How to do this step?
+
+
+ + + +
+
@@ -182,6 +228,10 @@ export default { data(){ return { + parameters: { + startDate: '', + endDate: '', + }, type: null, stage: null, exportStage: 0, @@ -190,28 +240,59 @@ export default { files: [], parameters: {}, section: 'bankTransactionSection', + invMappedTrue: false, + recMappedTrue: false, + selectAll: false, } }, validations: { + parameters: { + startDate: { + required + }, + endDate: { + required + }, + }, files: { // required // todo-new: set required if is pdf section } }, methods: { importInvoice(){ - this.parameters = { - files: this.files - }; - this.submit(this.route('api.import_invoices.upload'), 'post', this.section, true, false); + this.invMappedTrue = true; }, importReceipts(){ - this.parameters = { - files: this.files - }; - this.submit(this.route('api.import_receipts.upload'), 'post', this.section, true, false); + this.recMappedTrue = true; }, exportInvoiceToAutoCount(){ - window.open(this.route('invoiceTransactions.export'), '_blank'); + const checkedStatementTransactions = this.getCheckedStatementOwners(); + + let route = this.route('invoiceTransactions.export')+'?filter='+JSON.stringify(this.filter); + if (checkedStatementTransactions) { + route += '&bankStatementTransactionId='+checkedStatementTransactions; + } + + window.open(route, '_blank'); + }, + exportReceiptToAutoCount(){ + const checkedStatementTransactions = this.getCheckedStatementOwners(); + + this.filter['where_has_owners_and_null'] = 'statement_transaction_owners.receipt_reference'; + this.filter['where_has_owners_and_not_null'] = 'statement_transaction_owners.invoice_reference'; + let route = this.route('receiptTransactions.export')+'?filter='+JSON.stringify(this.filter); + if (checkedStatementTransactions) { + route += '&bankStatementTransactionId='+checkedStatementTransactions; + } + + window.open(route, '_blank'); + }, + getCheckedStatementOwners() { + let bankStatementTransactionId = []; + $('.request_export_item:checked').each(function() { + bankStatementTransactionId.push($(this).val()); + }); + return (bankStatementTransactionId.length > 0 ? JSON.stringify(bankStatementTransactionId) : null); }, successHandler(){ this.step += 1; @@ -233,10 +314,14 @@ export default { this.filter = {min_amount: 0, is_mapped: true, is_mapped_with_multiple: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [1], per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 3: - this.filter = {min_amount: 0, is_mapped: false, per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {min_amount: 0, is_mapped_false_or_mapped_but_status_in: [4], per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 4: this.filter = {min_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + + if (typeof this.parameters.startDate != 'undefined' && this.parameters.startDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_start: this.parameters.startDate}}; + + if (typeof this.parameters.endDate != 'undefined' && this.parameters.endDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_end:this.parameters.endDate}}; break; } } @@ -254,6 +339,11 @@ export default { break; case 4: this.filter = {max_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [3, 5], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + + if (typeof this.parameters.startDate != 'undefined' && this.parameters.startDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_start: this.parameters.startDate}}; + + if (typeof this.parameters.endDate != 'undefined' && this.parameters.endDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_end:this.parameters.endDate}}; + break; } } diff --git a/resources/assets/vue/components/bookings/elements/BookingComponent.vue b/resources/assets/vue/components/bookings/elements/BookingComponent.vue index 9ff3fe9c..7e675646 100644 --- a/resources/assets/vue/components/bookings/elements/BookingComponent.vue +++ b/resources/assets/vue/components/bookings/elements/BookingComponent.vue @@ -22,7 +22,7 @@
-
+
Marking
{{this.item.company.reference}} @@ -34,7 +34,7 @@ {{this.item.convertible_currency.short_code}}
-
+
Transfer Type
{{this.item.service.name}}
diff --git a/resources/assets/vue/components/bookings/elements/DownloadSupplierWhiteFormComponent.vue b/resources/assets/vue/components/bookings/elements/DownloadSupplierWhiteFormComponent.vue new file mode 100644 index 00000000..827557ea --- /dev/null +++ b/resources/assets/vue/components/bookings/elements/DownloadSupplierWhiteFormComponent.vue @@ -0,0 +1,98 @@ + + + diff --git a/resources/assets/vue/components/bookings/elements/PaymentComponent.vue b/resources/assets/vue/components/bookings/elements/PaymentComponent.vue new file mode 100644 index 00000000..1db46493 --- /dev/null +++ b/resources/assets/vue/components/bookings/elements/PaymentComponent.vue @@ -0,0 +1,121 @@ + + + diff --git a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue index 7b7ec3d4..9a1bf774 100644 --- a/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue +++ b/resources/assets/vue/components/bookings/forms/PurchaseOrderFormComponent.vue @@ -19,66 +19,94 @@
-
+
-
-
-
- - -
-
-
-
- - -
+
+
+ {{ useUploadCsvPo ? '< Back to Manual Enter Purchase Order' : 'Click here to Upload PURCHASE ORDER CSV' }}
-
-
-
- - +
+
+
+
+
+ + +
+
+
+
+ + +
+
-
-
-
-
-
-
-
- +
+
+
+ + +
+
+
+
+
+
+
+
+ +
+
-
-
-
- - -
-
-
-
- +
+ + +
+
+
+
+ +
+
+
+
+

Total

+
{{data.fixed_currency.short_code}} {{productTotal.toFixed(3)}}
+
+
+ +
+
-
-
-

Total

-
{{data.fixed_currency.short_code}} {{productTotal.toFixed(3)}}
-
-
- +
+
+
+
+ + + +
+
+
+
+ +
+
@@ -139,10 +167,7 @@ diff --git a/resources/assets/vue/components/general/elements/ListComponent.vue b/resources/assets/vue/components/general/elements/ListComponent.vue index 50d2fa19..8f54548b 100644 --- a/resources/assets/vue/components/general/elements/ListComponent.vue +++ b/resources/assets/vue/components/general/elements/ListComponent.vue @@ -99,6 +99,7 @@ updateFilters(filters){ this.filters = filters; this.setDecoratorDefault(); + this.$store.dispatch('updateListQueue', {'name': this.section, 'page': 1, 'filters': this.filters}); this.submit(this.endpoint + '?page=1&filters=' + JSON.stringify(this.filters), 'get', this.section, false, false) }, successHandler(response){ 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] diff --git a/resources/assets/vue/components/general/forms/SelectComponent.vue b/resources/assets/vue/components/general/forms/SelectComponent.vue index 1f902903..3629cbe0 100644 --- a/resources/assets/vue/components/general/forms/SelectComponent.vue +++ b/resources/assets/vue/components/general/forms/SelectComponent.vue @@ -1,5 +1,5 @@ @@ -13,6 +13,10 @@ }, value: { required: false + }, + disableOnFetch: { + type: Boolean, + default: false } }, mounted(){ diff --git a/resources/assets/vue/components/general/forms/SelectableComponent.vue b/resources/assets/vue/components/general/forms/SelectableComponent.vue index 95db6af8..d93dc4b5 100644 --- a/resources/assets/vue/components/general/forms/SelectableComponent.vue +++ b/resources/assets/vue/components/general/forms/SelectableComponent.vue @@ -1,5 +1,5 @@ diff --git a/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue b/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue index 698b35be..cc091588 100644 --- a/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue +++ b/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue @@ -1,36 +1,37 @@