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/HasAccountStatementId.php b/app/Classes/General/Eloquent/Filters/HasAccountStatementId.php index 05cfe9d8..a405be23 100644 --- a/app/Classes/General/Eloquent/Filters/HasAccountStatementId.php +++ b/app/Classes/General/Eloquent/Filters/HasAccountStatementId.php @@ -15,7 +15,7 @@ class HasAccountStatementId implements Filter */ public static function apply(Builder $builder, $value) { - return $builder->whereHas('statementTransaction', function ($query) use ($value) { + return $builder->whereHas('transaction', function ($query) use ($value) { $query->where('account_statement_id', $value); }); } 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/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/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/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/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..f9eb9c7b 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/GroupApproveStatementTransactionLogic.php @@ -57,13 +57,8 @@ class GroupApproveStatementTransactionLogic extends AbstractControllerLogic public function logic(Request $request): JsonResponse { - $filters = [ - "min_amount" => 0, - "is_mapped" => true, - "is_mapped_with_multiple" => false, - "statement_transaction_owner_type_in" => [1, 2], - "statement_transaction_owner_status_in" => [1] - ]; + $filters = $request->except(['per_page','order_by']); + $statementTransactions = $this->listsBankStatementTransactions->execute($filters); foreach ($statementTransactions as $statementTransaction) { diff --git a/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php index d9eab3db..9f6c28e6 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()->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/Processors/CreateBankStatementTransactionOwnersProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php index 164546c3..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::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){ @@ -39,21 +36,21 @@ class CreateBankStatementTransactionOwnersProcessor // Exchange Sales $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($creditTransactions as $creditTransaction) { - $transaction->owners()->firstOrCreate([ + $isArray = is_array($creditTransaction); + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SALES, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, - 'owner_id'=> $creditTransaction->id, - 'owner_reference'=> $creditTransaction->owner->marking, + 'owner_id'=> $isArray ? $creditTransaction['owner_id'] : $creditTransaction->id, + 'owner_reference'=> $isArray ? $creditTransaction['owner_reference'] : $creditTransaction->owner->marking, ]); } - // 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'], @@ -65,18 +62,19 @@ class CreateBankStatementTransactionOwnersProcessor // Exchange Wallet Top Up $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($creditTransactions as $creditTransaction) { - $transaction->owners()->firstOrCreate([ + $isArray = is_array($creditTransaction); + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, - 'owner_id'=> $creditTransaction->id, - 'owner_reference'=> $creditTransaction->owner->owner->reference, + 'owner_id'=> $isArray ? $creditTransaction['owner_id'] : $creditTransaction->id, + 'owner_reference'=> $isArray ? $creditTransaction['owner_reference'] : $creditTransaction->owner->owner->reference, ]); } - $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'], @@ -87,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 ]); } @@ -96,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 ]); } @@ -121,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, @@ -136,12 +134,13 @@ class CreateBankStatementTransactionOwnersProcessor // Exchange Wallet Withdrawal $debitTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::DEBIT_NOTE, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($debitTransactions as $debitTransaction) { - $transaction->owners()->firstOrCreate([ + $isArray = is_array($creditTransaction); + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_WITHDRAWAL, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, - 'owner_id'=> $debitTransaction->id, - 'owner_reference'=> $debitTransaction->owner->owner->marking, + 'owner_id'=> $isArray ? $debitTransaction['owner_id'] : $debitTransaction->id, + 'owner_reference'=> $isArray ? $debitTransaction['owner_reference'] : $debitTransaction->owner->owner->marking, ]); } @@ -149,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) @@ -271,10 +272,8 @@ class CreateBankStatementTransactionOwnersProcessor return $query->get(); } else { $result = $this->getTransactionsFromExchange($amount, $dateRange, $type, $ownerType, $paymentMethod); - $transactionsId = Arr::pluck($result, 'owner_id'); - $query = $model::whereIn('id', $transactionsId); - return $query->get(); + return $result; } } @@ -321,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']; @@ -348,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/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/Services/GeneratesBookingMarking.php b/app/Classes/Modules/Bookings/Services/GeneratesBookingMarking.php index 3e58e945..72f921a6 100644 --- a/app/Classes/Modules/Bookings/Services/GeneratesBookingMarking.php +++ b/app/Classes/Modules/Bookings/Services/GeneratesBookingMarking.php @@ -24,7 +24,7 @@ class GeneratesBookingMarking */ public function execute(): int { - $marking = mt_rand(20000, 99999); + $marking = mt_rand(100000, 999999); return !$this->bookingMarkingExists->execute($marking) ? $marking : self::execute(); } 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/ExportsCustomersWalletTransactionHistory.php b/app/Classes/Modules/Exports/Services/ExportsCustomersWalletTransactionHistory.php new file mode 100644 index 00000000..745539f5 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsCustomersWalletTransactionHistory.php @@ -0,0 +1,107 @@ +request = $request; + } + + public function headings(): array + { + return [ + 'Date', + 'Description', + 'Incoming', + 'Outgoing', + 'Balance', + ]; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + $company = Company::where('reference', $this->request->route('marking'))->first(); + $transactions = $company->wallets()->first()->transactions()->whereIn('transactions.status', [2, 3])->orderBy('id'); + // dd($transactions->get()->toArray()); + + return $transactions; + } + + /** + * @param Transaction $transaction + * + * @return array + */ + public function map($transaction): array + { + // dd($transaction); + + $decimals = $this->request->route('is_precise') == 'true' ? 5 : 2; + + $description = ''; + switch ((int) $transaction->type) { + case 5: + $description = (float) $transaction->amount . ' Credit Top up'; + break; + case 9: + $description = 'Credit Voucher for ' . $transaction->payment_reference; + break; + case 1: + $booking = Transaction::where('payment_reference', $transaction->bill_no)->first()->owner; + + if (!$booking) { + $description = 'Payment for unknown booking, please contact tech support.'; + break; + } + + $marking = $booking->marking; + $description = 'Payment For booking refs' . $marking; + break; + case 11: + $description = 'Debit Voucher for ' . $transaction->payment_reference; + break; + } + + $incoming = $outgoing = ''; + + if (in_array($transaction->type, [TransactionType::TOP_UP, TransactionType::CREDIT_NOTE])) { + $incoming = number_format($transaction->amount, $decimals, '.', ','); + $this->runningBalance += $transaction->amount; + } + + if (in_array($transaction->type, [TransactionType::PAYMENT, TransactionType::DEBIT_NOTE])) { + $outgoing = number_format($transaction->amount, $decimals, '.', ','); + $this->runningBalance -= $transaction->amount; + } + + return [ + Carbon::parse($transaction->created_at)->format('d-m-Y h:i:s A'), + $description, + $incoming, + $outgoing, + number_format($this->runningBalance, $decimals, '.', ',') + ]; + } +} diff --git a/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php b/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php new file mode 100644 index 00000000..71363b52 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php @@ -0,0 +1,78 @@ +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' + ]; + } + + /** + * @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 + { + // dd($transaction); + $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'), + ]; + + } +} diff --git a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php index 90780750..a7041b1c 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; @@ -106,15 +110,15 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading ]; } else { $row = (App()->make(ListShippingPortalTransactions::class))->execute([ - 'id' => $transaction->owner_id, + 'id' => $statementTransactionOwner->owner_id, 'with_company' => true, ]); 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); @@ -123,7 +127,24 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading Log::info('Error in Exports Invoice Transactions ' . $this->counter); - return []; + 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, + '', + '', + '', + '' + ]; } $row = $row[0]; diff --git a/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php b/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php new file mode 100644 index 00000000..07c5d3c1 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php @@ -0,0 +1,132 @@ +request = $request; + } + + public function headings(): array + { + $header = [ + '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), + $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 1ae97d45..649b3309 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/ListWalletTransactionsLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/ListWalletTransactionsLogic.php @@ -5,8 +5,12 @@ namespace App\Classes\Modules\Transactions\ControllersLogic; use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Modules\Transactions\Services\ListsTransactions; +use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\ValueObjects\Constants\TransactionType; use App\Http\Resources\BookingResource; use App\Http\Resources\WalletTransactionResource ; +use App\Models\Transaction; +use App\Models\Wallet; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -39,6 +43,36 @@ 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) { + $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]) + ->whereIn('type', [TransactionType::TOP_UP, TransactionType::CREDIT_NOTE]) + ->where('id', '>', $query->first()->id) + ->sum('amount'); + $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]) + ->where('id', '>', $query->first()->id) + ->sum('amount'); + $runningBalanceInReverse = $currentWalletBalance - $incoming + $outgoing; + $request['running_balance'] = $runningBalanceInReverse; + } + return $this->collectionResponse(WalletTransactionResource::collection($query)); } diff --git a/app/Classes/Modules/Transactions/Services/GeneratesTransactionBillNumber.php b/app/Classes/Modules/Transactions/Services/GeneratesTransactionBillNumber.php index 943da696..6a49c941 100644 --- a/app/Classes/Modules/Transactions/Services/GeneratesTransactionBillNumber.php +++ b/app/Classes/Modules/Transactions/Services/GeneratesTransactionBillNumber.php @@ -34,7 +34,8 @@ class GeneratesTransactionBillNumber $attempt = 0; while ($attempt < 10) { // Retry up to 10 times - $billNumber = $prefix . $date->format('Y') . $date->format('m') . '-' . microtime(true); + // $billNumber = $prefix . $date->format('Y') . $date->format('m') . '-' . intval(microtime(true)); + $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/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..733c84fa 100644 --- a/app/Http/Controllers/Exports/ExportCustomersToExcelController.php +++ b/app/Http/Controllers/Exports/ExportCustomersToExcelController.php @@ -15,6 +15,9 @@ 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; class ExportCustomersToExcelController { @@ -64,6 +67,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 +85,10 @@ 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; + } } \ No newline at end of file diff --git a/app/Http/Controllers/Exports/ExportCustomersWalletTransactionToExcelController.php b/app/Http/Controllers/Exports/ExportCustomersWalletTransactionToExcelController.php new file mode 100644 index 00000000..c4457565 --- /dev/null +++ b/app/Http/Controllers/Exports/ExportCustomersWalletTransactionToExcelController.php @@ -0,0 +1,32 @@ +headers->set('Authorization', 'Bearer ' . $token); + } + + public function export(Request $request) + { + $exportsTransactions = new ExportsCustomersWalletTransactionHistory($request); + $filename = $request->route('marking') . '-wallet-' . ($request->route('is_precise') == 'true' ? 'precise-' : '') . 'transaction-history.xls'; + $response = $exportsTransactions->download($filename, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + ob_end_clean(); + return $response; + } +} diff --git a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php index a59f9463..8d2b920b 100644 --- a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php +++ b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php @@ -2,33 +2,47 @@ 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'; + } + /** * @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'); - + $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; @@ -37,26 +51,37 @@ class ImportStatementInvoiceController $excelRows = $import->rows; $excelRows = $excelRows->toArray(); + $data = []; 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 - // } + $row['mapped_result_reference'] = null; + $row['mapped_status'] = 'failed'; + $row['date'] = date('Y-m-d', strtotime($row['date'])); // 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'); + foreach (['exchange','izyim'] as $system) { + $returnReference = $this->mappingTopUp($row, $system); + if ($returnReference) { + $row['mapped_result_reference'] = $returnReference; + $row['mapped_status'] = 'success'; + } + } + } else { + $returnReference = $this->mappingExchange($row); + if ($returnReference) { + $row['mapped_result_reference'] = $returnReference; + $row['mapped_status'] = 'success'; + } } + + TransactionMappingLog::create([ + 'imported_date'=>$importDate, + 'data'=>$row, + ]); + array_push($data, $row); + // if 5 digits -> exchange booking reference // find transation @@ -88,12 +113,53 @@ class ImportStatementInvoiceController } + + return $this->response(['data'=>$data,'importedDate'=>$importDate]); } - public function changeExcelDate($date) - { - $unixTime = (($date - 25569) * 86400); - $date = new DateTime("@$unixTime"); - return $date->format('Y-m-d'); // Change the format to 'Y-m-d' + public function response(?array $data = []) : JsonResponse { + return (new ApiResponseObject($this->responseTitle, + $this->responseMessage, + HttpStatus::OK_WITH_MESSAGE, $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['owner_reference']; + + if ($system == 'exchange') return $this->updateTransactionOwnerReference($data, $row['doc_no']); + } + } catch (\Throwable $th) { + return false; + } + } + + private function mappingExchange(Array $row) { + $date = $row['date']; + $transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where('statement_transactions.amount', $row['net_total'])->whereRaw("DATE(posting_date) = '$date'")->get(); + + if ($transactions && $transactions->count() == 0) { + $transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where(DB::raw('FLOOR(statement_transactions.amount)'), floor($row['net_total']))->whereRaw("DATE(posting_date) = '$date'")->get(); + } + + if ($transactions && $transactions->count() == 1) { + foreach ($transactions as $key => $transaction) { + return $this->updateTransactionOwnerReference($transaction, $row['doc_no']); + } + } + return 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; + } + return false; } } diff --git a/app/Http/Controllers/Imports/ImportStatementReceiptsController.php b/app/Http/Controllers/Imports/ImportStatementReceiptsController.php index 22111881..4006e130 100644 --- a/app/Http/Controllers/Imports/ImportStatementReceiptsController.php +++ b/app/Http/Controllers/Imports/ImportStatementReceiptsController.php @@ -17,9 +17,22 @@ use App\Classes\Modules\Companies\Processors\AssignSegmentProcessor; use App\Models\Company; use App\Models\SeasonalSegment; use App\Models\Transaction; +use App\Models\TransactionMappingLog; +use App\Classes\ValueObjects\Response\ApiResponseObject; +use App\Classes\ValueObjects\Constants\HttpStatus; +use Illuminate\Http\JsonResponse; +use Illuminate\Support\Facades\DB; class ImportStatementReceiptsController { + private $responseTitle; + private $responseMessage; + + public function __construct() { + $this->responseTitle = 'Import Receipt Mapping'; + $this->responseMessage = 'You have successfully imported receipt mapping'; + } + /** * @param Request $request * @return array @@ -27,6 +40,7 @@ class ImportStatementReceiptsController */ public function import(Request $request) { + $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; @@ -35,16 +49,59 @@ class ImportStatementReceiptsController $excelRows = $import->rows; $excelRows = $excelRows->toArray(); + $data = []; foreach ($excelRows as $row) { - // if has date column - // $transactionDate = $this->changeExcelDate($row['date']); + $row['mapped_result_reference'] = null; + $row['mapped_status'] = 'failed'; + $row['date'] = date('Y-m-d', strtotime($row['doc_date'])); + + $returnReference = $this->mappingExchange($row); + if ($returnReference) { + $row['mapped_result_reference'] = $returnReference; + $row['mapped_status'] = 'success'; + } + + TransactionMappingLog::create([ + 'imported_date'=>$importDate, + 'data'=>$row, + ]); + array_push($data, $row); } + + return $this->response(['data'=>$data,'importedDate'=>$importDate]); } - public function changeExcelDate($date) - { - $unixTime = (($date - 25569) * 86400); - $date = new DateTime("@$unixTime"); - return $date->format('Y-m-d'); // Change the format to 'Y-m-d' + public function response(?array $data = []) : JsonResponse { + return (new ApiResponseObject($this->responseTitle, + $this->responseMessage, + HttpStatus::OK_WITH_MESSAGE, $data))->handler(); + } + + private function mappingExchange(Array $row) { + $date = $row['date']; + $transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where('statement_transactions.amount', $row['payment_amount'])->whereRaw("DATE(posting_date) = '$date'")->get(); + + if ($transactions && $transactions->count() == 0) { + $transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where(DB::raw('FLOOR(statement_transactions.amount)'), floor($row['payment_amount']))->whereRaw("DATE(posting_date) = '$date'")->get(); + } + + if ($transactions && $transactions->count() == 1) { + foreach ($transactions as $key => $transaction) { + return $this->updateTransactionOwnerReference($transaction, $row['doc_no']); + } + } + return false; + } + + public function updateTransactionOwnerReference($transaction, String $docNo) { + $transactionOwner = $transaction->transaction_owner; + if ($transactionOwner) { + $transactionOwner->update([ + 'receipt_reference'=>$docNo, + 'status'=>ApprovalStatus::COMPLETED + ]); + return $transactionOwner->owner_reference; + } + return false; } } 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 new file mode 100644 index 00000000..c5bfba28 --- /dev/null +++ b/app/Http/Resources/BankStatementDetailResource.php @@ -0,0 +1,35 @@ +transaction; + $accountStatement = $transaction->statement; + return [ + '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, + 'account_statement_date_from' => Carbon::parse($accountStatement->date_from)->format('Y-m-d'), + 'account_statement_date_to' => Carbon::parse($accountStatement->date_to)->format('Y-m-d'), + ]; + } +} 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/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/WalletResource.php b/app/Http/Resources/WalletResource.php index 4fa484ad..d1c6b941 100644 --- a/app/Http/Resources/WalletResource.php +++ b/app/Http/Resources/WalletResource.php @@ -21,7 +21,7 @@ class WalletResource extends JsonResource 'currency_id' => $this->currency_id, 'amount' => (double) $this->amount, 'company_id' => (int) $this->owner->id, - 'transactions' => $this->whenLoaded('transactions', WalletTransactionResource::collection($this->transactions()->whereIn('status', [2, 3])->orderBy('id', 'DESC')->get()), []), + // 'transactions' => $this->whenLoaded('transactions', WalletTransactionResource::collection($this->transactions()->whereIn('status', [2, 3])->orderBy('id', 'DESC')->get()), []), 'top_up_records' => $this->whenLoaded('transactions', WalletTransactionResource::collection($this->transactions()->whereNotIn('status', [0])->where('type', TransactionType::TOP_UP)->orderBy('id', 'DESC')->get()), []), ]; } diff --git a/app/Http/Resources/WalletTransactionResource.php b/app/Http/Resources/WalletTransactionResource.php index a0e1a930..ef3091fa 100644 --- a/app/Http/Resources/WalletTransactionResource.php +++ b/app/Http/Resources/WalletTransactionResource.php @@ -20,12 +20,15 @@ class WalletTransactionResource extends JsonResource public function toArray($request) { $description = ''; + $current_running_balance = $request['running_balance']; switch((int) $this->type){ case 5: $description = (double) $this->amount.' Credit Top up'; + $request['running_balance'] = bcsub($request['running_balance'], $this->amount, 5); break; case 9: $description = 'Credit Voucher for '.$this->payment_reference; + $request['running_balance'] = bcsub($request['running_balance'], $this->amount, 5); break; case 1: $booking = Transaction::where('payment_reference', $this->bill_no)->first()->owner; @@ -35,11 +38,13 @@ class WalletTransactionResource extends JsonResource break; } + $request['running_balance'] = bcadd($request['running_balance'], $this->amount, 5); $marking = $booking->marking; $description = 'Payment For booking refs.'.''.$marking.''; break; case 11: $description = 'Debit Voucher for '.$this->payment_reference; + $request['running_balance'] = bcadd($request['running_balance'], $this->amount, 5); break; } @@ -53,6 +58,7 @@ class WalletTransactionResource extends JsonResource 'payment_method' => (float) $this->payment_method, 'issuer_name' => $this->issuerCompany->name, 'amount' => (double) $this->amount, + 'running_balance' => (double) $current_running_balance, 'service_charge' => (double) $this->service_charge, 'tax' => (double) $this->tax, 'status' => (int) $this->status, 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/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..d6093f39 --- /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/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/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/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue index db2fc252..b09b9a56 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -11,6 +11,46 @@
{{item.owners.pending_verification[0].reference}}
+ + +
+
+
{{item.owners.approved[0].system}}
+
{{ typeString(item.owners.approved[0].type) }}
+
+
+ {{item.owners.approved[0].reference}} +
+ + + + + + + + + + + + + +
+
+
+
+
+
@@ -52,7 +92,8 @@
-
+ +
{{ item.amount }}
-
{{ [6, 7, 8, 9, 10, 11, 12, 13, 14].include(item.owners.approved[0].type) ? 'Miscellaneous' : 'Approved' }}
+
{{ [6, 7, 8, 9, 10, 11, 12, 13, 14].includes(item.owners.approved[0].type) ? 'Miscellaneous' : 'Approved' }}
+ + +
+ +
+
Pending...
-
+
@@ -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,57 @@ export default { files: [], parameters: {}, section: 'bankTransactionSection', + mappedTrue: 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.mappedTrue = true; }, importReceipts(){ - this.parameters = { - files: this.files - }; - this.submit(this.route('api.import_receipts.upload'), 'post', this.section, true, false); + this.mappedTrue = 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['statement_transaction_owner_type_in'] = [3,4,5,7,13,14]; + 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 +312,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 +337,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/CustomerTransactionHistorySectionComponent.vue b/resources/assets/vue/components/bookings/elements/CustomerTransactionHistorySectionComponent.vue index 026a76c5..d1448193 100644 --- a/resources/assets/vue/components/bookings/elements/CustomerTransactionHistorySectionComponent.vue +++ b/resources/assets/vue/components/bookings/elements/CustomerTransactionHistorySectionComponent.vue @@ -6,7 +6,7 @@
-
Transaction History
+
Account Statement - Transaction History
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/CustomerTransactionPreciseSectionComponent.vue b/resources/assets/vue/components/wallets/elements/CustomerTransactionPreciseSectionComponent.vue deleted file mode 100644 index 85868a2b..00000000 --- a/resources/assets/vue/components/wallets/elements/CustomerTransactionPreciseSectionComponent.vue +++ /dev/null @@ -1,174 +0,0 @@ - - diff --git a/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue b/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue index fcfba752..cc091588 100644 --- a/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue +++ b/resources/assets/vue/components/wallets/elements/CustomerTransactionSectionComponent.vue @@ -2,84 +2,65 @@
-
-
-
-
-
Transaction History
+
+
+
+
+
+
Wallet Transaction History
+
+
+
+
+
+ {{ showingPreciseAmount ? 'Showing Precise Wallet Transaction' : 'Show Precise Wallet Transaction'}} + {{ showingPreciseAmount ? 'Download Precise Transaction' : 'Download Transaction'}} +
+
+
+ + + + +
+
+
+ +
+
+
-
-
-
-
Date
-
Description
-
Incoming
-
Outgoing
-
Balance
-
- -
-
{{item.created_at}}
-
-
{{[5, 9].includes(parseFloat(item.type)) ? (Math.round((parseFloat(item.amount) + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : ''}}
-
{{[1, 11].includes(parseFloat(item.type)) ? '- ' + (Math.round((parseFloat(item.amount) + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : ''}}
-
{{remainingBalance(index)}}
-
-
-
- -
-
-
-
-
-
-
-
-
-

Nothing To Show Here

+
+ +
+
+
+
+
Top Up Records
+
+
+
+
+ +
+
+
+
+
+
-
-
-
- There is no results found, Try adjusting your filters to find what you are looking for. -
-
-
-
-
-
-
-
- -
-
-
-
-
Top Up Records
-
-
-
-
- -
-
-
-
-
-
-
-
-
-
-
-

Nothing To Show Here

+
+
+
+
+

Nothing To Show Here

+
-
-
-
- There is no results found, Try adjusting your filters to find what you are looking for. +
+
+ There is no results found, Try adjusting your filters to find what you are looking for. +
@@ -99,6 +80,10 @@ export default { id: { type: Number, required: true + }, + wallet_id: { + type: Number, + required: true } }, data(){ @@ -106,6 +91,8 @@ export default { section: 'customerTransactionSection', isLoading: true, company: null, + showingPreciseAmount: false, + showingTransactionCount: 10, attention: false } }, @@ -121,6 +108,9 @@ export default { } } }, + validations: { + showingTransactionCount: { }, + }, created(){ this.$store.dispatch('updateListQueue', {'name': this.section}); }, @@ -129,19 +119,6 @@ export default { this.isLoading = true; this.submit(route('api.company.show', this.id), 'get', this.section, false, false) }, - remainingBalance(index) { - let tempBalance = 0; - - if(this.company.wallet){ - let transactions = this.company.wallet.transactions.slice().reverse(); - transactions.slice(0, transactions.length - index).map(function(transaction) { - [1, 11].includes(transaction.type) ? tempBalance -= (transaction.amount) : tempBalance += (transaction.amount); - return tempBalance - }, 0); - } - - return (Math.round((tempBalance + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ","); - }, successHandler(response){ this.isLoading = false; this.company = response.payload.data; diff --git a/resources/assets/vue/components/wallets/elements/CustomerWalletTransactionComponent.vue b/resources/assets/vue/components/wallets/elements/CustomerWalletTransactionComponent.vue new file mode 100644 index 00000000..bf9864e1 --- /dev/null +++ b/resources/assets/vue/components/wallets/elements/CustomerWalletTransactionComponent.vue @@ -0,0 +1,35 @@ + + \ No newline at end of file diff --git a/resources/assets/vue/components/wallets/elements/WalletComponent.vue b/resources/assets/vue/components/wallets/elements/WalletComponent.vue index c7789454..aef834f1 100644 --- a/resources/assets/vue/components/wallets/elements/WalletComponent.vue +++ b/resources/assets/vue/components/wallets/elements/WalletComponent.vue @@ -35,7 +35,7 @@
Reload
- @@ -52,9 +52,18 @@
- @@ -79,6 +88,11 @@ default: false } }, + methods: { + downloadInvoiceUrl(){ + return this.route('customers.invoices') + '?marking=' + this.data.reference; + }, + }, data(){ return { reload: false, diff --git a/resources/assets/vue/general/mixins/request.js b/resources/assets/vue/general/mixins/request.js index a3c212e8..940ad464 100644 --- a/resources/assets/vue/general/mixins/request.js +++ b/resources/assets/vue/general/mixins/request.js @@ -13,19 +13,39 @@ export default { let statusCode = response.status, success = response.ok; - response.json().then(response => { + if (response.headers.get("content-type") === "application/zip") { + const fileName = response.headers.get('Content-Disposition').split('filename=')[1].replaceAll('"', ''); - if(!success){ - this.openModal(); - errorNotification ? this.$store.dispatch('createNotification', {title: response.title, message: response.message, type: 'error'}): null; - this.errorHandler(response, statusCode); return; - } + response.blob().then(response => { + if (!success) { + this.openModal(); + errorNotification ? this.$store.dispatch('createNotification', { title: response.title, message: response.message, type: 'error' }) : null; + this.errorHandler(response, statusCode); return; + } - successNotification ? this.$store.dispatch('createNotification', {title: response.title, message: response.message, type: 'success'}): null; - this.successHandler(response) + successNotification ? this.$store.dispatch('createNotification', { title: response.title, message: response.message, type: 'success' }) : null; + + const link = document.createElement('a'); + link.href = window.URL.createObjectURL(response); + link.download = fileName.trim(); + link.click(); + this.successHandler(response) + }); + } else { + response.json().then(response => { + + if (!success) { + this.openModal(); + errorNotification ? this.$store.dispatch('createNotification', { title: response.title, message: response.message, type: 'error' }) : null; + this.errorHandler(response, statusCode); return; + } + + successNotification ? this.$store.dispatch('createNotification', { title: response.title, message: response.message, type: 'success' }) : null; + this.successHandler(response) - }); + }); + } }).catch((error) => { console.log(error); this.$store.dispatch('createNotification', {title: 'Unexpected Error', message: 'An unexpected error has occurred. Try again!', type: 'error'}); diff --git a/resources/views/pages/accounting/bank-statements/index.blade.php b/resources/views/pages/accounting/bank-statements/index.blade.php index cb38d912..c70d8f0a 100644 --- a/resources/views/pages/accounting/bank-statements/index.blade.php +++ b/resources/views/pages/accounting/bank-statements/index.blade.php @@ -125,7 +125,7 @@
-
+
+ + {{-- tab for report & Analysis --}} +
+
+ +
+
+
diff --git a/resources/views/pages/customer_invoices_bulk_download.blade.php b/resources/views/pages/customer_invoices_bulk_download.blade.php new file mode 100644 index 00000000..6ddc25cf --- /dev/null +++ b/resources/views/pages/customer_invoices_bulk_download.blade.php @@ -0,0 +1,8 @@ +@extends('layouts.base_portal') +@section('inner_content') +
+
+ +
+
+@endsection diff --git a/resources/views/pages/payments.blade.php b/resources/views/pages/payments.blade.php index 0b18afbc..eb3dee76 100644 --- a/resources/views/pages/payments.blade.php +++ b/resources/views/pages/payments.blade.php @@ -1,67 +1,4 @@ @extends('layouts.base_portal') @section('inner_content') -
-
- -
-
-
-
-
-
-
-
- Complete Payments -
-
-
-
- - - -
-
-
-
-
-
- Complete Currency Orders -
-
-
-
- - - - {{----}} - {{----}} - {{----}} -
-
-
-
-
-
- Open Currency Orders -
-
-
-
- - - -
-
-
-
-
-
+ @endsection \ No newline at end of file diff --git a/resources/views/pages/pdfs/deliver_order.blade.php b/resources/views/pages/pdfs/deliver_order.blade.php index e957c0f0..d16a68f5 100644 --- a/resources/views/pages/pdfs/deliver_order.blade.php +++ b/resources/views/pages/pdfs/deliver_order.blade.php @@ -69,109 +69,8 @@

- - - - - - - - - - - - - - @php - $subtotal = "0"; - $voucherDiscount = $voucher_redemption ? bcmul((string)$voucher_redemption->value, "-1", 5) : "0"; - $displayedSubtotal = "0"; - $exactTotal = "0"; - @endphp + @include('pages.pdfs.purchase_order_table') - @foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail) - @php - $exactUnitPrice = bcdiv($transaction_detail->price, $transaction->currency_rate, 5); - $itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5); - - // Round half to even for displayed item total - $displayedItemTotal = round(bcmul($exactUnitPrice, $transaction_detail->quantity, 2), 2, PHP_ROUND_HALF_EVEN); - - $displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2); - $subtotal = bcadd($subtotal, $itemTotal, 5); - $exactTotal = bcadd($exactTotal, $displayedItemTotal, 5); - @endphp - - - - - - - - - @endforeach - - - @php - $subtotalWithDiscount = bcsub($subtotal, $voucherDiscount, 5); - @endphp - - - - - - - - - - - - @if($voucher_redemption) - - - - - - @endif - - @if($transaction->tax > 0) - - - - - - @endif - @php - // Calculate the totals with 5 decimal places - $expectedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); - - // Calculate the displayed totals with 2 decimal places - $displayedTotal = bcadd(bcadd(bcadd($displayedSubtotal, $transaction->service_charge, 2), $transaction->tax, 2), $voucherDiscount, 2); - - // Calculate the discrepancy - $discrepancy = bcsub($expectedTotal, $displayedTotal, 5); - - // Calculate the final total - $total = bcadd($expectedTotal, $discrepancy, 5); - @endphp - - - - - - - - - - - -
NoStock CodeDescriptionQuantityUnit Price (RM)Total Amount
(RM)
{{ $key + 1 }}{{ $transaction_detail->product_code }}{{ $transaction_detail->product_name }}{{ $transaction_detail->quantity }} - {{ number_format($exactUnitPrice, 2) }} - - {{ number_format($itemTotal, 2) }} -
Subtotal{{ number_format($subtotal, 2) }}
Service Charges{{ number_format($transaction->service_charge, 2) }}
Voucher ({{ $voucher_redemption->voucher->code }})-{{ number_format($voucherDiscount, 2) }}
Tax{{ number_format($transaction->tax, 2) }}
Adjustment{{number_format($discrepancy, 5)}}
Total - {{ number_format($total, 2) }} -
diff --git a/resources/views/pages/pdfs/invoice.blade.php b/resources/views/pages/pdfs/invoice.blade.php index db6c42c5..2fe00625 100644 --- a/resources/views/pages/pdfs/invoice.blade.php +++ b/resources/views/pages/pdfs/invoice.blade.php @@ -58,97 +58,8 @@
-
- - - - - - - - - - - - - @php - $subtotal = "0"; - $voucherDiscount = $voucher_redemption ? bcmul((string)$voucher_redemption->value, "-1", 2) : "0"; - $displayedSubtotal = 0; - @endphp + @include('pages.pdfs.purchase_order_table') - @foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail) - @php - $exactUnitPrice = bcdiv($transaction_detail->price, $transaction->currency_rate, 7); - $itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5); - $displayedItemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 2); - $displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2); - $subtotal = bcadd($subtotal, $itemTotal, 5); - @endphp - - - - - - - - - @endforeach - - - @php - $subtotalWithDiscount = bcsub($subtotal, $voucherDiscount, 5); - @endphp - - - - - - - - - - - - @if($voucher_redemption) - - - - - - @endif - - @if($transaction->tax > 0) - - - - - - @endif - @php - $displayedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); - $expectedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); - $discrepancy = bcsub($displayedTotal, $expectedTotal, 5); - $total = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); - @endphp - - - - - - - - - - - -
NoStock CodeDescriptionQuantityUnit Price (RM)Total Amount
(RM)
{{ $key + 1 }}{{ $transaction_detail->product_code }}{{ $transaction_detail->product_name }}{{ $transaction_detail->quantity }} - {{ number_format($exactUnitPrice, 2) }} - - {{ number_format($itemTotal, 2) }} -
Subtotal{{ number_format($subtotal, 2) }}
Service Charges{{ number_format($transaction->service_charge, 2) }}
Voucher ({{ $voucher_redemption->voucher->code }})-{{ number_format($voucherDiscount, 2) }}
Tax{{ number_format($transaction->tax, 2) }}
Adjustment{{number_format($discrepancy, 5)}}
Total - {{ number_format($total, 2) }} -

Note: All items purchased are subject to our Terms & Conditions. Please refer to our official website for more information. @@ -158,6 +69,6 @@ Please transfer the payment to:
Bank: Maybank Berhad
Account Name: CIEF Worldwide Sdn Bhd
- Account No: 564892103405
+ Account No: 568603010762
@endsection diff --git a/resources/views/pages/pdfs/purchase_order.blade.php b/resources/views/pages/pdfs/purchase_order.blade.php index 3e79691a..1f6d72d9 100644 --- a/resources/views/pages/pdfs/purchase_order.blade.php +++ b/resources/views/pages/pdfs/purchase_order.blade.php @@ -76,109 +76,8 @@
- - - - - - - - - - - - - - @php - $subtotal = "0"; - $voucherDiscount = $voucher_redemption ? bcmul((string)$voucher_redemption->value, "-1", 5) : "0"; - $displayedSubtotal = "0"; - $exactTotal = "0"; - @endphp + @include('pages.pdfs.purchase_order_table') - @foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail) - @php - $exactUnitPrice = bcdiv($transaction_detail->price, $transaction->currency_rate, 5); - $itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5); - - // Round half to even for displayed item total - $displayedItemTotal = round(bcmul($exactUnitPrice, $transaction_detail->quantity, 2), 2, PHP_ROUND_HALF_EVEN); - - $displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2); - $subtotal = bcadd($subtotal, $itemTotal, 5); - $exactTotal = bcadd($exactTotal, $displayedItemTotal, 5); - @endphp - - - - - - - - - @endforeach - - - @php - $subtotalWithDiscount = bcsub($subtotal, $voucherDiscount, 5); - @endphp - - - - - - - - - - - - @if($voucher_redemption) - - - - - - @endif - - @if($transaction->tax > 0) - - - - - - @endif - @php - // Calculate the totals with 5 decimal places - $expectedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); - - // Calculate the displayed totals with 2 decimal places - $displayedTotal = bcadd(bcadd(bcadd($displayedSubtotal, $transaction->service_charge, 2), $transaction->tax, 2), $voucherDiscount, 2); - - // Calculate the discrepancy - $discrepancy = bcsub($expectedTotal, $displayedTotal, 5); - - // Calculate the final total - $total = bcadd($expectedTotal, $discrepancy, 5); - @endphp - - - - - - - - - - - -
NoStock CodeDescriptionQuantityUnit Price (RM)Total Amount
(RM)
{{ $key + 1 }}{{ $transaction_detail->product_code }}{{ $transaction_detail->product_name }}{{ $transaction_detail->quantity }} - {{ number_format($exactUnitPrice, 2) }} - - {{ number_format($itemTotal, 2) }} -
Subtotal{{ number_format($subtotal, 2) }}
Service Charges{{ number_format($transaction->service_charge, 2) }}
Voucher ({{ $voucher_redemption->voucher->code }})-{{ number_format($voucherDiscount, 2) }}
Tax{{ number_format($transaction->tax, 2) }}
Adjustment{{number_format($discrepancy, 5)}}
Total - {{ number_format($total, 2) }} -
diff --git a/resources/views/pages/pdfs/purchase_order_table.blade.php b/resources/views/pages/pdfs/purchase_order_table.blade.php new file mode 100644 index 00000000..20fac9b8 --- /dev/null +++ b/resources/views/pages/pdfs/purchase_order_table.blade.php @@ -0,0 +1,92 @@ +
+ + + + + + + + + + + + + @php + $subtotal = "0"; + $voucherDiscount = $voucher_redemption ? bcmul((string)$voucher_redemption->value, "-1", 2) : "0"; + $displayedSubtotal = 0; + @endphp + + @foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail) + @php + $exactUnitPrice = bcdiv($transaction_detail->price, $transaction->currency_rate, 7); + $displayUnitPrice = round($exactUnitPrice, 2); + $itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5); + $displayedItemTotal = round(bcmul($displayUnitPrice, $transaction_detail->quantity, 7), 2); + $displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2); + $subtotal = bcadd($subtotal, $itemTotal, 5); + @endphp + + + + + + + + + @endforeach + + + @php + $subtotalWithDiscount = bcsub($subtotal, $voucherDiscount, 5); + @endphp + + + + + + + + + + + + @if($voucher_redemption) + + + + + + @endif + + @if($transaction->tax > 0) + + + + + + @endif + @php + $displayedTotal = bcadd(bcadd(bcadd($displayedSubtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); + $expectedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); + $discrepancy = bcsub($expectedTotal, $displayedTotal, 5); + $total = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5); + @endphp + + + + + + + + + + + +
NoStock CodeDescriptionQuantityUnit Price (RM)Total Amount
(RM)
{{ $key + 1 }}{{ $transaction_detail->product_code }}{{ $transaction_detail->product_name }}{{ $transaction_detail->quantity }} + {{ number_format($displayUnitPrice, 2) }} + + {{ number_format($displayedItemTotal, 2) }} +
Subtotal{{ number_format($displayedSubtotal, 2) }}
Service Charges{{ number_format($transaction->service_charge, 2) }}
Voucher ({{ $voucher_redemption->voucher->code }})-{{ number_format($voucherDiscount, 2) }}
Tax{{ number_format($transaction->tax, 2) }}
Adjustment{{number_format($discrepancy, 5)}}
Total + {{ number_format($total, 2) }} +
\ No newline at end of file diff --git a/resources/views/pages/wallet/transactions.blade.php b/resources/views/pages/wallet/transactions.blade.php index ce31dec6..af89c443 100644 --- a/resources/views/pages/wallet/transactions.blade.php +++ b/resources/views/pages/wallet/transactions.blade.php @@ -1,5 +1,5 @@
- +
\ No newline at end of file diff --git a/routes/accounting.php b/routes/accounting.php index c7112947..4fe0a1ad 100644 --- a/routes/accounting.php +++ b/routes/accounting.php @@ -10,7 +10,7 @@ Route::group(['prefix' => 'accounting', 'as' => 'accounting.', 'namespace' => 'A Route::put('/details/update', 'BankStatementController@update')->name('details.update'); }); - Route::post('bankStatement/{id}/details/{status}', 'ApproveDuplicateBankStatementDetailsStatusController@update')->where('status', 'approve|reject')->name('bankStatement.details.status.update'); + Route::post('bankStatement/{id}/details/{status}', 'ApproveDuplicateBankStatementDetailsStatusController@update')->where('status', 'approve|reject|pending_verification')->name('bankStatement.details.status.update'); Route::group(['prefix' => 'statement_transaction', 'as' => 'statement_transaction.'], function () { Route::post('/owner/group-approve', 'GroupApproveStatementTransactionController@approve')->name('owner.groupApprove'); diff --git a/routes/api.php b/routes/api.php index 08673517..8b4bada0 100644 --- a/routes/api.php +++ b/routes/api.php @@ -32,6 +32,8 @@ Route::group(['middleware' => 'api', 'prefix' => 'v1', 'as' => 'api.'], function Route::post('/import/upload-honey-trap', 'Imports\ImportHoneyTrapController@import')->name('honey_trap.upload'); Route::post('/import/upload-import-invoices', 'Imports\ImportStatementInvoiceController@import')->name('import_invoices.upload'); Route::post('/import/upload-import-receipt', 'Imports\ImportStatementReceiptsController@import')->name('import_receipts.upload'); + Route::post('/customers/invoices', 'Companies\BulkDownloadCustomerInvoicesController@download')->name('customers.invoices'); + Route::post('/supplier/white-form/bulk-download', 'Companies\BulkDownloadSupplierWhiteFormsController@download')->name('suppliers.white_forms'); require __DIR__ . '/company.php'; diff --git a/routes/booking.php b/routes/booking.php index 81db27b6..119d24fa 100644 --- a/routes/booking.php +++ b/routes/booking.php @@ -19,6 +19,7 @@ Route::group(['prefix' => 'booking', 'as' => 'booking.', 'namespace' => 'Booking Route::post('create', 'CreateBookingPaymentController@create')->name('create'); Route::post('{payment_id}/verification/create', 'CreatePaymentVerificationController@create')->name('verification.create'); Route::put('/{payment_id}/approval/{status}', 'ApprovePaymentVerificationController@approve')->where('status', 'approve|reject')->name('approval'); + Route::post('delete', 'ExpireBookingPaymentController@expire')->name('expire'); }); Route::group(['prefix' => '{id}/refund', 'as' => 'refund.'], function () { diff --git a/routes/transaction.php b/routes/transaction.php index 708c2439..e714d6b7 100644 --- a/routes/transaction.php +++ b/routes/transaction.php @@ -16,6 +16,7 @@ Route::group(['prefix' => 'transactions', 'namespace' => 'Transactions', 'as' => route::delete('{id}/bill/delete', 'DeletePaymentProofDocumentController@delete')->name('bill.delete'); Route::post('booking/{id}/details/update', 'CreatePurchaseOrderTransactionController@create')->name('po.create'); + Route::post('booking/{id}/details/import', 'ImportPurchaseOrderTransactionController@import')->name('po.import'); Route::get('bulk/po/{issuer_id}/{start_date}/{end_date}', 'CreateBulkPurchaseOrderTransactionController@create')->name('po.bulk.create'); diff --git a/routes/web.php b/routes/web.php index d75c96b0..7325c90b 100644 --- a/routes/web.php +++ b/routes/web.php @@ -141,6 +141,10 @@ Route::get('/purchase_orders', function () { return view('pages.purchase_orders'); })->name('purchase_orders'); +Route::get('/customers/invoices', function () { + return view('pages.customer_invoices_bulk_download'); +})->name('customers.invoices'); + Route::get('/support', function () { return view('pages.customer_support', [ 'marking' => null, @@ -227,14 +231,13 @@ Route::get('/fix_bills', function () { })->name('products.random'); Route::get('/wallet/{marking}/details', function ($marking) { - $id = \App\Models\Company::where('reference', '=', $marking)->first()->id; - return view('pages.wallet.index', ['id' => $id]); + $company = \App\Models\Company::where('reference', '=', $marking)->first(); + $id = $company->id; + $wallet_id = $company->wallets()->first()->id; + return view('pages.wallet.index', ['id' => $id, 'wallet_id' => $wallet_id]); })->name('wallet.details'); -Route::get('/wallet/{marking}/details-precise', function ($marking) { - $id = \App\Models\Company::where('reference', '=', $marking)->first()->id; - return view('pages.wallet.precise', ['id' => $id]); -})->name('wallet.details-precise'); +Route::get('/wallet/{marking}/{is_precise}/export', 'Exports\ExportCustomersWalletTransactionToExcelController@export')->name('wallet.details-export'); Route::get('/wallets', function () { return view('pages.wallet.wallets'); @@ -258,6 +261,8 @@ Route::get('/export/payment-transactions/f614e339d7058904a831aad742e24d55', 'Exp Route::get('/export/wallet-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@walletTransactions')->name('walletTransactions.export'); Route::get('/export/booking-transactions', 'Exports\ExportCustomersToExcelController@bookingTransactions')->name('export.transactions.booking'); Route::get('/export/invoice-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@invoiceTransactions')->name('invoiceTransactions.export'); +Route::get('/export/receipt-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@receiptTransactions')->name('receiptTransactions.export'); +Route::get('/export/imported-invoice-mapped', 'Exports\ExportCustomersToExcelController@importedInvoiceMapped')->name('importedInvoiceMapped.export'); Route::get('/products', function (\App\Classes\Modules\Exports\Services\ExportsProducts $exportsProducts) { $bookings = Booking::where(function($query){