From 05b5823fe4d9c579bbd84440865a0efb35c67b92 Mon Sep 17 00:00:00 2001 From: Steve Ng Date: Mon, 23 Oct 2023 09:20:35 +0800 Subject: [PATCH 1/5] fixing unable mapping records and filtering function in Pending Export tab and listing data not same in Pending Export tab with export Invoice to autocount and calculate mapped percentage --- .../StatementTransactionPostingEnd.php | 18 +++++ .../StatementTransactionPostingStart.php | 18 +++++ ...ankStatementTransactionOwnersProcessor.php | 49 +++++++------ .../Services/ExportsInvoiceTransactions.php | 27 +++---- app/Models/AccountStatement.php | 2 + ...apped_rate_to_account_statements_table.php | 34 +++++++++ .../StatementTransactionComponent.vue | 2 +- .../sections/TransactionsMappingComponent.vue | 71 +++++++++++++++++-- 8 files changed, 182 insertions(+), 39 deletions(-) create mode 100644 app/Classes/General/Eloquent/Filters/StatementTransactionPostingEnd.php create mode 100644 app/Classes/General/Eloquent/Filters/StatementTransactionPostingStart.php create mode 100644 database/migrations/2023_10_22_140339_add_mapped_rate_to_account_statements_table.php diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionPostingEnd.php b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingEnd.php new file mode 100644 index 00000000..e837245e --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingEnd.php @@ -0,0 +1,18 @@ +whereDate('posting_date', '<=', date('Y-m-d',strtotime($value))); + } +} \ No newline at end of file diff --git a/app/Classes/General/Eloquent/Filters/StatementTransactionPostingStart.php b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingStart.php new file mode 100644 index 00000000..c3560357 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/StatementTransactionPostingStart.php @@ -0,0 +1,18 @@ +whereDate('posting_date', '>=', date('Y-m-d',strtotime($value))); + } +} \ No newline at end of file diff --git a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php index 36fc684a..6f7efe5e 100644 --- a/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php +++ b/app/Classes/Modules/Accounting/Processors/CreateBankStatementTransactionOwnersProcessor.php @@ -28,6 +28,7 @@ class CreateBankStatementTransactionOwnersProcessor // $transactions = StatementTransaction::whereDoesntHave('owners')->where('amount', '<', 0)->get(); foreach ($transactions as $transaction) { + $mapped = false; $keywords = array_filter(explode(" ", $transaction->transaction_description . " " . $transaction->transaction_description_2)); if($transaction->amount > 0){ @@ -36,7 +37,7 @@ class CreateBankStatementTransactionOwnersProcessor $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($creditTransactions as $creditTransaction) { $isArray = is_array($creditTransaction); - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SALES, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, @@ -45,12 +46,11 @@ class CreateBankStatementTransactionOwnersProcessor ]); } - // Shipping Portal Sales - $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), 2, PaymentMethodType::WALLET); + $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), [2], PaymentMethodType::WALLET); foreach ($creditTransactions as $creditTransaction) { if($creditTransaction['owner_type'] === Wallet::class) continue; - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SALES, 'system' => 'SHIPPING_PORTAL', 'owner_type' => $creditTransaction['owner_type'], @@ -63,7 +63,7 @@ class CreateBankStatementTransactionOwnersProcessor $creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($creditTransactions as $creditTransaction) { $isArray = is_array($creditTransaction); - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, @@ -72,9 +72,9 @@ class CreateBankStatementTransactionOwnersProcessor ]); } - $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), 5, null); + $creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), [5,15], null); foreach ($creditTransactions as $creditTransaction) { - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_TOP_UP, 'system' => 'SHIPPING_PORTAL', 'owner_type' => $creditTransaction['owner_type'], @@ -85,7 +85,7 @@ class CreateBankStatementTransactionOwnersProcessor // fpx charge refund if($transaction->transaction_description === 'DUITNOW S/CHRG REFUND'){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::FPX_CHARGE_REFUND ]); } @@ -94,7 +94,7 @@ class CreateBankStatementTransactionOwnersProcessor // INTERNAL_BANK_TRANSFER_IN if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_IN ]); } @@ -119,7 +119,7 @@ class CreateBankStatementTransactionOwnersProcessor ->where('amount', '<=', (($transaction->amount * -1) + 0.01))->whereDate('created_at', '>=', $paymentDateStart)->whereDate('created_at', '<=', $paymentDateEnd)->get(); foreach ($debitTransactions as $debitTransaction) { - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::SUPPLIER_PAYMENT, 'system' => 'EXCHANGE', 'owner_type' => Group::class, @@ -135,7 +135,7 @@ class CreateBankStatementTransactionOwnersProcessor $debitTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::DEBIT_NOTE, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords); foreach ($debitTransactions as $debitTransaction) { $isArray = is_array($creditTransaction); - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::WALLET_WITHDRAWAL, 'system' => 'EXCHANGE', 'owner_type' => Transaction::class, @@ -148,50 +148,52 @@ class CreateBankStatementTransactionOwnersProcessor // STATUTORY if(str_contains($transaction->transaction_description_2, 'PEMBANGUNAN SUMBER') || str_contains($transaction->transaction_description_2, 'HASIL') || str_contains($transaction->transaction_description_2, 'PERTUBUHAN KESELAMAT') || str_contains($transaction->transaction_description_2, 'KUMPULAN WANG SIMPAN')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::STATUTORY ]); } // FPX_CHARGE if($transaction->transaction_description === 'DR DUITNOW S/CHRG' || str_contains($transaction->transaction_description, 'Manual FPX') || str_contains($transaction->transaction_description, 'CMS - DR FPX CHG')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::FPX_CHARGE ]); } // BANK_CHARGE if($transaction->transaction_description === 'CMS - DR CORP CHG' || $transaction->transaction_description === 'MONTHLY PROFIT DEBIT'){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::BANK_CHARGE ]); } // CREDIT_CARD_PAYMENT if(str_contains($transaction->transaction_description_2, 'VISA CARD')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::CREDIT_CARD_PAYMENT ]); } // INTERNAL_BANK_TRANSFER_OUT if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE') || str_contains($transaction->transaction_description_2, 'CIEF WORLWIDE') || str_contains($transaction->transaction_description_2, 'IZYIM GLOBAL')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_OUT ]); } // non-operational charges if(str_contains($transaction->transaction_description_2, 'HIRE PURCHASE') || str_contains($transaction->transaction_description_2, 'TENAGA NASIONAL') || str_contains($transaction->transaction_description, 'CABLE CHARGE') || str_contains($transaction->transaction_description_2, 'CTOS DATA SYSTEMS') || str_contains($transaction->transaction_description_2, 'MAXIS')){ - $transaction->owners()->firstOrCreate([ + $data = $transaction->owners()->firstOrCreate([ 'type' => StatementTransactionOwnerType::NON_OPERATIONAL ]); } } + if (isset($data) && $data->wasRecentlyCreated) $mapped = true; + $this->updateMappedRate($transaction, $mapped); } - } + } - private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $keywords, $model = Transaction::class) { + private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $keywords, $model = Transaction::class) { $dateRange = $this->getDateRange($date, 4); if (App::environment(['production'])) { $query = $model::whereIn('status', $statuses) @@ -318,7 +320,7 @@ class CreateBankStatementTransactionOwnersProcessor try{ $client = new \GuzzleHttp\Client(['verify' => false]); - $response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2]'.$paymentMethodFilter.',"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in":['.$type.']}'); + $response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2]'.$paymentMethodFilter.',"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in":'.json_encode($type).'}'); $body = $response->getBody(); $data = json_decode($body, true); $payload = $data['payload']; @@ -345,4 +347,11 @@ class CreateBankStatementTransactionOwnersProcessor 'end_date' => $nextDay, ]; } + + private function updateMappedRate($transaction, $mapped) { + $statement = $transaction->statement; + $statement->total_rows = StatementTransaction::where('account_statement_id',$transaction->account_statement_id)->count(); + $statement->mapped_rows = $mapped ? $statement->mapped_rows+1 : $statement->mapped_rows; + $statement->save(); + } } diff --git a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php index 79ca4380..2ecaada8 100644 --- a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php +++ b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php @@ -4,7 +4,6 @@ namespace App\Classes\Modules\Exports\Services; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType; -use App\Models\StatementTransactionOwner; use App\Models\Transaction; use Maatwebsite\Excel\Concerns\Exportable; use Maatwebsite\Excel\Concerns\FromQuery; @@ -18,6 +17,8 @@ use App\Classes\Modules\Accounting\Processors\ListShippingPortalTransactions; use App\Classes\ValueObjects\Constants\ShippingTransactionType; use App\Classes\ValueObjects\Constants\TransactionType; use Illuminate\Support\Facades\Log; +use App\Classes\General\Eloquent\ApplyFiltersToQuery; +use App\Models\StatementTransaction; class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize { @@ -64,10 +65,9 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading */ public function query() { - $data = StatementTransactionOwner::whereNull('invoice_reference') - ->whereIn('type', [StatementTransactionOwnerType::SALES, StatementTransactionOwnerType::WALLET_TOP_UP]) - ->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED]); - if ($this->request->has('bankStatementOwnerId')) $data = $data->whereIn('id',json_decode($this->request->input('bankStatementOwnerId'))); + $data = (new ApplyFiltersToQuery())->execute(StatementTransaction::query(), json_decode($this->request->input('filter'), true)); + if ($this->request->has('bankStatementTransactionId')) $data = $data->whereIn('id',json_decode($this->request->input('bankStatementTransactionId'), true)); + return $data; } @@ -78,11 +78,12 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading */ public function map($transaction): array { + $statementTransactionOwner = $transaction->owners()->whereIn('status', [ApprovalStatus::APPROVED])->first(); $logArray = [ 'counter' => $this->counter, - 'system' => $transaction->system, - 'StatementTransactionOwner_id' => $transaction->id, - 'transaction_table_id' => $transaction->owner_id, + 'system' => $statementTransactionOwner->system, + 'StatementTransactionOwner_id' => $statementTransactionOwner->id, + 'transaction_table_id' => $statementTransactionOwner->owner_id, ]; $this->counter += 1; $logArray = json_encode($logArray); @@ -92,8 +93,8 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' ' . $logArray . PHP_EOL; file_put_contents($filePath, $textToAppend, FILE_APPEND); - if ($transaction->system == 'EXCHANGE') { - $row = (App()->make($transaction->owner_type))->where('id', $transaction->owner_id)->first(); + if ($statementTransactionOwner->system == 'EXCHANGE') { + $row = (App()->make($statementTransactionOwner->owner_type))->where('id', $statementTransactionOwner->owner_id)->first(); $company = $row->type === TransactionType::PAYMENT ? $row->owner->company : $row->owner->owner; $booking = $row->owner; @@ -116,15 +117,15 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading ]; } else { $row = (App()->make(ListShippingPortalTransactions::class))->execute([ - 'id' => $transaction->owner_id, + 'id' => $statementTransactionOwner->owner_id, 'with_company' => true, ]); if (empty($row) || $row[0]['status'] != 'success') { $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' Fetch Shipping Transaction Fail ' . json_encode([ - 'id' => $transaction->owner_id, + 'id' => $statementTransactionOwner->owner_id, 'with_company' => true, - 'StatementTransactionOwner_id' => $transaction->id, + 'StatementTransactionOwner_id' => $statementTransactionOwner->id, ]) . PHP_EOL; file_put_contents($errorFilePath, $textToAppend, FILE_APPEND); diff --git a/app/Models/AccountStatement.php b/app/Models/AccountStatement.php index d9e53d60..2f5b0e8c 100644 --- a/app/Models/AccountStatement.php +++ b/app/Models/AccountStatement.php @@ -16,6 +16,8 @@ class AccountStatement extends Model 'total_amount', 'begin_balance', 'end_balance', + 'total_rows', + 'mapped_rows', ]; protected $casts = [ diff --git a/database/migrations/2023_10_22_140339_add_mapped_rate_to_account_statements_table.php b/database/migrations/2023_10_22_140339_add_mapped_rate_to_account_statements_table.php new file mode 100644 index 00000000..f6a8e7e7 --- /dev/null +++ b/database/migrations/2023_10_22_140339_add_mapped_rate_to_account_statements_table.php @@ -0,0 +1,34 @@ +integer('total_rows')->unsigned()->default(0)->after('end_balance'); + $table->integer('mapped_rows')->unsigned()->default(0)->after('end_balance'); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('account_statements', function (Blueprint $table) { + $table->dropColumn('total_rows'); + $table->dropColumn('mapped_rows'); + }); + } +} diff --git a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue index 1caef408..b09b9a56 100644 --- a/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue +++ b/resources/assets/vue/components/accounting/elements/StatementTransactionComponent.vue @@ -126,7 +126,7 @@
- +
Pending...
diff --git a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue index 9d74dce1..4604f2e5 100644 --- a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue +++ b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue @@ -74,6 +74,32 @@ + + +
+
+
+ + + + +
+
+ + + + +
+
+
+ + Search + +
+
+
+
+
@@ -202,6 +228,10 @@ export default { data(){ return { + parameters: { + startDate: '', + endDate: '', + }, type: null, stage: null, exportStage: 0, @@ -215,6 +245,14 @@ export default { } }, validations: { + parameters: { + startDate: { + required + }, + endDate: { + required + }, + }, files: { // required // todo-new: set required if is pdf section } @@ -227,17 +265,31 @@ export default { this.mappedTrue = true; }, exportInvoiceToAutoCount(){ - window.open(this.route('invoiceTransactions.export')+'?bankStatementOwnerId='+this.getCheckedStatementOwners()+'&type=invoices', '_blank'); + const checkedStatementTransactions = this.getCheckedStatementOwners(); + + let route = this.route('invoiceTransactions.export')+'?type=invoices&filter='+JSON.stringify(this.filter); + if (checkedStatementTransactions) { + route += '&bankStatementTransactionId='+checkedStatementTransactions; + } + + window.open(route, '_blank'); }, exportReceiptToAutoCount(){ - window.open(this.route('invoiceTransactions.export')+'?bankStatementOwnerId='+this.getCheckedStatementOwners()+'&type=receipts', '_blank'); + const checkedStatementTransactions = this.getCheckedStatementOwners(); + + let route = this.route('invoiceTransactions.export')+'?type=receipts&filter='+JSON.stringify(this.filter); + if (checkedStatementTransactions) { + route += '&bankStatementTransactionId='+checkedStatementTransactions; + } + + window.open(route, '_blank'); }, getCheckedStatementOwners() { - let bankStatementOwnerId = []; + let bankStatementTransactionId = []; $('.request_export_item:checked').each(function() { - bankStatementOwnerId.push($(this).val()); + bankStatementTransactionId.push($(this).val()); }); - return JSON.stringify(bankStatementOwnerId); + return (bankStatementTransactionId.length > 0 ? JSON.stringify(bankStatementTransactionId) : null); }, successHandler(){ this.step += 1; @@ -263,6 +315,10 @@ export default { break; case 4: this.filter = {min_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + + if (typeof this.parameters.startDate != 'undefined' && this.parameters.startDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_start: this.parameters.startDate}}; + + if (typeof this.parameters.endDate != 'undefined' && this.parameters.endDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_end:this.parameters.endDate}}; break; } } @@ -280,6 +336,11 @@ export default { break; case 4: this.filter = {max_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [3, 5], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}} + + if (typeof this.parameters.startDate != 'undefined' && this.parameters.startDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_start: this.parameters.startDate}}; + + if (typeof this.parameters.endDate != 'undefined' && this.parameters.endDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_end:this.parameters.endDate}}; + break; } } From bc5a8a91939e3b992a20ff0bb61069ba505bebd4 Mon Sep 17 00:00:00 2001 From: Steve Ng Date: Tue, 24 Oct 2023 21:21:51 +0800 Subject: [PATCH 2/5] fix bug in function import invoices --- .../Imports/ImportStatementInvoiceController.php | 10 ++-------- app/Models/StatementTransactionOwner.php | 1 + app/Models/Transaction.php | 16 ++++++++++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php index 7ea3454e..73e58e87 100644 --- a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php +++ b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php @@ -137,16 +137,10 @@ class ImportStatementInvoiceController private function mappingExchange(Array $row) { $date = $row['date']; - $transactions = Transaction::where('original_amount', $row['net_total'])->whereRaw("DATE(created_at) = '$date'") - ->whereHas('receiverCompany', function($q) use($row) { - $q->where('debtor',$row['debtor_code']); - })->get(); + $transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where('statement_transactions.amount', $row['net_total'])->whereRaw("DATE(posting_date) = '$date'")->get(); if ($transactions && $transactions->count() == 0) { - $transactions = Transaction::where(DB::raw('FLOOR(original_amount)'), floor($row['net_total']))->whereRaw("DATE(created_at) = '$date'") - ->whereHas('receiverCompany', function($q) use($row) { - $q->where('debtor',$row['debtor_code']); - })->get(); + $transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where(DB::raw('FLOOR(statement_transactions.amount)'), floor($row['net_total']))->whereRaw("DATE(posting_date) = '$date'")->get(); } if ($transactions && $transactions->count() == 1) { diff --git a/app/Models/StatementTransactionOwner.php b/app/Models/StatementTransactionOwner.php index fb13f4b4..bd96efff 100644 --- a/app/Models/StatementTransactionOwner.php +++ b/app/Models/StatementTransactionOwner.php @@ -5,6 +5,7 @@ namespace App\Models; use Illuminate\Database\Eloquent\Factories\HasFactory; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; +use Illuminate\Database\Eloquent\Relations\MorphTo; class StatementTransactionOwner extends Model { diff --git a/app/Models/Transaction.php b/app/Models/Transaction.php index 631a5fa5..185fdb36 100644 --- a/app/Models/Transaction.php +++ b/app/Models/Transaction.php @@ -221,6 +221,22 @@ class Transaction extends AbstractModel implements Documentable, Transactionable return $query->whereIn('status', [ApprovalStatus::APPROVED]); } + /** + * @param Builder $query + * @return Builder + */ + public function scopeGetReceiverWithJoinStatementTransactionAndOwner(Builder $query, Array $row) { + $query->join('companies',function($q) use ($row) { + $q->on('companies.id','=','transactions.receiver'); + $q->where('debtor',$row['debtor_code']); + }) + ->join('statement_transaction_owners', function ($q) { + $q->on('statement_transaction_owners.owner_id','=','transactions.id'); + $q->where('statement_transaction_owners.owner_type','=',Transaction::class); + }) + ->join('statement_transactions','statement_transactions.id','=','statement_transaction_owners.statement_transaction_id'); + } + /** * @return MorphMany */ From 910f190075c82c4e2467abab2318e6236f1365cd Mon Sep 17 00:00:00 2001 From: Steve Ng Date: Wed, 25 Oct 2023 18:03:31 +0800 Subject: [PATCH 3/5] fixing the unknown tab to list the transactions of is_mapped false and also mapped and status in rejected --- .../IsMappedFalseOrMappedButStatusIn.php | 25 +++++++++++++++++++ .../sections/TransactionsMappingComponent.vue | 2 +- 2 files changed, 26 insertions(+), 1 deletion(-) create mode 100644 app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php diff --git a/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php b/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php new file mode 100644 index 00000000..8b264ff5 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php @@ -0,0 +1,25 @@ +where(function($q) use ($value) { + $q->whereDoesntHave('owners'); + $q->orwhereHas('owners', function($query) use ($value) { + $query->whereIn('status', $value); + }); + }); + } + +} diff --git a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue index 4604f2e5..160221bf 100644 --- a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue +++ b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue @@ -311,7 +311,7 @@ export default { this.filter = {min_amount: 0, is_mapped: true, is_mapped_with_multiple: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [1], per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 3: - this.filter = {min_amount: 0, is_mapped: false, per_page: 100, order_by: {column: 'posting_date', DESC: true}} + this.filter = {min_amount: 0, is_mapped_false_or_mapped_but_status_in: [4], per_page: 100, order_by: {column: 'posting_date', DESC: true}} break; case 4: this.filter = {min_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}} From f47c3c9ecc1e4cfdb81121c85759d88a8ae80431 Mon Sep 17 00:00:00 2001 From: Steve Ng Date: Thu, 26 Oct 2023 00:01:10 +0800 Subject: [PATCH 4/5] fixing the unknown tab to list the transactions of is_mapped false and also mapped and status in rejected --- .../Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php | 4 +--- app/Models/StatementTransaction.php | 5 +++++ 2 files changed, 6 insertions(+), 3 deletions(-) diff --git a/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php b/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php index 8b264ff5..c0eb9e74 100644 --- a/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php +++ b/app/Classes/General/Eloquent/Filters/IsMappedFalseOrMappedButStatusIn.php @@ -16,9 +16,7 @@ class IsMappedFalseOrMappedButStatusIn implements Filter { return $builder->where(function($q) use ($value) { $q->whereDoesntHave('owners'); - $q->orwhereHas('owners', function($query) use ($value) { - $query->whereIn('status', $value); - }); + $q->orwhereDoesntHave('owner_status'); }); } diff --git a/app/Models/StatementTransaction.php b/app/Models/StatementTransaction.php index eb4bcdc8..4bba7903 100644 --- a/app/Models/StatementTransaction.php +++ b/app/Models/StatementTransaction.php @@ -49,6 +49,11 @@ class StatementTransaction extends Model return $this->hasMany(StatementTransactionOwner::class); } + public function owner_status() + { + return $this->owners()->whereIn('status',[ApprovalStatus::APPROVED,ApprovalStatus::COMPLETED,ApprovalStatus::PENDING_VERIFICATION]); + } + public function scopeDoesntMapStatement($query) { $query->whereDoesntHave('owners', function($query){ From 5b681ac8c05e2f1f1fbd9b2292caaa2982322f26 Mon Sep 17 00:00:00 2001 From: Steve Ng Date: Sun, 29 Oct 2023 08:44:31 +0800 Subject: [PATCH 5/5] fixing the structure of export receipt to autocount and import receipt to exchange map failed --- .../Services/ExportsInvoiceTransactions.php | 21 +-- .../Services/ExportsReceiptTransactions.php | 132 ++++++++++++++++++ .../ExportCustomersToExcelController.php | 10 +- .../ImportStatementReceiptsController.php | 11 +- .../sections/TransactionsMappingComponent.vue | 5 +- routes/web.php | 1 + 6 files changed, 158 insertions(+), 22 deletions(-) create mode 100644 app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php diff --git a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php index 2ecaada8..796ec19d 100644 --- a/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php +++ b/app/Classes/Modules/Exports/Services/ExportsInvoiceTransactions.php @@ -34,19 +34,12 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading public function headings(): array { - $header = []; - if ($this->request->input('type') == 'invoices') { - $header[] = 'DocNo'; - $header[] = 'DocDate'; - $header[] = 'DebtorCode'; - } else { - $header[] = 'OrNo'; - $header[] = 'OrDate'; - $header[] = 'CreditorCode'; - } - $header[] = 'Ref'; - $header[] = ($this->request->input('type') == 'invoices' ? 'DebtorName' : 'CreditorName'); - $header = array_merge($header, [ + $header = [ + 'DocNo', + 'DocDate', + 'DebtorCode', + 'Ref', + 'DebtorName', 'CurrencyCode', 'ShipInfo', 'ItemCode', @@ -56,7 +49,7 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading 'UnitPrice', 'AccNo', 'DeptNo' - ]); + ]; return $header; } diff --git a/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php b/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php new file mode 100644 index 00000000..07c5d3c1 --- /dev/null +++ b/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php @@ -0,0 +1,132 @@ +request = $request; + } + + public function headings(): array + { + $header = [ + 'DocNo', + 'DocDate', + 'DebtorCode', + 'Description', + 'DocNo2', + 'ProjNo', + 'DeptNo', + 'CurrencyCode', + 'ToHomeRate', + 'ToDebtorRate', + 'Note', + 'PaymentMethod', + 'ChequeNo', + 'PaymentAmt', + 'BankCharge', + 'ToBankRate', + 'BankChargeTaxType', + 'BankChargeTaxRefNo', + 'BankChargeProjNo', + 'BankChargeDeptNo', + 'PaymentBy', + 'FloatDay', + 'IsRCHQ', + 'RCHQDate', + 'KnockOffDocType', + 'KnockOffDocNo', + 'KnockOffAmt', + '', + ]; + return $header; + } + + /** + * @return \Illuminate\Support\Collection|mixed + */ + public function query() + { + $data = (new ApplyFiltersToQuery())->execute(StatementTransaction::query(), json_decode($this->request->input('filter'), true)); + if ($this->request->has('bankStatementTransactionId')) $data = $data->whereIn('id',json_decode($this->request->input('bankStatementTransactionId'), true)); + + return $data; + } + + /** + * @param StatementTransaction $transaction + * + * @return array + */ + public function map($transaction): array + { + $statementTransactionOwner = $transaction->owners()->whereIn('status', [ApprovalStatus::APPROVED])->first(); + $logArray = [ + 'counter' => $this->counter, + 'system' => $statementTransactionOwner->system, + 'StatementTransactionOwner_id' => $statementTransactionOwner->id, + 'transaction_table_id' => $statementTransactionOwner->owner_id, + ]; + $this->counter += 1; + $logArray = json_encode($logArray); + + $filePath = storage_path('logs/exports_receipt_transactions.log'); + $errorFilePath = storage_path('logs/exports_receipt_transactions_error.log'); + $textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' ' . $logArray . PHP_EOL; + file_put_contents($filePath, $textToAppend, FILE_APPEND); + + $company = Company::where('name',$transaction->transaction_description_2)->first(); + + return [ + '<>', + Carbon::parse($transaction->posting_date)->format('d/m/Y'), + ($company ? $company->debtor : null), + $transaction->transaction_description, + '', + '', + '', + 'MYR', + 1, + 1, + '', + 'MBB', + '', + $transaction->amount, + '', + 1, + '', + '', + '', + '', + '', + '0', + '', + '', + 'RI', + $transaction->transaction_ref, + $transaction->amount, + '', + ]; + } +} diff --git a/app/Http/Controllers/Exports/ExportCustomersToExcelController.php b/app/Http/Controllers/Exports/ExportCustomersToExcelController.php index 7dfe0485..733c84fa 100644 --- a/app/Http/Controllers/Exports/ExportCustomersToExcelController.php +++ b/app/Http/Controllers/Exports/ExportCustomersToExcelController.php @@ -17,6 +17,7 @@ use Illuminate\Support\Facades\Auth; use Maatwebsite\Excel\Excel; use App\Classes\Modules\Exports\Services\ExportsImportedInvoiceMappeds; use App\Models\TransactionMappingLog; +use App\Classes\Modules\Exports\Services\ExportsReceiptTransactions; class ExportCustomersToExcelController { @@ -61,7 +62,14 @@ class ExportCustomersToExcelController public function invoiceTransactions(Request $request){ $exportsTransactions = new ExportsInvoiceTransactions($request); - $response = $exportsTransactions->download(($request->input('type') == 'invoices' ? 'invoice-transactions' : 'receipt-transactions').'.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + $response = $exportsTransactions->download('invoice-transactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); + ob_end_clean(); + return $response; + } + + public function receiptTransactions(Request $request){ + $exportsTransactions = new ExportsReceiptTransactions($request); + $response = $exportsTransactions->download('receipt-transactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']); ob_end_clean(); return $response; } diff --git a/app/Http/Controllers/Imports/ImportStatementReceiptsController.php b/app/Http/Controllers/Imports/ImportStatementReceiptsController.php index 8021e3a9..f3b89db7 100644 --- a/app/Http/Controllers/Imports/ImportStatementReceiptsController.php +++ b/app/Http/Controllers/Imports/ImportStatementReceiptsController.php @@ -21,6 +21,7 @@ use App\Models\TransactionMappingLog; use App\Classes\ValueObjects\Response\ApiResponseObject; use App\Classes\ValueObjects\Constants\HttpStatus; use Illuminate\Http\JsonResponse; +use Illuminate\Support\Facades\DB; class ImportStatementReceiptsController { @@ -78,11 +79,11 @@ class ImportStatementReceiptsController private function mappingExchange(Array $row) { $date = $row['date']; - $transactions = Transaction::where('original_amount', $row['local_payment_amount'])->whereRaw("DATE(created_at) = '$date'") - ->whereHas('issuerCompany', function($q) use($row) { - $q->where('debtor',$row['debtor_code']); - }) - ->get(); + $transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where('statement_transactions.amount', $row['payment_amount'])->whereRaw("DATE(posting_date) = '$date'")->get(); + + if ($transactions && $transactions->count() == 0) { + $transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where(DB::raw('FLOOR(statement_transactions.amount)'), floor($row['payment_amount']))->whereRaw("DATE(posting_date) = '$date'")->get(); + } if ($transactions && $transactions->count() == 1) { foreach ($transactions as $key => $transaction) { diff --git a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue index 160221bf..7a677bad 100644 --- a/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue +++ b/resources/assets/vue/components/accounting/sections/TransactionsMappingComponent.vue @@ -267,7 +267,7 @@ export default { exportInvoiceToAutoCount(){ const checkedStatementTransactions = this.getCheckedStatementOwners(); - let route = this.route('invoiceTransactions.export')+'?type=invoices&filter='+JSON.stringify(this.filter); + let route = this.route('invoiceTransactions.export')+'?filter='+JSON.stringify(this.filter); if (checkedStatementTransactions) { route += '&bankStatementTransactionId='+checkedStatementTransactions; } @@ -277,7 +277,8 @@ export default { exportReceiptToAutoCount(){ const checkedStatementTransactions = this.getCheckedStatementOwners(); - let route = this.route('invoiceTransactions.export')+'?type=receipts&filter='+JSON.stringify(this.filter); + this.filter['statement_transaction_owner_type_in'] = [3,4,5,7,13,14]; + let route = this.route('receiptTransactions.export')+'?filter='+JSON.stringify(this.filter); if (checkedStatementTransactions) { route += '&bankStatementTransactionId='+checkedStatementTransactions; } diff --git a/routes/web.php b/routes/web.php index 1dece5c3..18f8aa86 100644 --- a/routes/web.php +++ b/routes/web.php @@ -261,6 +261,7 @@ Route::get('/export/payment-transactions/f614e339d7058904a831aad742e24d55', 'Exp Route::get('/export/wallet-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@walletTransactions')->name('walletTransactions.export'); Route::get('/export/booking-transactions', 'Exports\ExportCustomersToExcelController@bookingTransactions')->name('export.transactions.booking'); Route::get('/export/invoice-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@invoiceTransactions')->name('invoiceTransactions.export'); +Route::get('/export/invoice-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@receiptTransactions')->name('receiptTransactions.export'); Route::get('/export/imported-invoice-mapped', 'Exports\ExportCustomersToExcelController@importedInvoiceMapped')->name('importedInvoiceMapped.export'); Route::get('/products', function (\App\Classes\Modules\Exports\Services\ExportsProducts $exportsProducts) {