From 7ca23edb9b84312d735520283e0bd4124259f05d Mon Sep 17 00:00:00 2001 From: Omair Saleh Date: Mon, 3 Apr 2023 17:48:39 +0800 Subject: [PATCH 01/69] 1. ImportBankRecordController (script for mapping that get the data from xsl file, needs to be changed to get data from db, and also to retrive data from shipping portal) 2. BankStatementController (for importing data from csv files from bank to insert into the database) --- .../Imports/Services/BankStatementImport.php | 82 ++++++++ .../Accounting/BankStatementController.php | 179 ++++++++++++++++++ app/Models/AccountStatement.php | 35 ++++ app/Models/StatementAccount.php | 23 +++ app/Models/StatementTransaction.php | 41 ++++ ...190633_create_statement_accounts_table.php | 36 ++++ ...190827_create_account_statements_table.php | 39 ++++ ...34_create_statement_transactions_table.php | 51 +++++ .../bank-statements/index.blade.php | 93 +++++++++ .../accounting/bank-statements/show.blade.php | 123 ++++++++++++ routes/web.php | 5 + 11 files changed, 707 insertions(+) create mode 100644 app/Classes/Modules/Imports/Services/BankStatementImport.php create mode 100644 app/Http/Controllers/Accounting/BankStatementController.php create mode 100644 app/Models/AccountStatement.php create mode 100644 app/Models/StatementAccount.php create mode 100644 app/Models/StatementTransaction.php create mode 100644 database/migrations/2023_03_26_190633_create_statement_accounts_table.php create mode 100644 database/migrations/2023_03_26_190827_create_account_statements_table.php create mode 100644 database/migrations/2023_03_26_190934_create_statement_transactions_table.php create mode 100644 resources/views/pages/accounting/bank-statements/index.blade.php create mode 100644 resources/views/pages/accounting/bank-statements/show.blade.php diff --git a/app/Classes/Modules/Imports/Services/BankStatementImport.php b/app/Classes/Modules/Imports/Services/BankStatementImport.php new file mode 100644 index 00000000..a552b1b0 --- /dev/null +++ b/app/Classes/Modules/Imports/Services/BankStatementImport.php @@ -0,0 +1,82 @@ +has('account_number')) { + // If the row has an account number, create a new statement account + $accountNumber = $row->get('account_number'); + $accountType = $row->get('account_type'); + $accountName = $row->get('account_name'); + $accountCurrency = $row->get('account_currency'); + + $account = StatementAccount::updateOrCreate( + ['number' => $accountNumber], + [ + 'type' => $accountType, + 'name' => $accountName, + 'currency' => $accountCurrency, + ] + ); + } else { + // Otherwise, create a new statement transaction for the current statement account + $dateFrom = $row->get('date_from'); + $dateTo = $row->get('date_to'); + $totalAmount = $row->get('total_amount'); + $beginBalance = $row->get('begin_balance'); + $endBalance = $row->get('end_balance'); + + $statement = AccountStatement::updateOrCreate( + [ + 'account_id' => $account->id, + 'date_from' => $dateFrom, + 'date_to' => $dateTo, + ], + [ + 'total_amount' => $totalAmount, + 'begin_balance' => $beginBalance, + 'end_balance' => $endBalance, + ] + ); + + $transactionDate = $row->get('transaction_date'); + $transactionTime = $row->get('transaction_time'); + $postingDate = $row->get('posting_date'); + $transactionDescription = $row->get('transaction_description'); + $transactionRef = $row->get('transaction_ref'); + $amount = $row->get('amount'); + $tellerId = $row->get('teller_id'); + $branchChannel = $row->get('branch_channel'); + $transactionCode = $row->get('transaction_code'); + + $transaction = new StatementTransaction([ + 'statement_id' => $statement->id, + 'transaction_date' => $transactionDate, + 'transaction_time' => $transactionTime, + 'posting_date' => $postingDate, + 'transaction_description' => $transactionDescription, + 'transaction_ref' => $transactionRef, + 'amount' => $amount, + 'teller_id' => $tellerId, + 'branch_channel' => $branchChannel, + 'transaction_code' => $transactionCode, + ]); + + $transaction->save(); + } + } + } +} diff --git a/app/Http/Controllers/Accounting/BankStatementController.php b/app/Http/Controllers/Accounting/BankStatementController.php new file mode 100644 index 00000000..d1df6a74 --- /dev/null +++ b/app/Http/Controllers/Accounting/BankStatementController.php @@ -0,0 +1,179 @@ +input('account'); + $search = $request->input('search'); + + $accounts = StatementAccount::all(); + + $statementsQuery = AccountStatement::query(); + + if ($selectedAccount) { + $statementsQuery->where('statement_account_id', $selectedAccount); + } + + if ($search) { + $statementsQuery->where(function ($query) use ($search) { + $query->where('date_from', 'LIKE', "%$search%") + ->orWhere('date_to', 'LIKE', "%$search%") + ->orWhere('total_amount', 'LIKE', "%$search%") + ->orWhere('begin_balance', 'LIKE', "%$search%") + ->orWhere('end_balance', 'LIKE', "%$search%"); + }); + } + + $statements = $statementsQuery->paginate(10); + + return view('pages.accounting.bank-statements.index', compact('accounts', 'selectedAccount', 'search', 'statements')); + } + + public function import(Request $request) + { + $request->validate([ + 'file' => 'required|mimes:csv,txt' + ]); + + $file = $request->file('file'); + + $collection = Excel::toCollection(null, $file, null, null, true); + + $sheet = $collection->first()->skip(1); + + $statementDetails = $sheet->first(); + + $accountNumber = $statementDetails[0]; + $accountType = $statementDetails[1]; + $accountName = $statementDetails[2]; + $accountCurrency = $statementDetails[3]; + $dateFrom = carbon::parse(str_replace(' MY (UTC+08:00)', '', $statementDetails[4])); + $dateTo = carbon::parse(str_replace(' MY (UTC+08:00)', '', $statementDetails[5])); + $totalDebit = $statementDetails[6]; + $totalCredit = $statementDetails[7]; + $beginBalance = $statementDetails[8]; + $endBalance = $statementDetails[9]; + $account = StatementAccount::updateOrCreate( + ['number' => $accountNumber], + [ + 'type' => $accountType, + 'name' => $accountName, + 'currency' => $accountCurrency, + ] + ); + + $statement = new AccountStatement([ + 'date_from' => $dateFrom, + 'date_to' => $dateTo, + 'total_amount' => $totalDebit ?: $totalCredit, + 'begin_balance' => $beginBalance, + 'end_balance' => $endBalance, + ]); + + $existingStatement = AccountStatement::where('date_from', $dateFrom) + ->where('date_to', $dateTo) + ->where('statement_account_id', $account->id) + ->first(); + + if ($existingStatement) { + return redirect()->back()->with('error', 'This statement has already been imported.'); + } + + $account->statements()->save($statement); + + $newTransactions = $sheet->map(function ($row) use ($statement, $account) { + $transactionRef = $row[15]; + $amount = $row[17] !== '-' ? ((float) str_replace(',', '', $row[17])) : (-((float) str_replace(',', '', $row[16]))); + $transactionDate = $row[10] !== '-' ? carbon::parse(str_replace(' MY (UTC+08:00)', '', $row[10]) . $row[11]) : null; + $postingDate = carbon::createFromFormat('d/M/Y H:i', str_replace(' MY (UTC+08:00)', '', $row[12]) . str_replace(' MY (UTC+08:00)', '', $row[13])); + $transactionDescription = is_numeric($row[14]) ? (int) sprintf('%.2f', $row[14]) : $row[14]; + $tellerId = $row[19]; + $branchChannel = $row[20]; + $transactionCode = $row[21]; + $endBalance = $row[22]; + $description2 = $row[25]; + $description3 = $row[26]; + $description4 = $row[27]; + $description5 = $row[28]; + $transaction = new StatementTransaction([ + 'transaction_ref' => $transactionRef, + 'amount' => $amount, + 'transaction_date' => $transactionDate, + 'posting_date' => $postingDate, + 'transaction_description' => $transactionDescription, + 'teller_id' => $tellerId, + 'branch_channel' => $branchChannel, + 'transaction_code' => $transactionCode, + 'end_balance' => $endBalance, + 'transaction_description_2' => $description2, + 'transaction_description_3' => $description3, + 'transaction_description_4' => $description4, + 'transaction_description_5' => $description5, + ]); + + // Check if the transaction already exists for this statement + $existingTransaction = StatementTransaction::where('transaction_ref', $transactionRef) + ->where('posting_date', $postingDate) + ->where('amount', $amount) + ->where('transaction_description', $transactionDescription) + ->where('teller_id', $tellerId) + ->where('branch_channel', $branchChannel) + ->where('transaction_code', $transactionCode) + ->first(); + + if (!$existingTransaction) { + $statement->transactions()->save($transaction); + } + + return $transaction; + }); + + return redirect()->back()->with('success', 'Statement imported successfully.')->with('newTransactions', $newTransactions); + } + + public function show(AccountStatement $statement, Request $request) + { + $transactions = $statement->transactions(); + + if ($request->get('transaction_filter')) { + $transactionFilter = $request->get('transaction_filter'); + $transactions = $transactions->where('transaction_description', 'LIKE', "%$transactionFilter%"); + } + + if ($request->get('from_amount_filter')) { + $fromAmountFilter = $request->get('from_amount_filter'); + $transactions = $transactions->where('amount', '>=', $fromAmountFilter); + } + + if ($request->get('to_amount_filter')) { + $toAmountFilter = $request->get('to_amount_filter'); + $transactions = $transactions->where('amount', '<=', $toAmountFilter); + } + + $transactions = $transactions->paginate(100); + + return view('pages.accounting.bank-statements.show', compact('statement', 'transactions')); + } + + public function download(AccountStatement $statement) + { + $transactions = $statement->transactions; + + $csvExporter = new \Laracsv\Export(); + $csvExporter->build($transactions, ['transaction_date', 'transaction_time', 'posting_date', 'transaction_description', 'transaction_ref', 'debit', 'credit']) + ->download($statement->date_from->format('Y-m-d') . '_' . $statement->date_to->format('Y-m-d') . '_statement.csv'); + } +} diff --git a/app/Models/AccountStatement.php b/app/Models/AccountStatement.php new file mode 100644 index 00000000..d9e53d60 --- /dev/null +++ b/app/Models/AccountStatement.php @@ -0,0 +1,35 @@ + 'date', + 'date_to' => 'date', + ]; + + public function account() + { + return $this->belongsTo(StatementAccount::class, 'statement_account_id', 'id'); + } + + public function transactions() + { + return $this->hasMany(StatementTransaction::class); + } +} diff --git a/app/Models/StatementAccount.php b/app/Models/StatementAccount.php new file mode 100644 index 00000000..741d2c5f --- /dev/null +++ b/app/Models/StatementAccount.php @@ -0,0 +1,23 @@ +hasMany(AccountStatement::class); + } +} diff --git a/app/Models/StatementTransaction.php b/app/Models/StatementTransaction.php new file mode 100644 index 00000000..a7c6a589 --- /dev/null +++ b/app/Models/StatementTransaction.php @@ -0,0 +1,41 @@ + 'datetime', + ]; + + public function statement() + { + return $this->belongsTo(AccountStatement::class, 'statement_id', 'id'); + } + + public function owner() + { + return $this->morphTo()->nullable(); + } +} diff --git a/database/migrations/2023_03_26_190633_create_statement_accounts_table.php b/database/migrations/2023_03_26_190633_create_statement_accounts_table.php new file mode 100644 index 00000000..348c5ec0 --- /dev/null +++ b/database/migrations/2023_03_26_190633_create_statement_accounts_table.php @@ -0,0 +1,36 @@ +id(); + $table->string('number')->unique(); + $table->string('type'); + $table->string('name'); + $table->string('currency'); + $table->timestamps(); + + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('statement_accounts'); + } +} diff --git a/database/migrations/2023_03_26_190827_create_account_statements_table.php b/database/migrations/2023_03_26_190827_create_account_statements_table.php new file mode 100644 index 00000000..43945692 --- /dev/null +++ b/database/migrations/2023_03_26_190827_create_account_statements_table.php @@ -0,0 +1,39 @@ +id(); + $table->unsignedBigInteger('statement_account_id'); + $table->date('date_from'); + $table->date('date_to'); + $table->float('total_amount'); + $table->float('begin_balance'); + $table->float('end_balance'); + $table->timestamps(); + + $table->foreign('statement_account_id')->references('id')->on('statement_accounts'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('account_statements'); + } +} diff --git a/database/migrations/2023_03_26_190934_create_statement_transactions_table.php b/database/migrations/2023_03_26_190934_create_statement_transactions_table.php new file mode 100644 index 00000000..bdb90b53 --- /dev/null +++ b/database/migrations/2023_03_26_190934_create_statement_transactions_table.php @@ -0,0 +1,51 @@ +id(); + $table->unsignedBigInteger('account_statement_id'); + $table->dateTime('transaction_date')->nullable(); + $table->dateTime('posting_date'); + $table->string('transaction_description')->nullable(); + $table->string('transaction_description_2')->nullable(); + $table->string('transaction_description_3')->nullable(); + $table->string('transaction_description_4')->nullable(); + $table->string('transaction_description_5')->nullable(); + $table->string('transaction_ref')->nullable(); + $table->float('amount', 15, 2)->unsigned(false); + $table->string('teller_id')->nullable(); + $table->string('branch_channel'); + $table->string('transaction_code'); + $table->string('owner_system')->nullable(); + $table->string('owner_type')->nullable(); + $table->unsignedBigInteger('owner_id')->nullable(); + $table->string('invoice_reference')->nullable(); + $table->string('payment_reference')->nullable(); + $table->timestamps(); + + $table->foreign('account_statement_id')->references('id')->on('account_statements'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('statement_transactions'); + } +} diff --git a/resources/views/pages/accounting/bank-statements/index.blade.php b/resources/views/pages/accounting/bank-statements/index.blade.php new file mode 100644 index 00000000..b22cec53 --- /dev/null +++ b/resources/views/pages/accounting/bank-statements/index.blade.php @@ -0,0 +1,93 @@ +@extends('layouts.base_portal') +@section('inner_content') +
+
+
+
+
Import Bank Statement
+ +
+ @if (session('success')) +
+ {{ session('success') }} +
+ @endif + @if (session('error')) +
+ {{ session('error') }} +
+ @endif + +
+ @csrf +
+ + +
+ +
+
+
+
+
+
+
Bank Statements
+ +
+
+
+ + +
+ + Clear +
+ +
+
+ + +
+ +
+ + + + + + + + + + + + + + + @foreach($statements as $statement) + + + + + + + + + + @endforeach + +
AccountDate FromDate ToTotal AmountBegin BalanceEnd BalanceActions
{{ $statement->account->name }} ({{ $statement->account->number }}){{ $statement->date_from->format('d-m-Y') }}{{ $statement->date_to->format('d-m-Y') }}{{ $statement->total_amount }}{{ $statement->begin_balance }}{{ $statement->end_balance }} + View +
+ {{ $statements->links() }} +
+
+
+
+
+@endsection diff --git a/resources/views/pages/accounting/bank-statements/show.blade.php b/resources/views/pages/accounting/bank-statements/show.blade.php new file mode 100644 index 00000000..31a50f2d --- /dev/null +++ b/resources/views/pages/accounting/bank-statements/show.blade.php @@ -0,0 +1,123 @@ +@extends('layouts.base_portal') +@section('inner_content') +
+
+
+
Statement: {{ $statement->date_from->format('M d, Y') }} - {{ $statement->date_to->format('M d, Y') }}
+

Account: {{ $statement->account->name }} ({{ $statement->account->number }})

+{{--

Total Debit: {{ number_format($statement->total_debit, 2) }}

--}} +{{--

Total Credit: {{ number_format($statement->total_credit, 2) }}

--}} +

Beginning Balance: {{ number_format($statement->begin_balance, 2) }}

+

Ending Balance: {{ number_format($statement->end_balance, 2) }}

+
+
+ +
+
+
Transactions
+
+
+
+ + +
+
+ + +
+
+ + +
+
+ +
+ + + + + + + + + + + + + + @foreach ($transactions as $transaction) + @php + $from = $transaction->transaction_description_2; + $type = ''; + $paymentMethod = ''; + + if(!$transaction->transaction_description_2){ + $from = $transaction->transaction_description; + } + + if(str_contains($transaction->transaction_description_3, 'FPX')){ + $paymentMethod = 'FPX'; + } + + if(str_contains($transaction->transaction_description_3, 'A/C')){ + $paymentMethod = 'Bank Transfer'; + } + + if(str_contains($transaction->transaction_description_3, 'IBFT')){ + $paymentMethod = 'Bank Transfer'; + } + + if(str_contains($transaction->transaction_description_3, 'FOREIGN TT')){ + $paymentMethod = 'International Transfer'; + } + + if($transaction->amount > 0) { + $type = 'Sale'; + } + + if($transaction->amount < 0 && str_contains($transaction->transaction_description_3, 'ESI')) { + $type = 'Statutory Payment'; + } + + if($transaction->amount < 0 && str_contains($transaction->transaction_description_3, 'ESI')) { + $type = 'Statutory Payment'; + } + + if($transaction->amount < 0 && str_contains($transaction->transaction_description, 'DR DUITNOW S/CHRG')) { + $type = 'Bank Charge'; + $paymentMethod = 'Bank Deduction'; + + } + + if($transaction->amount < 0 && str_contains($transaction->transaction_description, 'CMS - DR CORP CHG')) { + $type = 'Card Payment'; + $paymentMethod = 'Card'; + } + + if($transaction->amount < 0 && str_contains($transaction->transaction_description_3, 'ELECTRONIC')) { + $type = 'Electric Bill'; + } + + @endphp + + + + + + + + + + @endforeach + +
DatetimeFromTypePayment MethodDebitCredit
{{ $transaction->posting_date->format('d-m-Y') }}{{ $transaction->posting_date->format('g:i A') }}{{ $from }}{{ $type }}{{ $paymentMethod }}{{ $transaction->amount < 0 ? number_format($transaction->amount, 2) : 0.00}}{{ $transaction->amount > 0 ? number_format($transaction->amount, 2) : 0.00}}
+
+
+
+ {{ $transactions->appends(request()->query())->links() }} +
+
+@endsection + diff --git a/routes/web.php b/routes/web.php index df705655..0566f5c3 100644 --- a/routes/web.php +++ b/routes/web.php @@ -1,5 +1,6 @@ with('paymentMethods', $paymentMethods); })->name('currency_rate.history'); +Route::get('/statements', [BankStatementController::class, 'index'])->name('statements.index'); +Route::post('/statements/import', [BankStatementController::class, 'import'])->name('statements.import'); +Route::get('/statements/{statement}', [BankStatementController::class, 'show'])->name('statements.show'); +Route::get('/statements/{statement}/download', 'StatementController@download')->name('statements.download'); Route::get('/bank-record', 'Imports\ImportBankRecordController@import'); From 1954cfa63c6445793d7de82b8827acc44de870f0 Mon Sep 17 00:00:00 2001 From: Dillon Date: Tue, 11 Apr 2023 04:14:53 +0800 Subject: [PATCH 02/69] Mapping of bank statement records with exchange and shipping portal + UI to edit the details --- .../General/Eloquent/Filters/DateIn.php | 19 ++ .../Filters/HasAccountStatementId.php | 22 ++ .../General/Eloquent/Filters/PayFor.php | 19 ++ .../General/Eloquent/Filters/PayForIn.php | 19 ++ .../Jobs/CreateBankStatementDetails.php | 40 +++ .../ListBankStatementDetailsLogic.php | 52 ++++ .../UpdateBankStatementDetailLogic.php | 68 +++++ .../BankStatementDetailObject.php | 46 +++ .../CreateBankStatementDetailsProcessor.php | 218 +++++++++++++ .../Services/FetchesBankStatementDetails.php | 34 +++ .../Services/ListsBankStatementDetails.php | 32 ++ .../Services/UpdatesBankStatementDetails.php | 25 ++ .../Accounting/BankStatementController.php | 287 +++++++++++++++++- .../Resources/BankStatementDetailResource.php | 37 +++ app/Models/StatementTransaction.php | 9 +- app/Models/StatementTransactionsDetail.php | 30 ++ config/perfexcrm.php | 2 +- ...e_statement_transactions_details_table.php | 43 +++ .../EditSingleItemInListComponent.vue | 90 ++++++ .../StatementTransactionsDetailsComponent.vue | 227 ++++++++++++++ .../bank-statements/details.blade.php | 8 + .../bank-statements/index.blade.php | 2 +- routes/accounting.php | 10 + routes/api.php | 2 + routes/web.php | 4 + 25 files changed, 1326 insertions(+), 19 deletions(-) create mode 100644 app/Classes/General/Eloquent/Filters/DateIn.php create mode 100644 app/Classes/General/Eloquent/Filters/HasAccountStatementId.php create mode 100644 app/Classes/General/Eloquent/Filters/PayFor.php create mode 100644 app/Classes/General/Eloquent/Filters/PayForIn.php create mode 100644 app/Classes/Jobs/CreateBankStatementDetails.php create mode 100644 app/Classes/Modules/Accounting/ControllersLogic/ListBankStatementDetailsLogic.php create mode 100644 app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php create mode 100644 app/Classes/Modules/Accounting/DataTransferObjects/BankStatementDetailObject.php create mode 100644 app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php create mode 100644 app/Classes/Modules/Accounting/Services/FetchesBankStatementDetails.php create mode 100644 app/Classes/Modules/Accounting/Services/ListsBankStatementDetails.php create mode 100644 app/Classes/Modules/Accounting/Services/UpdatesBankStatementDetails.php create mode 100644 app/Http/Resources/BankStatementDetailResource.php create mode 100644 app/Models/StatementTransactionsDetail.php create mode 100644 database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php create mode 100644 resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue create mode 100644 resources/assets/vue/components/accounting/sections/StatementTransactionsDetailsComponent.vue create mode 100644 resources/views/pages/accounting/bank-statements/details.blade.php create mode 100644 routes/accounting.php diff --git a/app/Classes/General/Eloquent/Filters/DateIn.php b/app/Classes/General/Eloquent/Filters/DateIn.php new file mode 100644 index 00000000..b1704eb4 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/DateIn.php @@ -0,0 +1,19 @@ +whereIn('date', $value); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/HasAccountStatementId.php b/app/Classes/General/Eloquent/Filters/HasAccountStatementId.php new file mode 100644 index 00000000..05cfe9d8 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/HasAccountStatementId.php @@ -0,0 +1,22 @@ +whereHas('statementTransaction', function ($query) use ($value) { + $query->where('account_statement_id', $value); + }); + } +} diff --git a/app/Classes/General/Eloquent/Filters/PayFor.php b/app/Classes/General/Eloquent/Filters/PayFor.php new file mode 100644 index 00000000..b8a2ba75 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/PayFor.php @@ -0,0 +1,19 @@ +where('pay_for', $value); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/PayForIn.php b/app/Classes/General/Eloquent/Filters/PayForIn.php new file mode 100644 index 00000000..3fe98f00 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/PayForIn.php @@ -0,0 +1,19 @@ +whereIn('pay_for', $value); + } + +} diff --git a/app/Classes/Jobs/CreateBankStatementDetails.php b/app/Classes/Jobs/CreateBankStatementDetails.php new file mode 100644 index 00000000..9d12c6ba --- /dev/null +++ b/app/Classes/Jobs/CreateBankStatementDetails.php @@ -0,0 +1,40 @@ +statement = $statement; + } + + public function handle() + { + (App()->make(CreateBankStatementDetailsProcessor::class))->execute($this->statement); + } + + public function delay($delay) + { + // Add delay in seconds to the job + $this->delay = $delay; + return $this; + } +} diff --git a/app/Classes/Modules/Accounting/ControllersLogic/ListBankStatementDetailsLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/ListBankStatementDetailsLogic.php new file mode 100644 index 00000000..10cffba1 --- /dev/null +++ b/app/Classes/Modules/Accounting/ControllersLogic/ListBankStatementDetailsLogic.php @@ -0,0 +1,52 @@ + 'Retrieved Bank Statement Details', + 'message' => 'You have successfully retrieved a Bank Statement Details' + ]; + } + + + /** @var ListsBankStatementDetails */ + private $listsBankStatementDetails; + + /** + * ListBankStatementDetailsLogic constructor. + * @param ListsBankStatementDetails $listsBankStatementDetails + */ + public function __construct(ListsBankStatementDetails $listsBankStatementDetails) + { + $this->listsBankStatementDetails = $listsBankStatementDetails; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + $query = $this->listsBankStatementDetails->execute($this->listsBankStatementDetails->deserializeFilters($request->input('filters'))); + + return $this->collectionResponse(BankStatementDetailResource::collection($query)); + } + +} diff --git a/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php new file mode 100644 index 00000000..bbdeef35 --- /dev/null +++ b/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php @@ -0,0 +1,68 @@ + 'Updated Bank Statement Transactions Details', + 'message' => 'You have successfully updated the Bank Statement Transactions Details' + ]; + } + + // /** @var CanUpdateCompany */ + // private $canUpdateCompany; + + /** @var UpdatesBankStatementDetails */ + private $updatesBankStatementDetails; + + /** @var FetchesBankStatementDetails */ + private $fetchesBankStatementDetails; + + /** + * UpdateBankStatementDetailLogic constructor. + * @param UpdatesBankStatementDetails $updatesBankStatementDetails + * @param FetchesBankStatementDetails $fetchesBankStatementDetails + */ + public function __construct(UpdatesBankStatementDetails $updatesBankStatementDetails, FetchesBankStatementDetails $fetchesBankStatementDetails) + { + $this->updatesBankStatementDetails = $updatesBankStatementDetails; + $this->fetchesBankStatementDetails = $fetchesBankStatementDetails; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + $object = new BankStatementDetailObject($request->input('pay_for'), $request->input('system_references')); + + // $this->canUpdateCompany->passes($object); + + $query = $this->fetchesBankStatementDetails->execute(['id' => $request->route('id')]); + + $query = $this->updatesBankStatementDetails->execute($query, $object); + + return $this->resourceResponse(new BankStatementDetailResource($query)); + } + +} diff --git a/app/Classes/Modules/Accounting/DataTransferObjects/BankStatementDetailObject.php b/app/Classes/Modules/Accounting/DataTransferObjects/BankStatementDetailObject.php new file mode 100644 index 00000000..8da675d6 --- /dev/null +++ b/app/Classes/Modules/Accounting/DataTransferObjects/BankStatementDetailObject.php @@ -0,0 +1,46 @@ +pay_for = $pay_for; + $this->system_references = $system_references; + } + + /** + * @return string + */ + public function getPayFor(): string + { + return $this->pay_for; + } + + /** + * @return string + */ + public function getSystemReferences(): string + { + return $this->system_references; + } +} diff --git a/app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php new file mode 100644 index 00000000..4514682c --- /dev/null +++ b/app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php @@ -0,0 +1,218 @@ +transactions(); + $transactions = $transactions->get(); + + $headers = [ + 'Date', + 'Bank', + 'Description', + 'Credit', + 'Debit', + 'Pay For', + 'System', + 'System Reference', + 'Human Reference', + 'Multiple', + 'Match?', + 'System Amount' + ]; + + $branches = [ + 0 => 'MBB Cyber', + 1 => 'MBB SS2', + ]; + + $yes = 'Yes'; + $no = 'No'; + + $table = ''; + $count = 0; + + foreach ($transactions as $row) { + $isExist = StatementTransactionsDetail::where('statement_transactions_id', $row->id)->first(); + + if ($isExist) { + continue; + } + + $count++; + $credit = 0.00; + $debit = 0.00; + + $date = new DateTime($row['posting_date']); + $description = $row['transaction_description_2']; + + if($row['amount'] < 0){ + $debit = (float) $row['amount']; + } + else{ + $credit = (float) $row['amount']; + } + + $creditTransactions = []; + $debitTransactions = []; + + $system = []; + $systemReference = null; + $systemAmount = null; + + if($credit){ + $creditTransactions = $this->getTransactions($date, $credit, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + foreach ($creditTransactions as $transaction) { + $systemReference[] = $transaction->owner instanceof Booking ? $transaction->owner->marking : $transaction->bill_no; + $systemAmount[] = $transaction->amount; + $system[] = 'EXCHANGE'; + } + + $creditTransactions = $this->getTransactions($date, $credit, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + foreach ($creditTransactions as $transaction) { + $systemReference[] = $transaction->owner instanceof Booking ? $transaction->owner->marking : $transaction->bill_no; + $systemAmount[] = $transaction->amount; + $system[] = 'EXCHANGE'; + } + + $creditTransactions = $this->getTransactionsFromShippingPortal($credit, $this->getDateRange($row['posting_date'])); + foreach ($creditTransactions as $transaction) { + $systemReference[] = $transaction['order']['reference']; + $systemAmount[] = $transaction['amount']; + $system[] = 'SHIPPING'; + } + } + + if($debit){ + $debitTransactions = $this->getTransactions($date, $debit, null, null, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], Group::class); + + if(!count($debitTransactions)) { + foreach (['YSN', 'HCK', 'ATVANTIC', 'HIGH HILL'] as $reference){ + if(str_contains($description, $reference)) { + $paymentDate = date('Y-m-d', strtotime('+1 day', strtotime($row['posting_date']))); //$date->addDays(1)->format('Y-m-d'); + + if($reference = 'ATVANTIC'){ + $paymentDate = date('Y-m-d', strtotime($row['posting_date']));//$date->format('Y-m-d'); + } + $issuer = Company::where('name', 'like', '%'.$reference.'%')->get()->pluck('id'); + $debitTransactions = Group::whereIn('issuer', $issuer)->whereDate('created_at', $paymentDate)->get(); + break; + } + } + + } + + foreach ($debitTransactions as $transaction) { + $systemReference[] = $transaction->reference; + $systemAmount[] = $transaction->amount; + $system[] = 'EXCHANGE'; + } + } + + + $multiple = count($creditTransactions) + count($debitTransactions) > 1 ? $yes : $no; + + $systemReference = $systemReference ? implode(',', $systemReference) : null; + $systemAmount = $systemAmount ? implode(',', $systemAmount) : null; + $system = $system ? implode(',', $system) : null; + + $matches = $systemReference == $row['remarkreferences'] ? $yes : $no; + + $statementTransactionsDetail = new StatementTransactionsDetail([ + 'date' => $date, + 'statement_transactions_id' => $row->id, + // 'description' => is_null($description) ? "" : $description, + // 'credit' => $credit, + // 'debit' => $debit, + 'pay_for' => is_null($system) ? "" : $system, + 'system_references' => is_null($systemReference) ? "" : $systemReference, + // 'remark_references' => is_null($row['remarkreferences']) ? "" : $row['remarkreferences'], + // 'is_multiple' => $multiple == "Yes" ? 1 : 0, + // 'is_matches' => $matches == "Yes" ? 1 : 0, + 'system_amounts'=> is_null($systemAmount) ? "" : $systemAmount, + ]); + + $statementTransactionsDetail->save(); + + // if($count == 10){ + // break; + // } + } + } + + private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $model = Transaction::class) { + $query = $model::whereIn('status', $statuses) + ->where(function ($query) use ($ownerType, $paymentMethod, $type) { + if ($ownerType) { + $query->where('owner_type', $ownerType); + } + + if ($paymentMethod) { + $query->where('payment_method', '!=', $paymentMethod); + } + + if ($type) { + $query->where('type', $type); + } + }) + ->whereDate('created_at', $date->format('Y-m-d')) + ->where('amount', '>', ($amount - 0.01)) + ->where('amount', '<', ($amount + 0.01)); + + return $query->get(); + } + + private function getTransactionsFromShippingPortal($amount, $dateRange){ + try{ + + $client = new \GuzzleHttp\Client(); + $response = $client->request('GET', 'https://izyim.cief-malaysia.com/public/api/v1/list?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2],"type":2,"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).'}'); + $body = $response->getBody(); + $data = json_decode($body, true); + $payload = $data['payload']; + $transactions2 = $payload['data']; + return $transactions2; + }catch(\Exception $exception){ + Log::error($exception); + return []; + } + } + + private function getDateRange(string $dateStr) { + // Create a DateTime object from the input string + $date = strtotime($dateStr); + + // Get the first day of the month + $today = date('Y-m-d', $date); + + // Get the first day of the next month + $nextDay = date('Y-m-d', strtotime('+1 day', $date)); + + return [ + 'start_date' => $today, + 'end_date' => $nextDay, + ]; + } +} diff --git a/app/Classes/Modules/Accounting/Services/FetchesBankStatementDetails.php b/app/Classes/Modules/Accounting/Services/FetchesBankStatementDetails.php new file mode 100644 index 00000000..37a3d785 --- /dev/null +++ b/app/Classes/Modules/Accounting/Services/FetchesBankStatementDetails.php @@ -0,0 +1,34 @@ +repository = $repository; + } + + + /** + * @return Builder + */ + public function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} diff --git a/app/Classes/Modules/Accounting/Services/ListsBankStatementDetails.php b/app/Classes/Modules/Accounting/Services/ListsBankStatementDetails.php new file mode 100644 index 00000000..2f1290e5 --- /dev/null +++ b/app/Classes/Modules/Accounting/Services/ListsBankStatementDetails.php @@ -0,0 +1,32 @@ +repository = $repository; + } + + + /** + * @return Builder + */ + public function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} diff --git a/app/Classes/Modules/Accounting/Services/UpdatesBankStatementDetails.php b/app/Classes/Modules/Accounting/Services/UpdatesBankStatementDetails.php new file mode 100644 index 00000000..2e4ad23c --- /dev/null +++ b/app/Classes/Modules/Accounting/Services/UpdatesBankStatementDetails.php @@ -0,0 +1,25 @@ +system_references = $object->getSystemReferences(); + $model->pay_for = $object->getPayFor(); + + return $this->handler($model); + } +} diff --git a/app/Http/Controllers/Accounting/BankStatementController.php b/app/Http/Controllers/Accounting/BankStatementController.php index d1df6a74..3146e13d 100644 --- a/app/Http/Controllers/Accounting/BankStatementController.php +++ b/app/Http/Controllers/Accounting/BankStatementController.php @@ -2,15 +2,32 @@ namespace App\Http\Controllers\Accounting; +use App\Classes\Jobs\CreateBankStatementDetails; +use App\Classes\Modules\Accounting\ControllersLogic\ListBankStatementDetailsLogic; +use App\Classes\Modules\Accounting\ControllersLogic\UpdateBankStatementDetailLogic; use App\Classes\Modules\Imports\Services\BankStatementImport; -use App\Http\Controllers\Controller; -use DateTime; -use Illuminate\Http\Request; -use Illuminate\Support\Carbon; -use Maatwebsite\Excel\Facades\Excel; +use App\Classes\Modules\Imports\Services\ImportsBankRecord; +use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\ValueObjects\Constants\PaymentMethodType; +use App\Classes\ValueObjects\Constants\TransactionType; use App\Models\StatementAccount; use App\Models\AccountStatement; use App\Models\StatementTransaction; +use App\Models\Booking; +use App\Models\Company; +use App\Models\Group; +use App\Models\StatementTransactionsDetail; +use App\Models\Transaction; +use App\Models\Wallet; +use App\Http\Controllers\Controller; +use Maatwebsite\Excel\Facades\Excel; +use Illuminate\Http\JsonResponse; +use Illuminate\Http\Request; +use Illuminate\Support\Carbon; +use DateTime; + + +use PhpOffice\PhpSpreadsheet\Shared\Date; class BankStatementController extends Controller { @@ -44,6 +61,7 @@ class BankStatementController extends Controller public function import(Request $request) { + $request->validate([ 'file' => 'required|mimes:csv,txt' ]); @@ -83,17 +101,21 @@ class BankStatementController extends Controller 'end_balance' => $endBalance, ]); - $existingStatement = AccountStatement::where('date_from', $dateFrom) - ->where('date_to', $dateTo) - ->where('statement_account_id', $account->id) - ->first(); + // $existingStatement = AccountStatement::where('date_from', $dateFrom) + // ->where('date_to', $dateTo) + // ->where('statement_account_id', $account->id) + // ->first(); - if ($existingStatement) { - return redirect()->back()->with('error', 'This statement has already been imported.'); - } + // // if ($existingStatement) { + // // return redirect()->back()->with('error', 'This statement has already been imported.'); + // // } $account->statements()->save($statement); + CreateBankStatementDetails::dispatch($statement)->delay(30); + + + // $account = null; $newTransactions = $sheet->map(function ($row) use ($statement, $account) { $transactionRef = $row[15]; $amount = $row[17] !== '-' ? ((float) str_replace(',', '', $row[17])) : (-((float) str_replace(',', '', $row[16]))); @@ -141,13 +163,17 @@ class BankStatementController extends Controller return $transaction; }); + + // dd(json_encode($newTransactions)); return redirect()->back()->with('success', 'Statement imported successfully.')->with('newTransactions', $newTransactions); } public function show(AccountStatement $statement, Request $request) { $transactions = $statement->transactions(); - + // $account = $statement->account(); + // dd(json_encode($account->where('id', '>=', 1)->first())); + // dd(json_encode($transactions->where('id', '>=', 1)->first())); if ($request->get('transaction_filter')) { $transactionFilter = $request->get('transaction_filter'); $transactions = $transactions->where('transaction_description', 'LIKE', "%$transactionFilter%"); @@ -163,9 +189,11 @@ class BankStatementController extends Controller $transactions = $transactions->where('amount', '<=', $toAmountFilter); } - $transactions = $transactions->paginate(100); + // $transactions = $transactions->paginate(100); + $transactions = $transactions->get(); + echo $this->process3_merged($transactions); - return view('pages.accounting.bank-statements.show', compact('statement', 'transactions')); + //return view('pages.accounting.bank-statements.show', compact('statement', 'transactions')); } public function download(AccountStatement $statement) @@ -176,4 +204,233 @@ class BankStatementController extends Controller $csvExporter->build($transactions, ['transaction_date', 'transaction_time', 'posting_date', 'transaction_description', 'transaction_ref', 'debit', 'credit']) ->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 + { + return $logic->execute($request); + } + + public function update(Request $request, UpdateBankStatementDetailLogic $logic): JsonResponse + { + return $logic->execute($request); + } + + private function process3_merged($transactions){ + + // $statement = $transactions[0]->statement(); + // dd(json_encode($statement->first())); + + $headers = [ + 'Date', + 'Bank', + 'Description', + 'Credit', + 'Debit', + 'Pay For', + 'System', + 'System Reference', + 'Human Reference', + 'Multiple', + 'Match?', + 'System Amount' + ]; + + $branches = [ + 0 => 'MBB Cyber', + 1 => 'MBB SS2', + ]; + + $yes = 'Yes'; + $no = 'No'; + + $table = '
'.implode('', $headers).'
'; + $count = 0; + + foreach ($transactions as $row) { + $isExist = StatementTransactionsDetail::where('statement_transactions_id', $row->id)->first(); + + if ($isExist) { + continue; + } + + $count++; + $credit = 0.00; + $debit = 0.00; + + // dd(json_encode($row['posting_date'])); + $date = new DateTime($row['posting_date']); + $description = $row['transaction_description_2']; + + if($row['amount'] < 0){ + $debit = (float) $row['amount']; + } + else{ + $credit = (float) $row['amount']; + } + + $creditTransactions = []; + $debitTransactions = []; + + $system = ''; + $systemReference = null; + $systemAmount = null; + + if($credit){ + $creditTransactions = $this->getTransactions($date, $credit, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + foreach ($creditTransactions as $transaction) { + $systemReference[] = $transaction->owner instanceof Booking ? $transaction->owner->marking : $transaction->bill_no; + $systemAmount[] = $transaction->amount; + $system[] = 'EXCHANGE'; + } + + $creditTransactions = $this->getTransactions($date, $credit, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + foreach ($creditTransactions as $transaction) { + $systemReference[] = $transaction->owner instanceof Booking ? $transaction->owner->marking : $transaction->bill_no; + $systemAmount[] = $transaction->amount; + $system[] = 'EXCHANGE'; + } + + $creditTransactions = $this->getTransactionsFromShippingPortal($credit, $this->getDateRange($row['posting_date'])); + foreach ($creditTransactions as $transaction) { + $systemReference[] = $transaction['order']['reference']; + $systemAmount[] = $transaction['amount']; + $system[] = 'SHIPPING'; + } + } + + if($debit){ + $debitTransactions = $this->getTransactions($date, $debit, null, null, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], Group::class); + + if(!count($debitTransactions)) { + foreach (['YSN', 'HCK', 'ATVANTIC', 'HIGH HILL'] as $reference){ + if(str_contains($description, $reference)) { + $paymentDate = date('Y-m-d', strtotime('+1 day', strtotime($row['posting_date']))); //$date->addDays(1)->format('Y-m-d'); + + if($reference = 'ATVANTIC'){ + $paymentDate = date('Y-m-d', strtotime($row['posting_date']));//$date->format('Y-m-d'); + } + $issuer = Company::where('name', 'like', '%'.$reference.'%')->get()->pluck('id'); + $debitTransactions = Group::whereIn('issuer', $issuer)->whereDate('created_at', $paymentDate)->get(); + break; + } + } + + } + + foreach ($debitTransactions as $transaction) { + $systemReference[] = $transaction->reference; + $systemAmount[] = $transaction->amount; + $system[] = 'EXCHANGE'; + } + } + + + $multiple = count($creditTransactions) + count($debitTransactions) > 1 ? $yes : $no; + + + + + + $systemReference = $systemReference ? implode(',', $systemReference) : null; + $systemAmount = $systemAmount ? implode(',', $systemAmount) : null; + + $matches = $systemReference == $row['remarkreferences'] ? $yes : $no; + + $table .= ' + + + + + + + + + + + + + '; + + //AccountStatement + // $row->statement()->first()->id) + + $statementTransactionsDetail = new StatementTransactionsDetail([ + 'date' => $date, + 'statement_transactions_id' => $row->id, + 'description' => is_null($description) ? "" : $description, + 'credit' => $credit, + 'debit' => $debit, + 'pay_for' => $system, + 'system_references' => is_null($systemReference) ? "" : $systemReference, + 'remark_references' => is_null($row['remarkreferences']) ? "" : $row['remarkreferences'], + 'is_multiple' => $multiple == "Yes" ? 1 : 0, + 'is_matches' => $matches == "Yes" ? 1 : 0, + 'system_amounts'=> is_null($systemAmount) ? "" : $systemAmount, + ]); + + $statementTransactionsDetail->save(); + + if($count == 10){ + break; + } + } + + $table .= '
'.implode('', $headers).'
'.$date->format('d-m-Y').'branch'.$description.''.$credit.''.$debit.''.$row['pay_for'].''.$system.''.$systemReference.''.$row['remarkreferences'].''.$multiple.''.$matches.''.$systemAmount.'
'; + + return $table; + } + + private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $model = Transaction::class) { + $query = $model::whereIn('status', $statuses) + ->where(function ($query) use ($ownerType, $paymentMethod, $type) { + if ($ownerType) { + $query->where('owner_type', $ownerType); + } + + if ($paymentMethod) { + $query->where('payment_method', '!=', $paymentMethod); + } + + if ($type) { + $query->where('type', $type); + } + }) + ->whereDate('created_at', $date->format('Y-m-d')) + ->where('amount', '>', ($amount - 0.01)) + ->where('amount', '<', ($amount + 0.01)); + + return $query->get(); + } + + private function getDateRange(string $dateStr) { + // Create a DateTime object from the input string + $date = strtotime($dateStr); + + // Get the first day of the month + $today = date('Y-m-d', $date); + + // Get the first day of the next month + $nextDay = date('Y-m-d', strtotime('+1 day', $date)); + + return [ + 'start_date' => $today, + 'end_date' => $nextDay, + ]; + } + + private function getTransactionsFromShippingPortal($amount, $dateRange){ + + $client = new \GuzzleHttp\Client(); + $response = $client->request('GET', 'https://izyim.cief-malaysia.com/public/api/v1/list?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2],"type":2,"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).'}'); + $body = $response->getBody(); + $data = json_decode($body, true); + $payload = $data['payload']; + $transactions2 = $payload['data']; + // $filters = [ + // ['field' => 'created_at', 'value' => '2023-03-01 08:07:00'], + // ]; + // $transactions2 = $this->getTransactions3($transactions2, $filters); + return $transactions2; + } + } diff --git a/app/Http/Resources/BankStatementDetailResource.php b/app/Http/Resources/BankStatementDetailResource.php new file mode 100644 index 00000000..5533728c --- /dev/null +++ b/app/Http/Resources/BankStatementDetailResource.php @@ -0,0 +1,37 @@ + $this->id, + 'account_number' => $this->statementTransaction->statement->account->number, + 'account_type' => $this->statementTransaction->statement->account->type, + 'account_name' => $this->statementTransaction->statement->account->name, + 'account_statement_id' => $this->statementTransaction->statement->id, + 'account_statement_date_from' => $this->statementTransaction->statement->date_from, + 'account_statement_date_to' => $this->statementTransaction->statement->date_to, + 'date' => $this->date, + 'description' => $this->description, + 'amount' => $this->statementTransaction->amount, + 'pay_for' => $this->pay_for, + 'system_references' => $this->system_references, + 'transaction_description_1' => $this->statementTransaction->transaction_description, + 'transaction_description_2' => $this->statementTransaction->transaction_description_2, + 'transaction_description_3' => $this->statementTransaction->transaction_description_3, + 'transaction_description_4' => $this->statementTransaction->transaction_description_4, + 'transaction_description_5' => $this->statementTransaction->transaction_description_5, + ]; + } +} diff --git a/app/Models/StatementTransaction.php b/app/Models/StatementTransaction.php index a7c6a589..7d089b65 100644 --- a/app/Models/StatementTransaction.php +++ b/app/Models/StatementTransaction.php @@ -10,7 +10,7 @@ class StatementTransaction extends Model use HasFactory; protected $fillable = [ - 'statement_id', + 'account_statement_id', 'transaction_date', 'posting_date', 'transaction_description', @@ -31,11 +31,16 @@ class StatementTransaction extends Model public function statement() { - return $this->belongsTo(AccountStatement::class, 'statement_id', 'id'); + return $this->belongsTo(AccountStatement::class, 'account_statement_id', 'id'); } public function owner() { return $this->morphTo()->nullable(); } + + public function statementDetail() + { + return $this->hasMany(StatementTransactionsDetail::class); + } } diff --git a/app/Models/StatementTransactionsDetail.php b/app/Models/StatementTransactionsDetail.php new file mode 100644 index 00000000..1a0ee6ba --- /dev/null +++ b/app/Models/StatementTransactionsDetail.php @@ -0,0 +1,30 @@ +belongsTo(StatementTransaction::class, 'statement_transactions_id', 'id'); + } +} diff --git a/config/perfexcrm.php b/config/perfexcrm.php index f67040f5..7644a489 100644 --- a/config/perfexcrm.php +++ b/config/perfexcrm.php @@ -1,7 +1,7 @@ env('PERFEXCRM_BASE_URL', 'http://192.168.1.100:8084'), //cief todo: Update crm api domain here + 'base_url' => env('PERFEXCRM_BASE_URL', 'http://192.168.1.101:8084'), //cief todo: Update crm api domain here 'api_key' => env('PERFEXCRM_API_KEY', 'eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJ1c2VyIjoiZXhjaGFuZ2Utc2hpcHBpbmciLCJuYW1lIjoiRXhjaGFuZ2UgYW5kIFNoaXBwaW5nIFBvcnRhbCIsIkFQSV9USU1FIjoxNjc1MDg2Mzc4fQ.SGAHWl5stcxQwp55TBGeMRVTdlLeWQIbsvJh5glyVvs'), 'is_enabled' => env('PERFEXCRM_IS_ENABLED', 'true'), ]; diff --git a/database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php b/database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php new file mode 100644 index 00000000..41abbd96 --- /dev/null +++ b/database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php @@ -0,0 +1,43 @@ +id(); + $table->date('date'); + $table->unsignedBigInteger('statement_transactions_id'); + $table->foreign('statement_transactions_id')->references('id')->on('statement_transactions'); + // $table->string('description'); + // $table->decimal('credit', 8, 2); + // $table->decimal('debit', 8, 2); + $table->string('pay_for'); + $table->string('system_references'); + // $table->string('remark_references'); + // $table->boolean('is_multiple')->default(false); + // $table->boolean('is_matches')->default(false); + $table->string('system_amounts'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('statement_transactions_details'); + } +} diff --git a/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue b/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue new file mode 100644 index 00000000..b160eeac --- /dev/null +++ b/resources/assets/vue/components/accounting/elements/EditSingleItemInListComponent.vue @@ -0,0 +1,90 @@ + + + diff --git a/resources/assets/vue/components/accounting/sections/StatementTransactionsDetailsComponent.vue b/resources/assets/vue/components/accounting/sections/StatementTransactionsDetailsComponent.vue new file mode 100644 index 00000000..db9e25e1 --- /dev/null +++ b/resources/assets/vue/components/accounting/sections/StatementTransactionsDetailsComponent.vue @@ -0,0 +1,227 @@ + + diff --git a/resources/views/pages/accounting/bank-statements/details.blade.php b/resources/views/pages/accounting/bank-statements/details.blade.php new file mode 100644 index 00000000..6c0caf8b --- /dev/null +++ b/resources/views/pages/accounting/bank-statements/details.blade.php @@ -0,0 +1,8 @@ +@extends('layouts.base_portal') +@section('inner_content') +
+
+ +
+
+@endsection diff --git a/resources/views/pages/accounting/bank-statements/index.blade.php b/resources/views/pages/accounting/bank-statements/index.blade.php index b22cec53..2269ad94 100644 --- a/resources/views/pages/accounting/bank-statements/index.blade.php +++ b/resources/views/pages/accounting/bank-statements/index.blade.php @@ -78,7 +78,7 @@ {{ $statement->begin_balance }} {{ $statement->end_balance }} - View + View @endforeach diff --git a/routes/accounting.php b/routes/accounting.php new file mode 100644 index 00000000..acc75e35 --- /dev/null +++ b/routes/accounting.php @@ -0,0 +1,10 @@ + 'accounting', 'as' => 'accounting.', 'namespace' => 'Accounting'], function () { + Route::group(['prefix' => 'statements/{id}', 'as' => 'statement.'], function () { + Route::get('/details', 'BankStatementController@fetch')->name('details'); + Route::put('/details/update', 'BankStatementController@update')->name('details.update'); + }); +}); diff --git a/routes/api.php b/routes/api.php index 6c17a107..9af79578 100644 --- a/routes/api.php +++ b/routes/api.php @@ -54,6 +54,8 @@ Route::group(['middleware' => 'api', 'prefix' => 'v1', 'as' => 'api.'], function require __DIR__ . '/wallet.php'; + require __DIR__ . '/accounting.php'; + // require __DIR__ . '/rate.php'; // require __DIR__ . '/receipt.php'; diff --git a/routes/web.php b/routes/web.php index 0566f5c3..9c06273e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -557,9 +557,13 @@ Route::get('/currency-rate-history', function () { Route::get('/statements', [BankStatementController::class, 'index'])->name('statements.index'); Route::post('/statements/import', [BankStatementController::class, 'import'])->name('statements.import'); +Route::get('/statements/{statement}/details', function ($statement) { + return view('pages.accounting.bank-statements.details', ['statement' => $statement]); +})->name('statements.transactions.details'); Route::get('/statements/{statement}', [BankStatementController::class, 'show'])->name('statements.show'); Route::get('/statements/{statement}/download', 'StatementController@download')->name('statements.download'); Route::get('/bank-record', 'Imports\ImportBankRecordController@import'); + From 6aa2ed53c76e9968b7083f21a35864a11c106d69 Mon Sep 17 00:00:00 2001 From: Dillon Date: Wed, 12 Apr 2023 05:02:48 +0800 Subject: [PATCH 03/69] Allow user to upload statement repeatedly + master list page + rerun mapping + bug fixes --- .../CreateBankStatementDetailsProcessor.php | 30 +++++++--------- .../Accounting/BankStatementController.php | 35 ++++++++++++++----- app/Models/StatementTransaction.php | 1 + app/Models/StatementTransactionsDetail.php | 4 +-- ...34_create_statement_transactions_table.php | 1 + ...e_statement_transactions_details_table.php | 4 +-- .../StatementTransactionsDetailsComponent.vue | 7 +++- .../bank-statements/index.blade.php | 15 ++++++-- routes/web.php | 1 + 9 files changed, 63 insertions(+), 35 deletions(-) diff --git a/app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php index 4514682c..a978fb33 100644 --- a/app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php +++ b/app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php @@ -55,9 +55,8 @@ class CreateBankStatementDetailsProcessor $count = 0; foreach ($transactions as $row) { - $isExist = StatementTransactionsDetail::where('statement_transactions_id', $row->id)->first(); - - if ($isExist) { + $existingRecord = StatementTransactionsDetail::where('statement_transaction_id', $row->id)->first(); + if ($existingRecord && $existingRecord->pay_for != "") { continue; } @@ -140,21 +139,16 @@ class CreateBankStatementDetailsProcessor $matches = $systemReference == $row['remarkreferences'] ? $yes : $no; - $statementTransactionsDetail = new StatementTransactionsDetail([ - 'date' => $date, - 'statement_transactions_id' => $row->id, - // 'description' => is_null($description) ? "" : $description, - // 'credit' => $credit, - // 'debit' => $debit, - 'pay_for' => is_null($system) ? "" : $system, - 'system_references' => is_null($systemReference) ? "" : $systemReference, - // 'remark_references' => is_null($row['remarkreferences']) ? "" : $row['remarkreferences'], - // 'is_multiple' => $multiple == "Yes" ? 1 : 0, - // 'is_matches' => $matches == "Yes" ? 1 : 0, - 'system_amounts'=> is_null($systemAmount) ? "" : $systemAmount, - ]); - - $statementTransactionsDetail->save(); + StatementTransactionsDetail::updateOrCreate( + ['statement_transaction_id' => $row->id], + [ + 'date' => $date, + 'pay_for' => is_null($system) ? "" : $system, + 'system_references' => is_null($systemReference) ? "" : $systemReference, + 'system_amounts'=> is_null($systemAmount) ? "" : $systemAmount, + 'remark_references'=> is_null($row['remarkreferences']) ? "" : $row['remarkreferences'], + ] + ); // if($count == 10){ // break; diff --git a/app/Http/Controllers/Accounting/BankStatementController.php b/app/Http/Controllers/Accounting/BankStatementController.php index 3146e13d..5352d196 100644 --- a/app/Http/Controllers/Accounting/BankStatementController.php +++ b/app/Http/Controllers/Accounting/BankStatementController.php @@ -24,6 +24,7 @@ use Maatwebsite\Excel\Facades\Excel; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Carbon; +use Illuminate\Support\Facades\Log; use DateTime; @@ -93,13 +94,22 @@ class BankStatementController extends Controller ] ); - $statement = new AccountStatement([ - 'date_from' => $dateFrom, - 'date_to' => $dateTo, - 'total_amount' => $totalDebit ?: $totalCredit, - 'begin_balance' => $beginBalance, - 'end_balance' => $endBalance, - ]); + $statement = AccountStatement::where('date_from', $dateFrom) + ->where('date_to', $dateTo) + ->where('total_amount', $totalDebit ?: $totalCredit,) + ->where('begin_balance', $beginBalance) + ->where('end_balance', $endBalance)->first(); + + + if(!$statement){ + $statement = new AccountStatement([ + 'date_from' => $dateFrom, + 'date_to' => $dateTo, + 'total_amount' => $totalDebit ?: $totalCredit, + 'begin_balance' => $beginBalance, + 'end_balance' => $endBalance, + ]); + } // $existingStatement = AccountStatement::where('date_from', $dateFrom) // ->where('date_to', $dateTo) @@ -154,6 +164,7 @@ class BankStatementController extends Controller ->where('teller_id', $tellerId) ->where('branch_channel', $branchChannel) ->where('transaction_code', $transactionCode) + ->where('end_balance', $endBalance) ->first(); if (!$existingTransaction) { @@ -168,6 +179,12 @@ class BankStatementController extends Controller return redirect()->back()->with('success', 'Statement imported successfully.')->with('newTransactions', $newTransactions); } + public function rerun(AccountStatement $statement, Request $request) + { + CreateBankStatementDetails::dispatch($statement)->delay(30); + return redirect()->back()->with('success', 'Rerun triggered successfully'); + } + public function show(AccountStatement $statement, Request $request) { $transactions = $statement->transactions(); @@ -247,7 +264,7 @@ class BankStatementController extends Controller $count = 0; foreach ($transactions as $row) { - $isExist = StatementTransactionsDetail::where('statement_transactions_id', $row->id)->first(); + $isExist = StatementTransactionsDetail::where('statement_transaction_id', $row->id)->first(); if ($isExist) { continue; @@ -356,7 +373,7 @@ class BankStatementController extends Controller $statementTransactionsDetail = new StatementTransactionsDetail([ 'date' => $date, - 'statement_transactions_id' => $row->id, + 'statement_transaction_id' => $row->id, 'description' => is_null($description) ? "" : $description, 'credit' => $credit, 'debit' => $debit, diff --git a/app/Models/StatementTransaction.php b/app/Models/StatementTransaction.php index 7d089b65..6b789f08 100644 --- a/app/Models/StatementTransaction.php +++ b/app/Models/StatementTransaction.php @@ -23,6 +23,7 @@ class StatementTransaction extends Model 'teller_id', 'branch_channel', 'transaction_code', + 'end_balance', ]; protected $casts = [ diff --git a/app/Models/StatementTransactionsDetail.php b/app/Models/StatementTransactionsDetail.php index 1a0ee6ba..074f5304 100644 --- a/app/Models/StatementTransactionsDetail.php +++ b/app/Models/StatementTransactionsDetail.php @@ -11,7 +11,7 @@ class StatementTransactionsDetail extends Model protected $fillable = [ 'date', - 'statement_transactions_id', + 'statement_transaction_id', // 'description', // 'credit', // 'debit', @@ -25,6 +25,6 @@ class StatementTransactionsDetail extends Model public function statementTransaction() { - return $this->belongsTo(StatementTransaction::class, 'statement_transactions_id', 'id'); + return $this->belongsTo(StatementTransaction::class, 'statement_transaction_id', 'id'); } } diff --git a/database/migrations/2023_03_26_190934_create_statement_transactions_table.php b/database/migrations/2023_03_26_190934_create_statement_transactions_table.php index bdb90b53..95ad3571 100644 --- a/database/migrations/2023_03_26_190934_create_statement_transactions_table.php +++ b/database/migrations/2023_03_26_190934_create_statement_transactions_table.php @@ -28,6 +28,7 @@ class CreateStatementTransactionsTable extends Migration $table->string('teller_id')->nullable(); $table->string('branch_channel'); $table->string('transaction_code'); + $table->string('end_balance')->nullable(); $table->string('owner_system')->nullable(); $table->string('owner_type')->nullable(); $table->unsignedBigInteger('owner_id')->nullable(); diff --git a/database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php b/database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php index 41abbd96..3bc547fd 100644 --- a/database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php +++ b/database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php @@ -16,8 +16,8 @@ class CreateStatementTransactionsDetailsTable extends Migration Schema::create('statement_transactions_details', function (Blueprint $table) { $table->id(); $table->date('date'); - $table->unsignedBigInteger('statement_transactions_id'); - $table->foreign('statement_transactions_id')->references('id')->on('statement_transactions'); + $table->unsignedBigInteger('statement_transaction_id'); + $table->foreign('statement_transaction_id')->references('id')->on('statement_transactions'); // $table->string('description'); // $table->decimal('credit', 8, 2); // $table->decimal('debit', 8, 2); diff --git a/resources/assets/vue/components/accounting/sections/StatementTransactionsDetailsComponent.vue b/resources/assets/vue/components/accounting/sections/StatementTransactionsDetailsComponent.vue index db9e25e1..9a5e0058 100644 --- a/resources/assets/vue/components/accounting/sections/StatementTransactionsDetailsComponent.vue +++ b/resources/assets/vue/components/accounting/sections/StatementTransactionsDetailsComponent.vue @@ -133,7 +133,7 @@ export default { days: [] }, - filters: {'per_page': 10, order_by: {column: 'id', DESC: true}, 'has_account_statement_id': this.statement}, + filters: {'per_page': 10, order_by: {column: 'id', DESC: true}}, page: 1, days: [], @@ -183,6 +183,11 @@ export default { }, created(){ this.setDecoratorDefault(); + if (this.statement === 0) { + this.filters = { 'per_page': 10, order_by: {column: 'id', DESC: true} }; + } else { + this.filters = { 'per_page': 10, order_by: {column: 'id', DESC: true}, 'has_account_statement_id': this.statement }; + } this.$store.dispatch('updateListQueue', {'name': this.section, 'page': 1, 'filters': this.filters}); }, methods: { diff --git a/resources/views/pages/accounting/bank-statements/index.blade.php b/resources/views/pages/accounting/bank-statements/index.blade.php index 2269ad94..f41813db 100644 --- a/resources/views/pages/accounting/bank-statements/index.blade.php +++ b/resources/views/pages/accounting/bank-statements/index.blade.php @@ -31,8 +31,14 @@
-
Bank Statements
- + @if (session('message')) +
+ {{ session('message') }} +
+ @endif +
Bank Statements + View All +
@@ -65,7 +71,7 @@ Total Amount Begin Balance End Balance - Actions + Actions @@ -80,6 +86,9 @@ View + + Rerun + @endforeach diff --git a/routes/web.php b/routes/web.php index 9c06273e..d7117c89 100644 --- a/routes/web.php +++ b/routes/web.php @@ -561,6 +561,7 @@ Route::get('/statements/{statement}/details', function ($statement) { return view('pages.accounting.bank-statements.details', ['statement' => $statement]); })->name('statements.transactions.details'); Route::get('/statements/{statement}', [BankStatementController::class, 'show'])->name('statements.show'); +Route::get('/statements/{statement}/rerun', [BankStatementController::class, 'rerun'])->name('statements.rerun'); Route::get('/statements/{statement}/download', 'StatementController@download')->name('statements.download'); Route::get('/bank-record', 'Imports\ImportBankRecordController@import'); From 4a6ae598faf4a3e61de2fe4fb6ee8abee8dcf6f7 Mon Sep 17 00:00:00 2001 From: Omair Saleh Date: Tue, 18 Apr 2023 12:07:27 +0800 Subject: [PATCH 04/69] fix and update the functionality and the ui for accounting automation --- .../General/Eloquent/Filters/IsMapped.php | 20 + .../Eloquent/Filters/IsMappedWithMultiple.php | 20 + .../General/Eloquent/Filters/MaxAmount.php | 20 + .../General/Eloquent/Filters/MinAmount.php | 20 + .../Filters/StatementTransactionAccountId.php | 22 + .../StatementTransactionOwnerStatusIn.php | 22 + .../StatementTransactionOwnerTypeIn.php | 22 + ... CreateBankStatementTransactionOwners.php} | 19 +- .../ImportBankStatementLogic.php | 147 ++++++ .../ListBankStatementTransactionsLogic.php | 53 ++ .../UpdateBankStatementDetailLogic.php | 2 - .../CreateBankStatementDetailsProcessor.php | 212 -------- ...ankStatementTransactionOwnersProcessor.php | 275 +++++++++++ .../Services/FetchesBankStatementDetails.php | 8 +- .../Services/ListsBankStatementDetails.php | 8 +- .../ListsBankStatementTransactions.php | 33 ++ .../Services/UpdatesBankStatementDetails.php | 6 +- .../DataTransferObjects/FileObject.php | 6 +- .../Services/ConvertsBase64ToFile.php | 4 +- .../ValueObjects/Constants/FileType.php | 3 +- .../StatementTransactionOwnerType.php | 37 ++ .../Accounting/BankStatementController.php | 162 ++---- .../Resources/BankStatementDetailResource.php | 37 -- .../BankStatementTransactionOwnerResource.php | 65 +++ .../BankStatementTransactionResource.php | 36 ++ app/Models/StatementTransaction.php | 17 +- ...tail.php => StatementTransactionOwner.php} | 22 +- ...34_create_statement_transactions_table.php | 5 - ...ate_statement_transaction_owners_table.php | 44 ++ ...e_statement_transactions_details_table.php | 43 -- .../StatementTransactionComponent.vue | 93 ++++ .../forms/ImportStatementFormComponent.vue | 59 +++ .../sections/TransactionsMappingComponent.vue | 185 +++++++ .../bank-statements/bank_statement.blade.php | 12 + .../bank-statements/index.blade.php | 446 +++++++++++++---- .../bank-statements/indexv2.blade.php | 461 ++++++++++++++++++ routes/accounting.php | 2 + routes/web.php | 6 +- 38 files changed, 2088 insertions(+), 566 deletions(-) create mode 100644 app/Classes/General/Eloquent/Filters/IsMapped.php create mode 100644 app/Classes/General/Eloquent/Filters/IsMappedWithMultiple.php create mode 100644 app/Classes/General/Eloquent/Filters/MaxAmount.php create mode 100644 app/Classes/General/Eloquent/Filters/MinAmount.php create mode 100644 app/Classes/General/Eloquent/Filters/StatementTransactionAccountId.php create mode 100644 app/Classes/General/Eloquent/Filters/StatementTransactionOwnerStatusIn.php create mode 100644 app/Classes/General/Eloquent/Filters/StatementTransactionOwnerTypeIn.php rename app/Classes/Jobs/{CreateBankStatementDetails.php => CreateBankStatementTransactionOwners.php} (53%) create mode 100644 app/Classes/Modules/Accounting/ControllersLogic/ImportBankStatementLogic.php create mode 100644 app/Classes/Modules/Accounting/ControllersLogic/ListBankStatementTransactionsLogic.php delete mode 100644 app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php create mode 100644 app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php create mode 100644 app/Classes/Modules/Accounting/Services/ListsBankStatementTransactions.php create mode 100644 app/Classes/ValueObjects/Constants/StatementTransactionOwnerType.php delete mode 100644 app/Http/Resources/BankStatementDetailResource.php create mode 100644 app/Http/Resources/BankStatementTransactionOwnerResource.php create mode 100644 app/Http/Resources/BankStatementTransactionResource.php rename app/Models/{StatementTransactionsDetail.php => StatementTransactionOwner.php} (50%) create mode 100644 database/migrations/2023_04_07_212512_create_statement_transaction_owners_table.php delete mode 100644 database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php create mode 100644 resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue create mode 100644 resources/assets/vue/components/accounting/forms/ImportStatementFormComponent.vue create mode 100644 resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue create mode 100644 resources/views/pages/accounting/bank-statements/bank_statement.blade.php create mode 100644 resources/views/pages/accounting/bank-statements/indexv2.blade.php diff --git a/app/Classes/General/Eloquent/Filters/IsMapped.php b/app/Classes/General/Eloquent/Filters/IsMapped.php new file mode 100644 index 00000000..12282d3b --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/IsMapped.php @@ -0,0 +1,20 @@ +whereHas('owners') : $builder->whereDoesntHave('owners'); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/IsMappedWithMultiple.php b/app/Classes/General/Eloquent/Filters/IsMappedWithMultiple.php new file mode 100644 index 00000000..066fa6ef --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/IsMappedWithMultiple.php @@ -0,0 +1,20 @@ +has('owners', '>', 1) : $builder->has('owners', '=',1); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/MaxAmount.php b/app/Classes/General/Eloquent/Filters/MaxAmount.php new file mode 100644 index 00000000..3a0476c8 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/MaxAmount.php @@ -0,0 +1,20 @@ +where('amount', '<=', $value); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/MinAmount.php b/app/Classes/General/Eloquent/Filters/MinAmount.php new file mode 100644 index 00000000..52b72636 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/MinAmount.php @@ -0,0 +1,20 @@ +where('amount', '>=', $value); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionAccountId.php b/app/Classes/General/Eloquent/Filters/StatementTransactionAccountId.php new file mode 100644 index 00000000..b07bede9 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionAccountId.php @@ -0,0 +1,22 @@ +whereHas('account', function ($query) use ($value) { + $query->where('statement_accounts.id', $value); + }); + } +} diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerStatusIn.php b/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerStatusIn.php new file mode 100644 index 00000000..e309cd4d --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerStatusIn.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->whereIn('status', $value); + }); + } + +} diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerTypeIn.php b/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerTypeIn.php new file mode 100644 index 00000000..e23d0bcc --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionOwnerTypeIn.php @@ -0,0 +1,22 @@ +whereHas('owners', function ($query) use ($value) { + return $query->whereIn('type', $value); + }); + } + +} diff --git a/app/Classes/Jobs/CreateBankStatementDetails.php b/app/Classes/Jobs/CreateBankStatementTransactionOwners.php similarity index 53% rename from app/Classes/Jobs/CreateBankStatementDetails.php rename to app/Classes/Jobs/CreateBankStatementTransactionOwners.php index 9d12c6ba..e7797210 100644 --- a/app/Classes/Jobs/CreateBankStatementDetails.php +++ b/app/Classes/Jobs/CreateBankStatementTransactionOwners.php @@ -2,33 +2,20 @@ namespace App\Classes\Jobs; -use App\Classes\Modules\Accounting\Processors\CreateBankStatementDetailsProcessor; +use App\Classes\Modules\Accounting\Processors\CreateBankStatementTransactionOwnersProcessor; use Illuminate\Bus\Queueable; use Illuminate\Contracts\Queue\ShouldQueue; use Illuminate\Foundation\Bus\Dispatchable; use Illuminate\Queue\InteractsWithQueue; use Illuminate\Queue\SerializesModels; -use App\Models\AccountStatement; -class CreateBankStatementDetails implements ShouldQueue +class CreateBankStatementTransactionOwners implements ShouldQueue { use Dispatchable, InteractsWithQueue, Queueable, SerializesModels; - /** @var AccountStatement $statement*/ - private $statement; - - /** - * CreateBankStatementDetails constructor. - * @param AccountStatement $statement - */ - public function __construct(AccountStatement $statement) - { - $this->statement = $statement; - } - public function handle() { - (App()->make(CreateBankStatementDetailsProcessor::class))->execute($this->statement); + (App()->make(CreateBankStatementTransactionOwnersProcessor::class))->execute(); } public function delay($delay) diff --git a/app/Classes/Modules/Accounting/ControllersLogic/ImportBankStatementLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/ImportBankStatementLogic.php new file mode 100644 index 00000000..b7f737da --- /dev/null +++ b/app/Classes/Modules/Accounting/ControllersLogic/ImportBankStatementLogic.php @@ -0,0 +1,147 @@ + 'Import Bank Statement Transactions Details', + 'message' => 'You have successfully updated the Bank Statement Transactions Details' + ]; + } + + + /** + * @param Request $request + * @return JsonResponse + * @throws MalformedRequestException + */ + public function logic(Request $request) : 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); + + $statementDetails = $sheet->first(); + + $accountNumber = $statementDetails[0]; + $accountType = $statementDetails[1]; + $accountName = $statementDetails[2]; + $accountCurrency = $statementDetails[3]; + $dateFrom = carbon::parse(str_replace(' MY (UTC+08:00)', '', $statementDetails[4])); + $dateTo = carbon::parse(str_replace(' MY (UTC+08:00)', '', $statementDetails[5])); + $totalDebit = $statementDetails[6]; + $totalCredit = $statementDetails[7]; + $beginBalance = $statementDetails[8]; + $endBalance = $statementDetails[9]; + $account = StatementAccount::updateOrCreate( + ['number' => $accountNumber], + [ + 'type' => $accountType, + 'name' => $accountName, + 'currency' => $accountCurrency, + ] + ); + + $statement = AccountStatement::where('date_from', $dateFrom) + ->where('date_to', $dateTo) + ->where('total_amount', $totalDebit ?: $totalCredit,) + ->where('begin_balance', $beginBalance) + ->where('end_balance', $endBalance)->first(); + + + if(!$statement){ + $statement = new AccountStatement([ + 'date_from' => $dateFrom, + 'date_to' => $dateTo, + 'total_amount' => $totalDebit ?: $totalCredit, + 'begin_balance' => $beginBalance, + 'end_balance' => $endBalance, + ]); + } + + $account->statements()->save($statement); + + CreateBankStatementTransactionOwners::dispatch($statement); + + + $sheet->map(function ($row) use ($statement, $account) { + $transactionRef = $row[15]; + $amount = $row[17] !== '-' ? ((float) str_replace(',', '', $row[17])) : (-((float) str_replace(',', '', $row[16]))); + $transactionDate = $row[10] !== '-' ? carbon::parse(str_replace(' MY (UTC+08:00)', '', $row[10]) . $row[11]) : null; + $postingDate = carbon::createFromFormat('d/M/Y H:i', str_replace(' MY (UTC+08:00)', '', $row[12]) . str_replace(' MY (UTC+08:00)', '', $row[13])); + $transactionDescription = is_numeric($row[14]) ? (int) sprintf('%.2f', $row[14]) : $row[14]; + $tellerId = $row[19]; + $branchChannel = $row[20]; + $transactionCode = $row[21]; + $endBalance = $row[22]; + $description2 = $row[25]; + $description3 = $row[26]; + $description4 = $row[27]; + $description5 = $row[28]; + $transaction = new StatementTransaction([ + 'transaction_ref' => $transactionRef, + 'amount' => $amount, + 'transaction_date' => $transactionDate, + 'posting_date' => $postingDate, + 'transaction_description' => $transactionDescription, + 'teller_id' => $tellerId, + 'branch_channel' => $branchChannel, + 'transaction_code' => $transactionCode, + 'end_balance' => $endBalance, + 'transaction_description_2' => $description2, + 'transaction_description_3' => $description3, + 'transaction_description_4' => $description4, + 'transaction_description_5' => $description5, + ]); + + // Check if the transaction already exists for this statement + $existingTransaction = StatementTransaction::where('transaction_ref', $transactionRef) + ->where('posting_date', $postingDate) + ->where('amount', $amount) + ->where('transaction_description', $transactionDescription) + ->where('teller_id', $tellerId) + ->where('branch_channel', $branchChannel) + ->where('transaction_code', $transactionCode) + ->where('end_balance', $endBalance) + ->first(); + + if (!$existingTransaction) { + $statement->transactions()->save($transaction); + } + + return $transaction; + }); + } + + + + return $this->response([]); + + } + +} diff --git a/app/Classes/Modules/Accounting/ControllersLogic/ListBankStatementTransactionsLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/ListBankStatementTransactionsLogic.php new file mode 100644 index 00000000..3d2b8273 --- /dev/null +++ b/app/Classes/Modules/Accounting/ControllersLogic/ListBankStatementTransactionsLogic.php @@ -0,0 +1,53 @@ + 'Retrieved Bank Statement Transactions', + 'message' => 'You have successfully retrieved a Bank Statement Transactions' + ]; + } + + + /** @var ListsBankStatementTransactions */ + private $listsBankStatementTransactions; + + /** + * @param ListsBankStatementTransactions $listsBankStatementTransactions + */ + public function __construct(ListsBankStatementTransactions $listsBankStatementTransactions) + { + $this->listsBankStatementTransactions = $listsBankStatementTransactions; + } + + /** + * @param Request $request + * @return JsonResponse + * @throws ErrorException + */ + public function logic(Request $request) : JsonResponse + { + $query = $this->listsBankStatementTransactions->execute($this->listsBankStatementTransactions->deserializeFilters($request->input('filters'))); + + return $this->collectionResponse(BankStatementTransactionResource::collection($query)); + } + +} diff --git a/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php index bbdeef35..f29bd627 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/UpdateBankStatementDetailLogic.php @@ -56,8 +56,6 @@ class UpdateBankStatementDetailLogic extends AbstractControllerLogic { $object = new BankStatementDetailObject($request->input('pay_for'), $request->input('system_references')); - // $this->canUpdateCompany->passes($object); - $query = $this->fetchesBankStatementDetails->execute(['id' => $request->route('id')]); $query = $this->updatesBankStatementDetails->execute($query, $object); diff --git a/app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php deleted file mode 100644 index a978fb33..00000000 --- a/app/Classes/Modules/Accounting/Processors/CreateBankStatementDetailsProcessor.php +++ /dev/null @@ -1,212 +0,0 @@ -transactions(); - $transactions = $transactions->get(); - - $headers = [ - 'Date', - 'Bank', - 'Description', - 'Credit', - 'Debit', - 'Pay For', - 'System', - 'System Reference', - 'Human Reference', - 'Multiple', - 'Match?', - 'System Amount' - ]; - - $branches = [ - 0 => 'MBB Cyber', - 1 => 'MBB SS2', - ]; - - $yes = 'Yes'; - $no = 'No'; - - $table = ''; - $count = 0; - - foreach ($transactions as $row) { - $existingRecord = StatementTransactionsDetail::where('statement_transaction_id', $row->id)->first(); - if ($existingRecord && $existingRecord->pay_for != "") { - continue; - } - - $count++; - $credit = 0.00; - $debit = 0.00; - - $date = new DateTime($row['posting_date']); - $description = $row['transaction_description_2']; - - if($row['amount'] < 0){ - $debit = (float) $row['amount']; - } - else{ - $credit = (float) $row['amount']; - } - - $creditTransactions = []; - $debitTransactions = []; - - $system = []; - $systemReference = null; - $systemAmount = null; - - if($credit){ - $creditTransactions = $this->getTransactions($date, $credit, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); - foreach ($creditTransactions as $transaction) { - $systemReference[] = $transaction->owner instanceof Booking ? $transaction->owner->marking : $transaction->bill_no; - $systemAmount[] = $transaction->amount; - $system[] = 'EXCHANGE'; - } - - $creditTransactions = $this->getTransactions($date, $credit, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); - foreach ($creditTransactions as $transaction) { - $systemReference[] = $transaction->owner instanceof Booking ? $transaction->owner->marking : $transaction->bill_no; - $systemAmount[] = $transaction->amount; - $system[] = 'EXCHANGE'; - } - - $creditTransactions = $this->getTransactionsFromShippingPortal($credit, $this->getDateRange($row['posting_date'])); - foreach ($creditTransactions as $transaction) { - $systemReference[] = $transaction['order']['reference']; - $systemAmount[] = $transaction['amount']; - $system[] = 'SHIPPING'; - } - } - - if($debit){ - $debitTransactions = $this->getTransactions($date, $debit, null, null, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], Group::class); - - if(!count($debitTransactions)) { - foreach (['YSN', 'HCK', 'ATVANTIC', 'HIGH HILL'] as $reference){ - if(str_contains($description, $reference)) { - $paymentDate = date('Y-m-d', strtotime('+1 day', strtotime($row['posting_date']))); //$date->addDays(1)->format('Y-m-d'); - - if($reference = 'ATVANTIC'){ - $paymentDate = date('Y-m-d', strtotime($row['posting_date']));//$date->format('Y-m-d'); - } - $issuer = Company::where('name', 'like', '%'.$reference.'%')->get()->pluck('id'); - $debitTransactions = Group::whereIn('issuer', $issuer)->whereDate('created_at', $paymentDate)->get(); - break; - } - } - - } - - foreach ($debitTransactions as $transaction) { - $systemReference[] = $transaction->reference; - $systemAmount[] = $transaction->amount; - $system[] = 'EXCHANGE'; - } - } - - - $multiple = count($creditTransactions) + count($debitTransactions) > 1 ? $yes : $no; - - $systemReference = $systemReference ? implode(',', $systemReference) : null; - $systemAmount = $systemAmount ? implode(',', $systemAmount) : null; - $system = $system ? implode(',', $system) : null; - - $matches = $systemReference == $row['remarkreferences'] ? $yes : $no; - - StatementTransactionsDetail::updateOrCreate( - ['statement_transaction_id' => $row->id], - [ - 'date' => $date, - 'pay_for' => is_null($system) ? "" : $system, - 'system_references' => is_null($systemReference) ? "" : $systemReference, - 'system_amounts'=> is_null($systemAmount) ? "" : $systemAmount, - 'remark_references'=> is_null($row['remarkreferences']) ? "" : $row['remarkreferences'], - ] - ); - - // if($count == 10){ - // break; - // } - } - } - - private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $model = Transaction::class) { - $query = $model::whereIn('status', $statuses) - ->where(function ($query) use ($ownerType, $paymentMethod, $type) { - if ($ownerType) { - $query->where('owner_type', $ownerType); - } - - if ($paymentMethod) { - $query->where('payment_method', '!=', $paymentMethod); - } - - if ($type) { - $query->where('type', $type); - } - }) - ->whereDate('created_at', $date->format('Y-m-d')) - ->where('amount', '>', ($amount - 0.01)) - ->where('amount', '<', ($amount + 0.01)); - - return $query->get(); - } - - private function getTransactionsFromShippingPortal($amount, $dateRange){ - try{ - - $client = new \GuzzleHttp\Client(); - $response = $client->request('GET', 'https://izyim.cief-malaysia.com/public/api/v1/list?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2],"type":2,"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).'}'); - $body = $response->getBody(); - $data = json_decode($body, true); - $payload = $data['payload']; - $transactions2 = $payload['data']; - return $transactions2; - }catch(\Exception $exception){ - Log::error($exception); - return []; - } - } - - private function getDateRange(string $dateStr) { - // Create a DateTime object from the input string - $date = strtotime($dateStr); - - // Get the first day of the month - $today = date('Y-m-d', $date); - - // Get the first day of the next month - $nextDay = date('Y-m-d', strtotime('+1 day', $date)); - - return [ - 'start_date' => $today, - 'end_date' => $nextDay, - ]; - } -} diff --git a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php new file mode 100644 index 00000000..f3d61595 --- /dev/null +++ b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php @@ -0,0 +1,275 @@ +whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); +// })->get(); + + $transactions = StatementTransaction::whereDoesntHave('owners')->where('amount', '<', 0)->get(); + + foreach ($transactions as $transaction) { + + if($transaction->amount > 0){ + + // Exchange Sales + $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + foreach ($creditTransactions as $creditTransaction) { + $transaction->owners()->firstOrCreate([ + 'type' => StatementTransactionOwnerType::SALES, + 'system' => 'EXCHANGE', + 'owner_type' => Transaction::class, + 'owner_id'=> $creditTransaction->id, + ]); + } + + + // Shipping Portal Sales + $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date)); + foreach ($creditTransactions as $creditTransaction) { + $transaction->owners()->firstOrCreate([ + 'type' => StatementTransactionOwnerType::SALES, + 'system' => 'SHIPPING_PORTAL', + 'owner_type' => Transaction::class, + 'owner_id'=> $creditTransaction['id'], + ]); + } + + // Exchange Wallet Top Up + $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + foreach ($creditTransactions as $creditTransaction) { + $transaction->owners()->firstOrCreate([ + 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, + 'system' => 'EXCHANGE', + 'owner_type' => Transaction::class, + 'owner_id'=> $creditTransaction->id, + ]); + } + + // fpx charge refund + if($transaction->transaction_description === 'DUITNOW S/CHRG REFUND'){ + $transaction->owners()->firstOrCreate([ + 'type' => StatementTransactionOwnerType::FPX_CHARGE_REFUND + ]); + } + + // Customer Refund + + // INTERNAL_BANK_TRANSFER_IN + if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE')){ + $transaction->owners()->firstOrCreate([ + 'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_IN + ]); + } + + + } + + if($transaction->amount < 0){ + + // Supplier Purchase Order Payments + foreach (['YSN', 'HCK', 'ATVANTIC', 'HIGH HILL'] as $reference){ + if(str_contains($transaction->transaction_description.' '.$transaction->transaction_description_2.' '.$transaction->transaction_description_3.' '.$transaction->transaction_description_4.' '.$transaction->transaction_description_5 , $reference)) { + $paymentDateStart = $transaction->posting_date->startOfDay()->subDays(1); + $paymentDateEnd = $transaction->posting_date->endOfDay(); + + if($paymentDateStart->dayOfWeek === Carbon::SUNDAY){ + $paymentDateStart->subDays(2); + } + $issuer = Company::where('name', 'like', '%'.$reference.'%')->get()->pluck('id'); + + $debitTransactions = Group::whereIn('issuer', $issuer)->where('amount', '>=', (($transaction->amount * -1) - 0.01)) + ->where('amount', '<=', (($transaction->amount * -1) + 0.01))->whereDate('created_at', '>=', $paymentDateStart)->whereDate('created_at', '<=', $paymentDateEnd)->get(); + + foreach ($debitTransactions as $debitTransaction) { + $transaction->owners()->firstOrCreate([ + 'type' => StatementTransactionOwnerType::SUPPLIER_PAYMENT, + 'system' => 'EXCHANGE', + 'owner_type' => Group::class, + 'owner_id'=> $debitTransaction->id, + ]); + } + + } + } + + // Exchange Wallet Withdrawal + $debitTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::DEBIT_NOTE, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + foreach ($debitTransactions as $debitTransaction) { + $transaction->owners()->firstOrCreate([ + 'type' => StatementTransactionOwnerType::WALLET_WITHDRAWAL, + 'system' => 'EXCHANGE', + 'owner_type' => Transaction::class, + 'owner_id'=> $debitTransaction->id, + ]); + } + + // SALARY + + // 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([ + '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([ + 'type' => StatementTransactionOwnerType::FPX_CHARGE + ]); + } + + // BANK_CHARGE + if($transaction->transaction_description === 'CMS - DR CORP CHG' || $transaction->transaction_description === 'MONTHLY PROFIT DEBIT'){ + $transaction->owners()->firstOrCreate([ + 'type' => StatementTransactionOwnerType::BANK_CHARGE + ]); + } + + // CREDIT_CARD_PAYMENT + if(str_contains($transaction->transaction_description_2, 'VISA CARD')){ + $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([ + '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([ + 'type' => StatementTransactionOwnerType::NON_OPERATIONAL + ]); + } + } + } + } + + public function get(int $statementTransactionId){ + + $owners = [ + 'data' => [] + ]; + + $statementTransaction = StatementTransaction::find($statementTransactionId); + + if($statementTransaction->amount > 0) { + $creditTransactions = $this->getTransactions($statementTransaction->posting_date, $statementTransaction->amount, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + foreach ($creditTransactions as $transaction) { + $owners['data'][] = [ + 'system' => 'EXCHANGE', + 'owner_type' => Transaction::class, + 'owner_id' => $transaction->id, + 'bill_no' => $transaction->bill_no + ]; + } + + $creditTransactions = $this->getTransactions($statementTransaction->posting_date, $statementTransaction->amount, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]); + foreach ($creditTransactions as $transaction) { + $owners[] = [ + 'system' => 'EXCHANGE', + 'owner_type' => Transaction::class, + 'owner_id' => $transaction->id, + 'bill_no' => $transaction->bill_no + ]; + } + + $creditTransactions = $this->getTransactionsFromShippingPortal($statementTransaction->amount, $this->getDateRange($statementTransaction->posting_date)); + foreach ($creditTransactions as $transaction) { + $owners[] = [ + 'system' => 'IZYIM', + 'owner_type' => Transaction::class, + 'owner_id' => $transaction->id, + 'bill_no' => $transaction->bill_no + ]; + } + } + + return $owners; + } + + private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $model = Transaction::class) { + $query = $model::whereIn('status', $statuses) + ->where(function ($query) use ($ownerType, $paymentMethod, $type) { + if ($ownerType) { + $query->where('owner_type', $ownerType); + } + + if ($paymentMethod) { + $query->where('payment_method', '!=', $paymentMethod); + } + + if ($type) { + $query->where('type', $type); + } + }) + ->whereDate('created_at', $date->format('Y-m-d')) + ->where('amount', '>', ($amount - 0.01)) + ->where('amount', '<', ($amount + 0.01)); + + return $query->get(); + } + + private function getTransactionsFromShippingPortal($amount, $dateRange){ + try{ + + $client = new \GuzzleHttp\Client(['verify' => false]); + $response = $client->request('GET', 'https://izyim.cief-malaysia.com/public/api/v1/list?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2],"type":2,"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).'}'); + $body = $response->getBody(); + $data = json_decode($body, true); + $payload = $data['payload']; + $transactions2 = $payload['data']; + return $transactions2; + }catch(\Exception $exception){ + Log::error($exception); + return []; + } + } + + private function getDateRange(string $dateStr) { + // Create a DateTime object from the input string + $date = strtotime($dateStr); + + // Get the first day of the month + $today = date('Y-m-d', strtotime('-1 day', $date)); + + // Get the first day of the next month + $nextDay = date('Y-m-d', strtotime('+1 day', $date)); + + return [ + 'start_date' => $today, + 'end_date' => $nextDay, + ]; + } +} diff --git a/app/Classes/Modules/Accounting/Services/FetchesBankStatementDetails.php b/app/Classes/Modules/Accounting/Services/FetchesBankStatementDetails.php index 37a3d785..22de5c39 100644 --- a/app/Classes/Modules/Accounting/Services/FetchesBankStatementDetails.php +++ b/app/Classes/Modules/Accounting/Services/FetchesBankStatementDetails.php @@ -5,20 +5,20 @@ namespace App\Classes\Modules\Accounting\Services; use App\Classes\General\Eloquent\AbstractFetchRecord; use Illuminate\Database\Eloquent\Builder; -use App\Models\StatementTransactionsDetail; +use App\Models\StatementTransactionOwner; class FetchesBankStatementDetails extends AbstractFetchRecord { - /** @var StatementTransactionsDetail */ + /** @var StatementTransactionOwner */ private $repository; /** * FetchesBankStatementDetails constructor. - * @param StatementTransactionsDetail $repository + * @param StatementTransactionOwner $repository */ - public function __construct(StatementTransactionsDetail $repository) + public function __construct(StatementTransactionOwner $repository) { $this->repository = $repository; } diff --git a/app/Classes/Modules/Accounting/Services/ListsBankStatementDetails.php b/app/Classes/Modules/Accounting/Services/ListsBankStatementDetails.php index 2f1290e5..6e085e44 100644 --- a/app/Classes/Modules/Accounting/Services/ListsBankStatementDetails.php +++ b/app/Classes/Modules/Accounting/Services/ListsBankStatementDetails.php @@ -4,19 +4,19 @@ namespace App\Classes\Modules\Accounting\Services; use App\Classes\General\Eloquent\AbstractListRecord; use Illuminate\Database\Eloquent\Builder; -use App\Models\StatementTransactionsDetail; +use App\Models\StatementTransactionOwner; class ListsBankStatementDetails extends AbstractListRecord { - /** @var StatementTransactionsDetail */ + /** @var StatementTransactionOwner */ private $repository; /** * ListsBankStatementDetails constructor. - * @param StatementTransactionsDetail $repository + * @param StatementTransactionOwner $repository */ - public function __construct(StatementTransactionsDetail $repository) + public function __construct(StatementTransactionOwner $repository) { $this->repository = $repository; } diff --git a/app/Classes/Modules/Accounting/Services/ListsBankStatementTransactions.php b/app/Classes/Modules/Accounting/Services/ListsBankStatementTransactions.php new file mode 100644 index 00000000..8d4fbf69 --- /dev/null +++ b/app/Classes/Modules/Accounting/Services/ListsBankStatementTransactions.php @@ -0,0 +1,33 @@ +repository = $repository; + } + + + /** + * @return Builder + */ + public function getRepository(): Builder + { + return $this->repository->newQuery(); + } +} diff --git a/app/Classes/Modules/Accounting/Services/UpdatesBankStatementDetails.php b/app/Classes/Modules/Accounting/Services/UpdatesBankStatementDetails.php index 2e4ad23c..e87121ac 100644 --- a/app/Classes/Modules/Accounting/Services/UpdatesBankStatementDetails.php +++ b/app/Classes/Modules/Accounting/Services/UpdatesBankStatementDetails.php @@ -4,18 +4,18 @@ namespace App\Classes\Modules\Accounting\Services; use App\Classes\General\Eloquent\AbstractUpdateRecord; use App\Classes\Modules\Accounting\DataTransferObjects\BankStatementDetailObject; -use App\Models\StatementTransactionsDetail; +use App\Models\StatementTransactionOwner; class UpdatesBankStatementDetails extends AbstractUpdateRecord { /** - * @param StatementTransactionsDetail $model + * @param StatementTransactionOwner $model * @param BankStatementDetailsObject $object * @return \Illuminate\Database\Eloquent\Model * @throws \App\Classes\Exceptions\MalformedRequestException */ - public function execute(StatementTransactionsDetail $model, BankStatementDetailObject $object) + public function execute(StatementTransactionOwner $model, BankStatementDetailObject $object) { $model->system_references = $object->getSystemReferences(); $model->pay_for = $object->getPayFor(); diff --git a/app/Classes/Modules/Documents/DataTransferObjects/FileObject.php b/app/Classes/Modules/Documents/DataTransferObjects/FileObject.php index 736853fc..2a425f7d 100644 --- a/app/Classes/Modules/Documents/DataTransferObjects/FileObject.php +++ b/app/Classes/Modules/Documents/DataTransferObjects/FileObject.php @@ -28,7 +28,7 @@ class FileObject implements DataTransferObject */ public function getData() { - return in_array($this->getExtension(), ['pdf', 'excel']) ? $this->data : (new imageManager())->make($this->data); + return in_array($this->getExtension(), ['pdf', 'excel', 'text']) ? $this->data : (new imageManager())->make($this->data); } /** @@ -66,7 +66,7 @@ class FileObject implements DataTransferObject */ public function getDecodedData(): string { - return in_array($this->getExtension(), ['pdf', 'excel']) ? + return in_array($this->getExtension(), ['pdf', 'excel', 'text']) ? base64_decode((explode('base64,', $this->getData()))[1]): $this->getData()->encode('data-url')->encoded; } @@ -83,4 +83,4 @@ class FileObject implements DataTransferObject -} \ No newline at end of file +} diff --git a/app/Classes/Modules/Documents/Services/ConvertsBase64ToFile.php b/app/Classes/Modules/Documents/Services/ConvertsBase64ToFile.php index 8741b823..0e0cf6b9 100644 --- a/app/Classes/Modules/Documents/Services/ConvertsBase64ToFile.php +++ b/app/Classes/Modules/Documents/Services/ConvertsBase64ToFile.php @@ -36,7 +36,7 @@ class ConvertsBase64ToFile foreach ($files as $file) { $object = new FileObject($file); - in_array($object->getExtension(), ['pdf', 'excel']) ? $this->generatePDF($object) : $this->generateImage($object); + in_array($object->getExtension(), ['pdf', 'excel', 'text']) ? $this->generatePDF($object) : $this->generateImage($object); } @@ -122,4 +122,4 @@ class ConvertsBase64ToFile ]); } -} \ No newline at end of file +} diff --git a/app/Classes/ValueObjects/Constants/FileType.php b/app/Classes/ValueObjects/Constants/FileType.php index d5404e7a..fc6dbf1b 100644 --- a/app/Classes/ValueObjects/Constants/FileType.php +++ b/app/Classes/ValueObjects/Constants/FileType.php @@ -23,6 +23,7 @@ class FileType 'application/pdf' => 'pdf', 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'excel', 'application/vnd.ms-excel' => 'excel', + 'text/plain' => 'text', ]; -} \ No newline at end of file +} diff --git a/app/Classes/ValueObjects/Constants/StatementTransactionOwnerType.php b/app/Classes/ValueObjects/Constants/StatementTransactionOwnerType.php new file mode 100644 index 00000000..24d31516 --- /dev/null +++ b/app/Classes/ValueObjects/Constants/StatementTransactionOwnerType.php @@ -0,0 +1,37 @@ +paginate(10); + $statements = $statementsQuery->orderBy('date_from')->paginate(10); return view('pages.accounting.bank-statements.index', compact('accounts', 'selectedAccount', 'search', 'statements')); } - public function import(Request $request) + public function indexv2(Request $request) { + $selectedAccount = $request->input('account'); + $search = $request->input('search'); - $request->validate([ - 'file' => 'required|mimes:csv,txt' - ]); + $accounts = StatementAccount::all(); - $file = $request->file('file'); + $statementsQuery = AccountStatement::query(); - $collection = Excel::toCollection(null, $file, null, null, true); - - $sheet = $collection->first()->skip(1); - - $statementDetails = $sheet->first(); - - $accountNumber = $statementDetails[0]; - $accountType = $statementDetails[1]; - $accountName = $statementDetails[2]; - $accountCurrency = $statementDetails[3]; - $dateFrom = carbon::parse(str_replace(' MY (UTC+08:00)', '', $statementDetails[4])); - $dateTo = carbon::parse(str_replace(' MY (UTC+08:00)', '', $statementDetails[5])); - $totalDebit = $statementDetails[6]; - $totalCredit = $statementDetails[7]; - $beginBalance = $statementDetails[8]; - $endBalance = $statementDetails[9]; - $account = StatementAccount::updateOrCreate( - ['number' => $accountNumber], - [ - 'type' => $accountType, - 'name' => $accountName, - 'currency' => $accountCurrency, - ] - ); - - $statement = AccountStatement::where('date_from', $dateFrom) - ->where('date_to', $dateTo) - ->where('total_amount', $totalDebit ?: $totalCredit,) - ->where('begin_balance', $beginBalance) - ->where('end_balance', $endBalance)->first(); - - - if(!$statement){ - $statement = new AccountStatement([ - 'date_from' => $dateFrom, - 'date_to' => $dateTo, - 'total_amount' => $totalDebit ?: $totalCredit, - 'begin_balance' => $beginBalance, - 'end_balance' => $endBalance, - ]); + if ($selectedAccount) { + $statementsQuery->where('statement_account_id', $selectedAccount); } - // $existingStatement = AccountStatement::where('date_from', $dateFrom) - // ->where('date_to', $dateTo) - // ->where('statement_account_id', $account->id) - // ->first(); + if ($search) { + $statementsQuery->where(function ($query) use ($search) { + $query->where('date_from', 'LIKE', "%$search%") + ->orWhere('date_to', 'LIKE', "%$search%") + ->orWhere('total_amount', 'LIKE', "%$search%") + ->orWhere('begin_balance', 'LIKE', "%$search%") + ->orWhere('end_balance', 'LIKE', "%$search%"); + }); + } - // // if ($existingStatement) { - // // return redirect()->back()->with('error', 'This statement has already been imported.'); - // // } + $statements = $statementsQuery->paginate(10); - $account->statements()->save($statement); - - CreateBankStatementDetails::dispatch($statement)->delay(30); - - - // $account = null; - $newTransactions = $sheet->map(function ($row) use ($statement, $account) { - $transactionRef = $row[15]; - $amount = $row[17] !== '-' ? ((float) str_replace(',', '', $row[17])) : (-((float) str_replace(',', '', $row[16]))); - $transactionDate = $row[10] !== '-' ? carbon::parse(str_replace(' MY (UTC+08:00)', '', $row[10]) . $row[11]) : null; - $postingDate = carbon::createFromFormat('d/M/Y H:i', str_replace(' MY (UTC+08:00)', '', $row[12]) . str_replace(' MY (UTC+08:00)', '', $row[13])); - $transactionDescription = is_numeric($row[14]) ? (int) sprintf('%.2f', $row[14]) : $row[14]; - $tellerId = $row[19]; - $branchChannel = $row[20]; - $transactionCode = $row[21]; - $endBalance = $row[22]; - $description2 = $row[25]; - $description3 = $row[26]; - $description4 = $row[27]; - $description5 = $row[28]; - $transaction = new StatementTransaction([ - 'transaction_ref' => $transactionRef, - 'amount' => $amount, - 'transaction_date' => $transactionDate, - 'posting_date' => $postingDate, - 'transaction_description' => $transactionDescription, - 'teller_id' => $tellerId, - 'branch_channel' => $branchChannel, - 'transaction_code' => $transactionCode, - 'end_balance' => $endBalance, - 'transaction_description_2' => $description2, - 'transaction_description_3' => $description3, - 'transaction_description_4' => $description4, - 'transaction_description_5' => $description5, - ]); - - // Check if the transaction already exists for this statement - $existingTransaction = StatementTransaction::where('transaction_ref', $transactionRef) - ->where('posting_date', $postingDate) - ->where('amount', $amount) - ->where('transaction_description', $transactionDescription) - ->where('teller_id', $tellerId) - ->where('branch_channel', $branchChannel) - ->where('transaction_code', $transactionCode) - ->where('end_balance', $endBalance) - ->first(); - - if (!$existingTransaction) { - $statement->transactions()->save($transaction); - } - - return $transaction; - }); - - - // dd(json_encode($newTransactions)); - return redirect()->back()->with('success', 'Statement imported successfully.')->with('newTransactions', $newTransactions); + return view('pages.accounting.bank-statements.indexv2', compact('accounts', 'selectedAccount', 'search', 'statements')); } - public function rerun(AccountStatement $statement, Request $request) + public function import(Request $request, ImportBankStatementLogic $logic): JsonResponse { - CreateBankStatementDetails::dispatch($statement)->delay(30); + return $logic->execute($request); + } + + public function rerun() + { + CreateBankStatementTransactionOwners::dispatch(); return redirect()->back()->with('success', 'Rerun triggered successfully'); } @@ -227,6 +134,11 @@ class BankStatementController extends Controller return $logic->execute($request); } + public function transactions(Request $request, ListBankStatementTransactionsLogic $logic): JsonResponse + { + return $logic->execute($request); + } + public function update(Request $request, UpdateBankStatementDetailLogic $logic): JsonResponse { return $logic->execute($request); @@ -264,7 +176,7 @@ class BankStatementController extends Controller $count = 0; foreach ($transactions as $row) { - $isExist = StatementTransactionsDetail::where('statement_transaction_id', $row->id)->first(); + $isExist = StatementTransactionOwner::where('statement_transaction_id', $row->id)->first(); if ($isExist) { continue; @@ -371,7 +283,7 @@ class BankStatementController extends Controller //AccountStatement // $row->statement()->first()->id) - $statementTransactionsDetail = new StatementTransactionsDetail([ + $statementTransactionsDetail = new StatementTransactionOwner([ 'date' => $date, 'statement_transaction_id' => $row->id, 'description' => is_null($description) ? "" : $description, diff --git a/app/Http/Resources/BankStatementDetailResource.php b/app/Http/Resources/BankStatementDetailResource.php deleted file mode 100644 index 5533728c..00000000 --- a/app/Http/Resources/BankStatementDetailResource.php +++ /dev/null @@ -1,37 +0,0 @@ - $this->id, - 'account_number' => $this->statementTransaction->statement->account->number, - 'account_type' => $this->statementTransaction->statement->account->type, - 'account_name' => $this->statementTransaction->statement->account->name, - 'account_statement_id' => $this->statementTransaction->statement->id, - 'account_statement_date_from' => $this->statementTransaction->statement->date_from, - 'account_statement_date_to' => $this->statementTransaction->statement->date_to, - 'date' => $this->date, - 'description' => $this->description, - 'amount' => $this->statementTransaction->amount, - 'pay_for' => $this->pay_for, - 'system_references' => $this->system_references, - 'transaction_description_1' => $this->statementTransaction->transaction_description, - 'transaction_description_2' => $this->statementTransaction->transaction_description_2, - 'transaction_description_3' => $this->statementTransaction->transaction_description_3, - 'transaction_description_4' => $this->statementTransaction->transaction_description_4, - 'transaction_description_5' => $this->statementTransaction->transaction_description_5, - ]; - } -} diff --git a/app/Http/Resources/BankStatementTransactionOwnerResource.php b/app/Http/Resources/BankStatementTransactionOwnerResource.php new file mode 100644 index 00000000..0066eafa --- /dev/null +++ b/app/Http/Resources/BankStatementTransactionOwnerResource.php @@ -0,0 +1,65 @@ +system === 'EXCHANGE') { + if($this->owner_type === Transaction::class){ + $transaction = Transaction::find($this->owner_id); + + if($transaction->owner_type === Booking::class){ + $reference = $transaction->owner->marking; + $referenceLink = route('booking.details', $transaction->owner->marking); + } + + if($transaction->owner_type === Wallet::class) { + $reference = $transaction->owner->owner->reference; + $referenceLink = route('wallet.details', $transaction->owner->owner->reference); + } + } + + if($this->owner_type === Group::class){ + $transaction = Group::find($this->owner_id); + $reference = $transaction->reference; +// $referenceLink = route('booking.details', $transaction->owner->marking); + } + } + + if($this->system === 'SHIPPING_PORTAL') { + if($this->owner_type === Transaction::class){ + $transaction = Transaction::find($this->owner_id); + + } + } + + return [ + 'id' => $this->id, + 'type' => $this->type, + 'system' => $this->system, + 'owner_type' => $this->owner_type, + 'owner_id' => $this->owner_id, + 'reference_link' => $referenceLink, + 'reference' => $reference, + 'invoice_reference' => $this->invoice_reference, + 'receipt_reference' => $this->receipt_reference, + 'status' => $this->status + ]; + } +} diff --git a/app/Http/Resources/BankStatementTransactionResource.php b/app/Http/Resources/BankStatementTransactionResource.php new file mode 100644 index 00000000..09768f51 --- /dev/null +++ b/app/Http/Resources/BankStatementTransactionResource.php @@ -0,0 +1,36 @@ + $this->id, + 'account_number' => $this->statement->account->number, + 'account_type' => $this->statement->account->type, + 'account_name' => $this->statement->account->name, + 'account_statement_id' => $this->statement->id, + 'account_statement_date_from' => $this->statement->date_from, + 'account_statement_date_to' => $this->statement->date_to, + 'posting_date' => $this->posting_date->format('d-m-Y g:i A'), + 'amount' => $this->amount, + 'transaction_description_1' => $this->transaction_description, + 'transaction_description_2' => $this->transaction_description_2, + 'transaction_description_3' => $this->transaction_description_3, + 'transaction_description_4' => $this->transaction_description_4, + 'transaction_description_5' => $this->transaction_description_5, + 'owners' => BankStatementTransactionOwnerResource::collection($this->owners) + ]; + } +} diff --git a/app/Models/StatementTransaction.php b/app/Models/StatementTransaction.php index 6b789f08..80d6759f 100644 --- a/app/Models/StatementTransaction.php +++ b/app/Models/StatementTransaction.php @@ -4,9 +4,12 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Staudenmeir\EloquentHasManyDeep\HasRelationships; class StatementTransaction extends Model { + use HasRelationships; + use HasFactory; protected $fillable = [ @@ -30,18 +33,18 @@ class StatementTransaction extends Model 'posting_date' => 'datetime', ]; + public function account() + { + return $this->hasOneDeep(StatementAccount::class, [AccountStatement::class], ['id', 'id'], ['account_statement_id', 'statement_account_id']); + } + public function statement() { return $this->belongsTo(AccountStatement::class, 'account_statement_id', 'id'); } - public function owner() + public function owners() { - return $this->morphTo()->nullable(); - } - - public function statementDetail() - { - return $this->hasMany(StatementTransactionsDetail::class); + return $this->hasMany(StatementTransactionOwner::class); } } diff --git a/app/Models/StatementTransactionsDetail.php b/app/Models/StatementTransactionOwner.php similarity index 50% rename from app/Models/StatementTransactionsDetail.php rename to app/Models/StatementTransactionOwner.php index 074f5304..1db5404d 100644 --- a/app/Models/StatementTransactionsDetail.php +++ b/app/Models/StatementTransactionOwner.php @@ -4,26 +4,24 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; +use Illuminate\Database\Eloquent\Relations\BelongsTo; -class StatementTransactionsDetail extends Model +class StatementTransactionOwner extends Model { use HasFactory; protected $fillable = [ - 'date', 'statement_transaction_id', - // 'description', - // 'credit', - // 'debit', - 'pay_for', - 'system_references', - // 'remark_references', - // 'is_multiple', - // 'is_matches', - 'system_amounts', + 'type', + 'system', + 'owner_type', + 'owner_id', + 'invoice_reference', + 'receipt_reference', + 'status', ]; - public function statementTransaction() + public function transaction(): BelongsTo { return $this->belongsTo(StatementTransaction::class, 'statement_transaction_id', 'id'); } diff --git a/database/migrations/2023_03_26_190934_create_statement_transactions_table.php b/database/migrations/2023_03_26_190934_create_statement_transactions_table.php index 95ad3571..29cacb80 100644 --- a/database/migrations/2023_03_26_190934_create_statement_transactions_table.php +++ b/database/migrations/2023_03_26_190934_create_statement_transactions_table.php @@ -29,11 +29,6 @@ class CreateStatementTransactionsTable extends Migration $table->string('branch_channel'); $table->string('transaction_code'); $table->string('end_balance')->nullable(); - $table->string('owner_system')->nullable(); - $table->string('owner_type')->nullable(); - $table->unsignedBigInteger('owner_id')->nullable(); - $table->string('invoice_reference')->nullable(); - $table->string('payment_reference')->nullable(); $table->timestamps(); $table->foreign('account_statement_id')->references('id')->on('account_statements'); diff --git a/database/migrations/2023_04_07_212512_create_statement_transaction_owners_table.php b/database/migrations/2023_04_07_212512_create_statement_transaction_owners_table.php new file mode 100644 index 00000000..50d3a9c8 --- /dev/null +++ b/database/migrations/2023_04_07_212512_create_statement_transaction_owners_table.php @@ -0,0 +1,44 @@ +id(); + $table->foreignId('statement_transaction_id'); + $table->integer('type')->default(StatementTransactionOwnerType::UNKNOWN); + $table->string('system')->nullable(); + $table->string('owner_type')->nullable(); + $table->bigInteger('owner_id')->nullable(); + $table->string('invoice_reference')->nullable(); + $table->string('receipt_reference')->nullable(); + $table->string('is_auto_mapped')->default(true); + $table->integer('status')->default(ApprovalStatus::PENDING_VERIFICATION); + + $table->foreign('statement_transaction_id')->references('id')->on('statement_transactions'); + $table->timestamps(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('statement_transaction_owners'); + } +} diff --git a/database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php b/database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php deleted file mode 100644 index 3bc547fd..00000000 --- a/database/migrations/2023_04_07_212512_create_statement_transactions_details_table.php +++ /dev/null @@ -1,43 +0,0 @@ -id(); - $table->date('date'); - $table->unsignedBigInteger('statement_transaction_id'); - $table->foreign('statement_transaction_id')->references('id')->on('statement_transactions'); - // $table->string('description'); - // $table->decimal('credit', 8, 2); - // $table->decimal('debit', 8, 2); - $table->string('pay_for'); - $table->string('system_references'); - // $table->string('remark_references'); - // $table->boolean('is_multiple')->default(false); - // $table->boolean('is_matches')->default(false); - $table->string('system_amounts'); - $table->timestamps(); - }); - } - - /** - * Reverse the migrations. - * - * @return void - */ - public function down() - { - Schema::dropIfExists('statement_transactions_details'); - } -} diff --git a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue new file mode 100644 index 00000000..e2072785 --- /dev/null +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -0,0 +1,93 @@ + + + diff --git a/resources/assets/vue/components/accounting/forms/ImportStatementFormComponent.vue b/resources/assets/vue/components/accounting/forms/ImportStatementFormComponent.vue new file mode 100644 index 00000000..54db23df --- /dev/null +++ b/resources/assets/vue/components/accounting/forms/ImportStatementFormComponent.vue @@ -0,0 +1,59 @@ + + diff --git a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue new file mode 100644 index 00000000..3a4863a4 --- /dev/null +++ b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue @@ -0,0 +1,185 @@ + + diff --git a/resources/views/pages/accounting/bank-statements/bank_statement.blade.php b/resources/views/pages/accounting/bank-statements/bank_statement.blade.php new file mode 100644 index 00000000..87bbf321 --- /dev/null +++ b/resources/views/pages/accounting/bank-statements/bank_statement.blade.php @@ -0,0 +1,12 @@ +@extends('layouts.base_portal') +@section('inner_content') +
+
+ + + +
+
+@endsection diff --git a/resources/views/pages/accounting/bank-statements/index.blade.php b/resources/views/pages/accounting/bank-statements/index.blade.php index f41813db..e4071c26 100644 --- a/resources/views/pages/accounting/bank-statements/index.blade.php +++ b/resources/views/pages/accounting/bank-statements/index.blade.php @@ -1,102 +1,370 @@ @extends('layouts.base_portal') @section('inner_content') -
-
-
-
-
Import Bank Statement
+
+
+
-
- @if (session('success')) -
- {{ session('success') }} + {{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{-- --}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
Complete
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{-- --}} +{{-- --}} +{{-- --}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
Bank Statements
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
Transactions Mapping
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
Exceptional Transactions
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+
Reports & Analysis
+
+
+
+
+
+
+
- @endif - @if (session('error')) -
- {{ session('error') }} -
- @endif +
+
+
+
+
+
+ +
+
+
+
+
'.implode('', $headers).'
+ + + + + + + + + @foreach($accounts as $account) + + + + + + @endforeach + +
AccountCurrency
{{$account->number}}
{{$account->type}}
{{$account->currency}} + Open +
+
+
+
+
+
+
+
+
+ +
+ + +
+ + +
+
+ Rerun +
+
+
+
+ + +
+ + Clear +
+
+
-
- @csrf -
- - + + + + + + + + + + + + + + + @foreach($statements as $statement) + + + + + + + + + + @endforeach + +
AccountDate FromDate ToTotal AmountBegin BalanceEnd BalanceActions
{{ $statement->account->number }}{{ $statement->date_from->format('d-m-Y') }}{{ $statement->date_to->format('d-m-Y') }}{{ $statement->total_amount }}{{ $statement->begin_balance }}{{ $statement->end_balance }} + View +
+ {{ $statements->links() }} +
+
+
+
+ +
+
+
+
+
+
+
+
+
+
+
+
+
Deposit Mapping
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
Withdrawal Mapping
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ +
+
+
+
+ +
+
+
+
+
+
+
+
+ + + +
+
+
- - - - - -
-
- @if (session('message')) -
- {{ session('message') }}
- @endif -
Bank Statements - View All -
-
-
-
- - -
- - Clear -
- -
-
- - -
- -
- - - - - - - - - - - - - - - @foreach($statements as $statement) - - - - - - - - - - - @endforeach - -
AccountDate FromDate ToTotal AmountBegin BalanceEnd BalanceActions
{{ $statement->account->name }} ({{ $statement->account->number }}){{ $statement->date_from->format('d-m-Y') }}{{ $statement->date_to->format('d-m-Y') }}{{ $statement->total_amount }}{{ $statement->begin_balance }}{{ $statement->end_balance }} - View - - Rerun -
- {{ $statements->links() }}
@endsection +{{--@extends('layouts.base_portal')--}} +{{--@section('inner_content')--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
Import Bank Statement
--}} + +{{--
--}} +{{-- @if (session('success'))--}} +{{--
--}} +{{-- {{ session('success') }}--}} +{{--
--}} +{{-- @endif--}} +{{-- @if (session('error'))--}} +{{--
--}} +{{-- {{ session('error') }}--}} +{{--
--}} +{{-- @endif--}} + +{{--
--}} +{{-- @csrf--}} +{{--
--}} +{{-- --}} +{{-- --}} +{{--
--}} +{{-- --}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{-- @if (session('message'))--}} +{{--
--}} +{{-- {{ session('message') }}--}} +{{--
--}} +{{-- @endif--}} +{{--
Bank Statements--}} +{{-- View All--}} +{{--
--}} + +{{--
--}} +{{--
--}} +{{--
--}} +{{--
--}} +{{--@endsection--}} diff --git a/resources/views/pages/accounting/bank-statements/indexv2.blade.php b/resources/views/pages/accounting/bank-statements/indexv2.blade.php new file mode 100644 index 00000000..f18a77ae --- /dev/null +++ b/resources/views/pages/accounting/bank-statements/indexv2.blade.php @@ -0,0 +1,461 @@ +@extends('layouts.base_portal') +@section('inner_content') + + +
+
+
+

Accounting Dashboard

+
+
+
+
+
+
+
+
Import Bank Statement
+ +
+ @if (session('success')) +
+ {{ session('success') }} +
+ @endif + @if (session('error')) +
+ {{ session('error') }} +
+ @endif + +
+ @csrf +
+ + +
+ +
+
+
+
+
+
+
+
+
Transaction Filtering
+ +
+
+
+ + +
+
+ + +
+
+ + +
+
+ + +
+ +
+
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTransaction TypeAccount NameDescriptionStatus
2023-04-11DepositBank Account 1Salary PaymentPending
2023-04-09WithdrawalBank Account 2Vendor PaymentReconciled
2023-04-07DepositBank Account 3Online Order PaymentException
+
+
+ + + +
+
+

Step 1: Start Mapping bank Transactions

+

This is the first step in the wizard.

+
+
+

Step 2: List of automatically mapped bank transactions

+

This is the second step in the wizard.

+
+
+

Step 3: List of bank transactions that require manual mapping

+

This is the third step in the wizard.

+
+
+

Step 4: Export invoices to accounting software

+

This is the fourth step in the wizard.

+
+
+

Step 5: Import invoices from accounting software

+

This is the fifth step in the wizard.

+
+
+

Step 6: Export payment receipts

+

This is the sixth step in the wizard.

+
+
+

Step 7: Import payment receipts

+

This is the final step in the wizard.

+
+
+ + +
    +
  • +
  • +
  • +
+ +
+
+

Tab 3 Content

+

Aliquam vitae magna sit amet tellus bibendum posuere. Integer nec leo quis arcu tincidunt eleifend. Suspendisse potenti. Proin ullamcorper sodales nisl vel tincidunt. Etiam malesuada, mauris sit amet tincidunt facilisis, nisl enim aliquet turpis, ac pretium lacus nulla a libero. Vivamus euismod ex vel sapien dignissim, a fringilla enim fringilla. Sed sit amet lobortis augue. Aenean ut neque ac elit interdum pretium vel vel purus. Duis ut magna at ante dignissim efficitur. Pellentesque molestie bibendum ipsum a malesuada. Nulla cursus vehicula felis vel dapibus. Suspendisse eget vulputate ex. In pulvinar tincidunt justo, eu viverra orci malesuada id. Sed posuere arcu ac diam finibus posuere.

+
+
+
+
+ + +
+ + Clear +
+ +
+
+ + +
+ +
+ + + + + + + + + + + + + + + @foreach($statements as $statement) + + + + + + + + + + @endforeach + +
AccountDate FromDate ToTotal AmountBegin BalanceEnd BalanceActions
{{ $statement->account->name }} ({{ $statement->account->number }}){{ $statement->date_from->format('d-m-Y') }}{{ $statement->date_to->format('d-m-Y') }}{{ $statement->total_amount }}{{ $statement->begin_balance }}{{ $statement->end_balance }} + View +
+ {{ $statements->links() }} +
+
+
+
+
+
+
+
+ +
+
+
+
+ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +
DateTransaction TypeAccount NameDescriptionStatus
2023-04-11DepositBank Account 1Salary PaymentPending
2023-04-09WithdrawalBank Account 2Vendor PaymentReconciled
2023-04-07DepositBank Account 3Online Order PaymentException
+
+
+
+
+ + +
+ + Clear +
+ +
+
+ + +
+ +
+ + + + + + + + + + + + + + + @foreach($statements as $statement) + + + + + + + + + + @endforeach + +
AccountDate FromDate ToTotal AmountBegin BalanceEnd BalanceActions
{{ $statement->account->name }} ({{ $statement->account->number }}){{ $statement->date_from->format('d-m-Y') }}{{ $statement->date_to->format('d-m-Y') }}{{ $statement->total_amount }}{{ $statement->begin_balance }}{{ $statement->end_balance }} + View +
+ {{ $statements->links() }} +
+
+

Tab 3 Content

+

Aliquam vitae magna sit amet tellus bibendum posuere. Integer nec leo quis arcu tincidunt eleifend. Suspendisse potenti. Proin ullamcorper sodales nisl vel tincidunt. Etiam malesuada, mauris sit amet tincidunt facilisis, nisl enim aliquet turpis, ac pretium lacus nulla a libero. Vivamus euismod ex vel sapien dignissim, a fringilla enim fringilla. Sed sit amet lobortis augue. Aenean ut neque ac elit interdum pretium vel vel purus. Duis ut magna at ante dignissim efficitur. Pellentesque molestie bibendum ipsum a malesuada. Nulla cursus vehicula felis vel dapibus. Suspendisse eget vulputate ex. In pulvinar tincidunt justo, eu viverra orci malesuada id. Sed posuere arcu ac diam finibus posuere.

+
+
+
+
+
+
+
+
+
+ + + + ``` + Next, we add some custom CSS styles to the wizard to make it look more appealing. + php + Copy code + + Finally, we add some JavaScript code to handle the wizard functionality. We use the Bootstrap Wizard plugin to enable the wizard navigation buttons. + php + Copy code + +@endsection diff --git a/routes/accounting.php b/routes/accounting.php index acc75e35..807ba564 100644 --- a/routes/accounting.php +++ b/routes/accounting.php @@ -3,6 +3,8 @@ use Illuminate\Support\Facades\Route; Route::group(['prefix' => 'accounting', 'as' => 'accounting.', 'namespace' => 'Accounting'], function () { + Route::post('/import', 'BankStatementController@import')->name('statement.import'); + Route::get('/bank_account', 'BankStatementController@transactions')->name('bank.transaction'); Route::group(['prefix' => 'statements/{id}', 'as' => 'statement.'], function () { Route::get('/details', 'BankStatementController@fetch')->name('details'); Route::put('/details/update', 'BankStatementController@update')->name('details.update'); diff --git a/routes/web.php b/routes/web.php index d7117c89..e4018b8e 100644 --- a/routes/web.php +++ b/routes/web.php @@ -556,12 +556,16 @@ Route::get('/currency-rate-history', function () { })->name('currency_rate.history'); Route::get('/statements', [BankStatementController::class, 'index'])->name('statements.index'); +Route::get('/statements/v2', [BankStatementController::class, 'indexv2'])->name('statements.indexv2'); Route::post('/statements/import', [BankStatementController::class, 'import'])->name('statements.import'); Route::get('/statements/{statement}/details', function ($statement) { return view('pages.accounting.bank-statements.details', ['statement' => $statement]); })->name('statements.transactions.details'); +Route::get('/statements/{account}/transactions', function ($account) { + return view('pages.accounting.bank-statements.bank_statement', ['account' => $account]); +})->name('statements.account.transactions'); Route::get('/statements/{statement}', [BankStatementController::class, 'show'])->name('statements.show'); -Route::get('/statements/{statement}/rerun', [BankStatementController::class, 'rerun'])->name('statements.rerun'); +Route::get('/statements/mapping/rerun', [BankStatementController::class, 'rerun'])->name('statements.rerun'); Route::get('/statements/{statement}/download', 'StatementController@download')->name('statements.download'); Route::get('/bank-record', 'Imports\ImportBankRecordController@import'); From b94d50325cc78d311bf81d7aa2af10ef5e70aa48 Mon Sep 17 00:00:00 2001 From: Omair Saleh Date: Tue, 18 Apr 2023 17:16:11 +0800 Subject: [PATCH 05/69] fix duplicated listing section bug --- .../views/pages/accounting/bank-statements/index.blade.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/resources/views/pages/accounting/bank-statements/index.blade.php b/resources/views/pages/accounting/bank-statements/index.blade.php index e4071c26..34184e2d 100644 --- a/resources/views/pages/accounting/bank-statements/index.blade.php +++ b/resources/views/pages/accounting/bank-statements/index.blade.php @@ -305,7 +305,7 @@
- + From 83e883abb91cfb40042c7348ca47a3e87f486f55 Mon Sep 17 00:00:00 2001 From: Omair Saleh Date: Tue, 18 Apr 2023 17:23:27 +0800 Subject: [PATCH 06/69] fix duplicated listing section bug --- .../CreateBankStatementTransactionOwnersProcessor.php | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php index f3d61595..79ee5018 100644 --- a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php +++ b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php @@ -32,7 +32,7 @@ class CreateBankStatementTransactionOwnersProcessor // })->get(); $transactions = StatementTransaction::whereDoesntHave('owners')->where('amount', '<', 0)->get(); - +dd($transactions); foreach ($transactions as $transaction) { if($transaction->amount > 0){ From 7cb88cb486f0adf7964161c701ad13a51d82f84d Mon Sep 17 00:00:00 2001 From: edmondlang Date: Wed, 19 Apr 2023 18:59:00 +0800 Subject: [PATCH 07/69] modal to approve match and reject match --- .../StatementTransactionComponent.vue | 22 ++++++++ .../sections/TransactionsMappingComponent.vue | 16 +++++- .../GeneralConfirmationFormComponent.vue | 55 +++++++++++++++++++ 3 files changed, 91 insertions(+), 2 deletions(-) create mode 100644 resources/assets/vue/components/general/forms/GeneralConfirmationFormComponent.vue diff --git a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue index e2072785..d5459e81 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -44,6 +44,22 @@
{{ item.amount }}
+
+ +
+ + + + @@ -54,6 +70,12 @@ \ No newline at end of file From 44ddcebcede7ebf9ab59f4d37ace3ebfd637b37e Mon Sep 17 00:00:00 2001 From: edmondlang Date: Wed, 19 Apr 2023 21:02:52 +0800 Subject: [PATCH 08/69] modal to approve match and reject match --- .../accounting/elements/StatementTransactionComponent.vue | 2 +- .../accounting/sections/TransactionsMappingComponent.vue | 5 +++-- .../general/forms/GeneralConfirmationFormComponent.vue | 8 +++++++- 3 files changed, 11 insertions(+), 4 deletions(-) diff --git a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue index d5459e81..357db4be 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -56,7 +56,7 @@ class="text-center" :apiRoute="route('api.company.delete', 1)" apiMethod="post" - :section="section" + section="statementTransactionComponent" > diff --git a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue index 2e9ba412..e51f1e9f 100644 --- a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue +++ b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue @@ -89,7 +89,7 @@ @@ -141,7 +141,8 @@ export default { stage: null, exportStage: 0, step: 0, - filter: {} + filter: {}, + section: 'bankTransactionSection', } }, methods: { diff --git a/resources/assets/vue/components/general/forms/GeneralConfirmationFormComponent.vue b/resources/assets/vue/components/general/forms/GeneralConfirmationFormComponent.vue index 561681aa..7ac446dd 100644 --- a/resources/assets/vue/components/general/forms/GeneralConfirmationFormComponent.vue +++ b/resources/assets/vue/components/general/forms/GeneralConfirmationFormComponent.vue @@ -15,7 +15,8 @@
Cancel
-
{{ buttonText }}
+ +
{{ buttonText }}
@@ -49,6 +50,11 @@ required: true }, }, + methods: { + test() { + console.log('sjhb'); + } + }, mixins: [componentHandler, ModalFormHandler] } From 6dbdb0a1d69a0138e04b935aded7c792320a6d4a Mon Sep 17 00:00:00 2001 From: edmondlang Date: Wed, 19 Apr 2023 22:21:53 +0800 Subject: [PATCH 09/69] modal to approve match and reject match --- .../sections/TransactionsMappingComponent.vue | 26 ++++++++++--------- 1 file changed, 14 insertions(+), 12 deletions(-) diff --git a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue index e51f1e9f..39480482 100644 --- a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue +++ b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue @@ -59,18 +59,20 @@
-
Approve all the Mapping Below
- - - - +
+
Approve all the Mapping Below
+ + + + +
From 5f8fa00853dc48c0912d107df668c3f6f97b6ab6 Mon Sep 17 00:00:00 2001 From: edmondlang Date: Wed, 19 Apr 2023 22:32:44 +0800 Subject: [PATCH 10/69] update modal to approve match and reject match --- .../StatementTransactionComponent.vue | 24 +++++++++---------- .../sections/TransactionsMappingComponent.vue | 8 +++---- 2 files changed, 16 insertions(+), 16 deletions(-) diff --git a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue index 357db4be..25fbc62d 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -45,21 +45,21 @@
{{ item.amount }}
- + + + +
- - - -
diff --git a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue index 39480482..616e4f63 100644 --- a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue +++ b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue @@ -1,5 +1,5 @@