diff --git a/app/Classes/Modules/Accounting/ControllersLogic/ImportAmbankStatementLogic.php b/app/Classes/Modules/Accounting/ControllersLogic/ImportAmbankStatementLogic.php index a1c253c0..e5d7adf0 100644 --- a/app/Classes/Modules/Accounting/ControllersLogic/ImportAmbankStatementLogic.php +++ b/app/Classes/Modules/Accounting/ControllersLogic/ImportAmbankStatementLogic.php @@ -14,6 +14,7 @@ use Exception; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; use Illuminate\Support\Carbon; +use Illuminate\Support\Collection; use Illuminate\Support\Facades\Log; use Maatwebsite\Excel\Facades\Excel; @@ -44,19 +45,24 @@ class ImportAmbankStatementLogic extends AbstractControllerLogic foreach ($object->getFiles() as $file){ $collection = Excel::toCollection(null, json_decode($file)->file_info->original->file, null, null, true); - $statementDetails = $collection->first(); + $statementDetailRows = $collection->first()->slice(0,13); - $statementDateRange = trim(explode(':', $statementDetails[3][0])[1]); + $dateInfoKey = $this->findInfoIndexFromExcelCollection($statementDetailRows, "STATEMENT DATE"); + $statementDateRange = trim(explode(':', $this->extractInfoFromExcelCollection($statementDetailRows[$dateInfoKey])[0])[1]); $dateFrom = trim(explode('-', $statementDateRange)[0]); $dateTo = trim(explode('-', $statementDateRange)[1]); $dateFrom = carbon::createFromFormat('d/m/Y', $dateFrom); $dateTo = carbon::createFromFormat('d/m/Y', $dateTo); - $dateTo = carbon::parse($dateTo); - $totalDebit = $statementDetails[7][7]; - $totalCredit = $statementDetails[8][7]; + $dateTo = carbon::parse($dateTo); + $totalDebitKey = $this->findInfoIndexFromExcelCollection($statementDetailRows, "TOTAL DEBIT"); + $totalDebit = $this->extractInfoFromExcelCollection($statementDetailRows[$totalDebitKey])[1]; + $totalCreditKey = $this->findInfoIndexFromExcelCollection($statementDetailRows, "TOTAL CREDIT"); + $totalCredit = $this->extractInfoFromExcelCollection($statementDetailRows[$totalCreditKey])[1]; $totalTransactions = $totalDebit + $totalCredit; - $beginBalance = ((float) str_replace(',', '', $statementDetails[6][10])); - $endBalance = ((float) str_replace(',', '', $statementDetails[9][10])); + $beginBalanceKey = $this->findInfoIndexFromExcelCollection($statementDetailRows, "OPENING BALANCE"); + $beginBalance = ((float) str_replace(',', '', $this->extractInfoFromExcelCollection($statementDetailRows[$beginBalanceKey])[1])); + $endBalanceKey = $this->findInfoIndexFromExcelCollection($statementDetailRows, "CLOSING BALANCE"); + $endBalance = ((float) str_replace(',', '', $this->extractInfoFromExcelCollection($statementDetailRows[$endBalanceKey])[1])); $account = StatementAccount::where('number', 8881040198515)->first(); @@ -86,140 +92,123 @@ class ImportAmbankStatementLogic extends AbstractControllerLogic $collection->map(function ($sheet, $key) use ($statement) { if ($key === 0) { - $sheet->slice(13)->map(function ($row, $index) use ($statement, $sheet, $key) { - if (!$row[0] || !$row[11]) { - return; - } - - $postingDate = carbon::createFromFormat('dM', trim($row[0])); - - $description = trim($row[1]); - - $nextRow = $sheet->slice(13)[$index + 1]; - - if (!$nextRow[0] && $nextRow[1]) { - foreach ($nextRow as $col) { - if ($col) { - $description .= ' '. $col; - } - } - } - - $descriptionArr = explode(',', $description); - - $transactionDescription = array_key_exists(0, $descriptionArr) ? trim($descriptionArr[0]) : ""; - $description2 = array_key_exists(1, $descriptionArr) ? trim($descriptionArr[1]) : ""; - $description3 = array_key_exists(2, $descriptionArr) ? trim($descriptionArr[2]) : ""; - $description4 = array_key_exists(3, $descriptionArr) ? trim($descriptionArr[3]) : ""; - $description5 = array_key_exists(4, $descriptionArr) ? trim($descriptionArr[4]) : ""; - - if (count($descriptionArr) > 5) { - for ($i = 5; $i < count($descriptionArr); $i++) { - $description5 = $description5 . array_key_exists($i, $descriptionArr) ? trim($descriptionArr[$i]) : ""; - } - } - - $amount = $row[9] ? ((float) str_replace(',', '', trim($row[9]))) : (-((float) str_replace(',', '', $row[8]))); - $endBalance = ((float) str_replace(',', '', $row[11])); - $transaction = new StatementTransaction([ - 'posting_date' => $postingDate, - 'transaction_description' => $transactionDescription, - 'transaction_description_2' => $description2, - 'transaction_description_3' => $description3, - 'transaction_description_4' => $description4, - 'transaction_description_5' => $description5, - 'amount' => $amount, - 'end_balance' => $endBalance, - ]); - - // Check if the transaction already exists for this statement - $existingTransaction = StatementTransaction::whereDate('posting_date', $postingDate) - ->where('amount', $amount) - ->where('transaction_description', $transactionDescription) - ->whereRaw("CAST(REPLACE(end_balance,',','') AS DECIMAL(15,2)) = ?",[$endBalance]) - ->first(); - - if (!$existingTransaction) { - $statement->transactions()->save($transaction); - } - - return $transaction; - }); + $headerColumnKey = $this->findInfoIndexFromExcelCollection($sheet->slice(11), "DATE"); + $dateColumnKey = $this->findInfoIndexFromExcelCollection($sheet->slice(11)[$headerColumnKey], "DATE"); + $descriptionColumnKey = $this->findInfoIndexFromExcelCollection($sheet->slice(11)[$headerColumnKey], "TRANSACTION"); + $debitColumnKey = $this->findInfoIndexFromExcelCollection($sheet->slice(11)[$headerColumnKey], "DEBIT"); + $creditColumnKey = $this->findInfoIndexFromExcelCollection($sheet->slice(11)[$headerColumnKey], "CREDIT"); + $balanceColumnKey = $this->findInfoIndexFromExcelCollection($sheet->slice(11)[$headerColumnKey], "BALANCE"); } else { if (strpos($sheet->first()->first(), "DATE") === false) { return; } - - $extraColumn = 0; - if (count($sheet->first()) > 7 && $sheet->first()[7]) { - $extraColumn = 1; + $headerColumnKey = $this->findInfoIndexFromExcelCollection($sheet, "DATE"); + $dateColumnKey = $this->findInfoIndexFromExcelCollection($sheet[$headerColumnKey], "DATE"); + $descriptionColumnKey = $this->findInfoIndexFromExcelCollection($sheet[$headerColumnKey], "TRANSACTION"); + $debitColumnKey = $this->findInfoIndexFromExcelCollection($sheet[$headerColumnKey], "DEBIT"); + $creditColumnKey = $this->findInfoIndexFromExcelCollection($sheet[$headerColumnKey], "CREDIT"); + $balanceColumnKey = $this->findInfoIndexFromExcelCollection($sheet[$headerColumnKey], "BALANCE"); + } + + $sheet->slice($headerColumnKey + 1)->map(function ($row, $index) use ( + $statement, + $sheet, + $dateColumnKey, + $descriptionColumnKey, + $debitColumnKey, + $creditColumnKey, + $balanceColumnKey, + $key) + { + // if date or balance is null or empty, skip the row + if (!$row[$dateColumnKey] || !$row[$balanceColumnKey]) { + return; } - $sheet->slice(1)->map(function ($row, $index) use ($statement, $sheet, $extraColumn, $key) { - if (!$row[0] || !$row[6 + $extraColumn]) { - return; - } + $postingDate = carbon::createFromFormat('dM', trim($row[$dateColumnKey])); - $postingDate = carbon::createFromFormat('dM', trim($row[0])); + $description = trim($row[$descriptionColumnKey]); - $description = trim($row[1]); + $nextRow = $sheet[$index + 1]; - $nextRow = $sheet->slice(1)[$index + 1]; - - if (!$nextRow[0] && $nextRow[1]) { - foreach ($nextRow as $col) { - if ($col) { - $description .= ' '. $col; - } + if (!$nextRow[$dateColumnKey] && $nextRow[$descriptionColumnKey]) { + $nextRowInfoArr = $this->extractInfoFromExcelCollection($nextRow); + foreach ($nextRowInfoArr as $col) { + if ($col) { + $description .= ' '. $col; } } + } - $descriptionArr = explode(',', $description); + $descriptionArr = explode(',', $description); - $transactionDescription = array_key_exists(0, $descriptionArr) ? trim($descriptionArr[0]) : ""; - $description2 = array_key_exists(1, $descriptionArr) ? trim($descriptionArr[1]) : ""; - $description3 = array_key_exists(2, $descriptionArr) ? trim($descriptionArr[2]) : ""; - $description4 = array_key_exists(3, $descriptionArr) ? trim($descriptionArr[3]) : ""; - $description5 = array_key_exists(4, $descriptionArr) ? trim($descriptionArr[4]) : ""; - - if (count($descriptionArr) > 5) { - for ($i = 5; $i < count($descriptionArr); $i++) { - $description5 = $description5 . array_key_exists($i, $descriptionArr) ? trim($descriptionArr[$i]) : ""; - } + $transactionDescription = array_key_exists(0, $descriptionArr) ? trim($descriptionArr[0]) : ""; + $description2 = array_key_exists(1, $descriptionArr) ? trim($descriptionArr[1]) : ""; + $description3 = array_key_exists(2, $descriptionArr) ? trim($descriptionArr[2]) : ""; + $description4 = array_key_exists(3, $descriptionArr) ? trim($descriptionArr[3]) : ""; + $description5 = array_key_exists(4, $descriptionArr) ? trim($descriptionArr[4]) : ""; + + if (count($descriptionArr) > 5) { + for ($i = 5; $i < count($descriptionArr); $i++) { + $description5 = array_key_exists($i, $descriptionArr) ? $description5 . " " . trim($descriptionArr[$i]) : $description5; } + } - $amount = $row[5 + $extraColumn] ? ((float) str_replace(',', '', trim($row[5 + $extraColumn]))) : (-((float) str_replace(',', '', $row[4 + $extraColumn]))); - $endBalance = ((float) str_replace(',', '', $row[6 + $extraColumn])); - $transaction = new StatementTransaction([ - 'posting_date' => $postingDate, - 'transaction_description' => $transactionDescription, - 'transaction_description_2' => $description2, - 'transaction_description_3' => $description3, - 'transaction_description_4' => $description4, - 'transaction_description_5' => $description5, - 'amount' => $amount, - 'end_balance' => $endBalance, - ]); + $amount = $row[$creditColumnKey] ? ((float) str_replace(',', '', trim($row[$creditColumnKey]))) : (-((float) str_replace(',', '', $row[$debitColumnKey]))); + $endBalance = ((float) str_replace(',', '', $row[$balanceColumnKey])); + $transaction = new StatementTransaction([ + 'posting_date' => $postingDate, + 'transaction_description' => $transactionDescription, + 'transaction_description_2' => $description2, + 'transaction_description_3' => $description3, + 'transaction_description_4' => $description4, + 'transaction_description_5' => $description5, + 'amount' => $amount, + 'end_balance' => $endBalance, + ]); - // Check if the transaction already exists for this statement - $existingTransaction = StatementTransaction::whereDate('posting_date', $postingDate) - ->where('amount', $amount) - ->where('transaction_description', $transactionDescription) - ->whereRaw("CAST(REPLACE(end_balance,',','') AS DECIMAL(15,2)) = ?",[$endBalance]) - ->first(); + // Check if the transaction already exists for this statement + $existingTransaction = StatementTransaction::whereDate('posting_date', $postingDate) + ->where('amount', $amount) + ->where('transaction_description', $transactionDescription) + ->whereRaw("CAST(REPLACE(end_balance,',','') AS DECIMAL(15,2)) = ?",[$endBalance]) + ->first(); + + if (!$existingTransaction) { + $statement->transactions()->save($transaction); + } - if (!$existingTransaction) { - $statement->transactions()->save($transaction); - } - - return $transaction; - }); - } + return $transaction; + }); }); } return $this->response([]); + } + private function findInfoIndexFromExcelCollection($collection, $keyword) + { + foreach ($collection as $key => $row) { + if ($row instanceof Collection) { + $infoArr = $this->extractInfoFromExcelCollection($row); + foreach ($infoArr as $info) { + if (str_contains(strtolower($info), strtolower($keyword))) { + return $key; + } + } + } else { + if (str_contains(strtolower($row), strtolower($keyword))) { + return $key; + } + } + + } + } + + // return an array with information of the row start from 0 index + private function extractInfoFromExcelCollection($collection) + { + return array_values(array_filter($collection->toArray())); } } diff --git a/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php b/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php index 71363b52..e629675f 100644 --- a/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php +++ b/app/Classes/Modules/Exports/Services/ExportsImportedInvoiceMappeds.php @@ -39,7 +39,8 @@ class ExportsImportedInvoiceMappeds implements FromQuery, WithHeadings, WithHead 'Net Total', 'Cancelled', 'Mapped Status', - 'Mapped Reference No' + 'Mapped Reference No', + 'MapPayment Received Date' ]; } @@ -72,6 +73,7 @@ class ExportsImportedInvoiceMappeds implements FromQuery, WithHeadings, WithHead Arr::get($data,'cancelled'), Arr::get($data,'mapped_status'), Arr::get($data,'mapped_result_reference'), + Arr::get($data,'payment_received_date'), ]; } diff --git a/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php b/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php index 07c5d3c1..bde46225 100644 --- a/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php +++ b/app/Classes/Modules/Exports/Services/ExportsReceiptTransactions.php @@ -15,8 +15,11 @@ use Illuminate\Support\Facades\Log; use App\Classes\General\Eloquent\ApplyFiltersToQuery; use App\Models\StatementTransaction; use App\Models\Company; +use Maatwebsite\Excel\Concerns\WithEvents; +use Maatwebsite\Excel\Concerns\WithCustomStartCell; +use Maatwebsite\Excel\Events\AfterSheet; -class ExportsReceiptTransactions implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize +class ExportsReceiptTransactions implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize, WithEvents, WithCustomStartCell { use Exportable; @@ -28,37 +31,101 @@ class ExportsReceiptTransactions implements FromQuery, WithHeadings, WithHeading $this->request = $request; } + public function startCell(): string + { + return 'A2'; + } + + public function registerEvents(): array { + + return [ + AfterSheet::class => function(AfterSheet $event) { + $sheet = $event->sheet; + + $sheet->mergeCells('A1:A1'); + $sheet->setCellValue('A1', '"'); + + $sheet->mergeCells('M1:Y1'); + $sheet->setCellValue('M1', "Payment Detail Column"); + + $sheet->mergeCells('Z1:AB1'); + $sheet->setCellValue('Z1', "Knock Off Detail"); + + $styleArray = [ + 'alignment' => [ + 'horizontal' => \PhpOffice\PhpSpreadsheet\Style\Alignment::HORIZONTAL_CENTER, + ], + ]; + + $cellRange = 'A1:AB1'; + $event->sheet->getDelegate()->getStyle($cellRange)->applyFromArray($styleArray); + }, + ]; + } + public function headings(): array { $header = [ - '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', - '', + [ + ' ', + '(20 chars)', + '(Date: dd/MM/yyyy)', + '(12 chars)', + '(40 chars)', + '(25 chars)', + '(10 chars)', + '(10 chars)', + '(5 chars)', + '(Number, use System Currency Rate Decimal)', + '(Number, use System Currency Rate Decimal)', + '(Rich Text)', + '(20 chars)', + '(20 chars)', + '(Number, use System Currency Decimal)', + '(Number, use System Currency Decimal)', + '(Number, use System Currency Rate Decimal)', + '(14 chars)', + '(30 chars)', + '(10 chars)', + '(10 chars)', + '(20 chars)', + '(Integer)', + '(Boolean. Indicate T for stock control or F for non stock control)', + '(Returned Cheque Date: dd/MM/yyyy)', + '(2 chars, RI for Invoice, RD for D/N)', + '', + '(Number, use System Currency Decimal)', + ], + [ + 'DocNo', + 'DocDate', + 'DebtorCode', + 'Description', + 'DocNo2', + 'ProjNo', + 'DeptNo', + 'CurrencyCode', + 'ToHomeRate', + 'ToDebtorRate', + 'Note', + 'PaymentMethod', + 'ChequeNo', + 'PaymentAmt', + 'BankCharge', + 'ToBankRate', + 'BankChargeTaxType', + 'BankChargeTaxRefNo', + 'BankChargeProjNo', + 'BankChargeDeptNo', + 'PaymentBy', + 'FloatDay', + 'IsRCHQ', + 'RCHQDate', + 'KnockOffDocType', + 'KnockOffDocNo', + 'KnockOffAmt', + '', + ] ]; return $header; } @@ -102,7 +169,7 @@ class ExportsReceiptTransactions implements FromQuery, WithHeadings, WithHeading '<>', Carbon::parse($transaction->posting_date)->format('d/m/Y'), ($company ? $company->debtor : null), - $transaction->transaction_description, + 'Payment for '.$transaction->transaction_description, '', '', '', diff --git a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php index b6cfd567..75953f2b 100644 --- a/app/Http/Controllers/Imports/ImportStatementInvoiceController.php +++ b/app/Http/Controllers/Imports/ImportStatementInvoiceController.php @@ -40,18 +40,22 @@ class ImportStatementInvoiceController if (str_starts_with($row['shipping_info'], 'TOPUP')) { // find in exchange first, if cannont then find in izyim foreach (['exchange','izyim'] as $system) { - $returnReference = $this->mappingTopUp($row, $system); + [$returnReference, $transactionDate] = $this->mappingTopUp($row, $system); if ($returnReference) { + // $row['mapped_result_reference'] = $data['owner_reference']; + // $row['payment_received_date'] = date('Y-m-d', strtotime($data['created_at'])); $row['mapped_result_reference'] = $returnReference; + $row['payment_received_date'] = $transactionDate ? date('d-m-Y', strtotime($transactionDate)) : null; $row['mapped_status'] = 'success'; return $row; } } } - $returnReference = $this->mappingExchange($row); + [$returnReference, $transactionDate] = $this->mappingExchange($row); if ($returnReference) { $row['mapped_result_reference'] = $returnReference; + $row['payment_received_date'] = date('d-m-Y', strtotime($transactionDate)); $row['mapped_status'] = 'success'; return $row; } @@ -88,6 +92,7 @@ class ImportStatementInvoiceController $data = []; foreach ($excelRows as $row) { $row['mapped_result_reference'] = null; + $row['payment_received_date'] = null; $row['mapped_status'] = 'failed'; $row['date'] = in_array(gettype($row['date']), ['integer', 'double']) ? $this->changeExcelDate($row['date']) : date('Y-m-d', strtotime($row['date'])); @@ -144,7 +149,8 @@ class ImportStatementInvoiceController private function mappingTopUp(Array $row, String $system) { try { if ($data = (App()->make(ChecksBillNumber::class))->execute($row['shipping_info'], $system)) { - if ($system == 'izyim' && isset($data['owner_reference'])) return $data['owner_reference']; + // if ($system == 'izyim' && isset($data['owner_reference'])) return $data; + if ($system == 'izyim' && isset($data['owner_reference'])) return [$data['owner_reference'], null]; if ($system == 'exchange') return $this->updateTransactionOwnerReference($data, $row['doc_no']); } @@ -168,7 +174,7 @@ class ImportStatementInvoiceController if ($transaction && $transaction->count() > 0) { return $this->updateTransactionOwnerReference($transaction, $row['doc_no']); } - return false; + return [false, false]; } public function updateTransactionOwnerReference($transaction, String $docNo) { @@ -178,9 +184,9 @@ class ImportStatementInvoiceController 'invoice_reference'=>$docNo, 'status'=>ApprovalStatus::COMPLETED ]); - return $transactionOwner->owner_reference; + return [$transactionOwner->owner_reference, $transaction->created_at]; } - return false; + return [false, false]; } public function changeExcelDate($date) diff --git a/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue b/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue index 9fd29e45..f10f9181 100644 --- a/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue +++ b/resources/assets/vue/components/accounting/sections/ImportedInvoiceMappedComponent.vue @@ -39,6 +39,7 @@ {{item.cancelled}} {{item.mapped_status}} {{item.mapped_result_reference}} + {{item.payment_received_date}} @@ -101,7 +102,7 @@ }, appendComponentTableHeader() { if (this.section == 'importInvoiceMapping') { - this.tableHeaders = ['No','Doc No','Date','Debtor Code','Debtor Name','Shipping Info','Net Total','Cancelled','Mapped Status','Mapped Reference No']; + this.tableHeaders = ['No','Doc No','Date','Debtor Code','Debtor Name','Shipping Info','Net Total','Cancelled','Mapped Status','Mapped Reference No','Payment Received Date']; } else { this.tableHeaders = ['No','OR No','Date','Creditor Code','Creditor Name','Shipping Info','Net Total','Cancelled','Mapped Status','Mapped Reference No']; }