mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-24 15:04:19 +00:00
Merge branch 'dillon/accounting-bank-mapping' into 'development'
fix and update the functionality and the ui for accounting automation See merge request CIEFWorldwideSdnBhd/exchange-2.0!132
This commit is contained in:
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class IsMapped implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return Builder|mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $value ? $builder->whereHas('owners') : $builder->whereDoesntHave('owners');
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class IsMappedWithMultiple implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return Builder|mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $value ? $builder->has('owners', '>', 1) : $builder->has('owners', '=',1);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class MaxAmount implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return Builder|mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->where('amount', '<=', $value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class MinAmount implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return Builder|mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->where('amount', '>=', $value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class StatementTransactionAccountId implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->whereHas('account', function ($query) use ($value) {
|
||||
$query->where('statement_accounts.id', $value);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class StatementTransactionOwnerStatusIn implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return Builder|mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->whereHas('owners', function ($query) use ($value) {
|
||||
return $query->whereIn('status', $value);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,22 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class StatementTransactionOwnerTypeIn implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return Builder|mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->whereHas('owners', function ($query) use ($value) {
|
||||
return $query->whereIn('type', $value);
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
+3
-16
@@ -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)
|
||||
@@ -0,0 +1,147 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Accounting\ControllersLogic;
|
||||
|
||||
|
||||
use App\Classes\Exceptions\MalformedRequestException;
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Jobs\CreateBankStatementTransactionOwners;
|
||||
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Models\AccountStatement;
|
||||
use App\Models\StatementAccount;
|
||||
use App\Models\StatementTransaction;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Carbon;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class ImportBankStatementLogic extends AbstractControllerLogic
|
||||
{
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function notification():array {
|
||||
return [
|
||||
'title' => '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([]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
+53
@@ -0,0 +1,53 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Accounting\ControllersLogic;
|
||||
|
||||
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Modules\Accounting\Services\ListsBankStatementDetails;
|
||||
use App\Classes\Modules\Accounting\Services\ListsBankStatementTransactions;
|
||||
use App\Http\Resources\BankStatementTransactionResource;
|
||||
use App\Models\StatementTransaction;
|
||||
use ErrorException;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ListBankStatementTransactionsLogic extends AbstractControllerLogic
|
||||
{
|
||||
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function notification():array {
|
||||
return [
|
||||
'title' => '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));
|
||||
}
|
||||
|
||||
}
|
||||
@@ -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);
|
||||
|
||||
@@ -1,212 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Accounting\Processors;
|
||||
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\PaymentMethodType;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Models\AccountStatement;
|
||||
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 Illuminate\Support\Facades\Log;
|
||||
use DateTime;
|
||||
|
||||
class CreateBankStatementDetailsProcessor
|
||||
{
|
||||
|
||||
/**
|
||||
* @param $transactions
|
||||
* @return true
|
||||
* @throws \App\Classes\Exceptions\MalformedRequestException
|
||||
*/
|
||||
public function execute(AccountStatement $statement) {
|
||||
|
||||
$transactions = $statement->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 = '<table><tr><th>'.implode('</th><th>', $headers).'</th></tr>';
|
||||
$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,
|
||||
];
|
||||
}
|
||||
}
|
||||
+275
@@ -0,0 +1,275 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Accounting\Processors;
|
||||
|
||||
use App\Classes\Exceptions\MalformedRequestException;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\PaymentMethodType;
|
||||
use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Models\AccountStatement;
|
||||
use App\Models\Booking;
|
||||
use App\Models\Company;
|
||||
use App\Models\Group;
|
||||
use App\Models\StatementTransaction;
|
||||
use App\Models\StatementTransactionOwner;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\Wallet;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use DateTime;
|
||||
|
||||
class CreateBankStatementTransactionOwnersProcessor
|
||||
{
|
||||
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function execute() {
|
||||
|
||||
// $transactions = StatementTransaction::whereDoesntHave('owners', function($query){
|
||||
// return $query->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,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Accounting\Services;
|
||||
|
||||
use App\Classes\General\Eloquent\AbstractListRecord;
|
||||
use App\Models\StatementTransaction;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use App\Models\StatementTransactionOwner;
|
||||
|
||||
class ListsBankStatementTransactions extends AbstractListRecord
|
||||
{
|
||||
|
||||
/** @var StatementTransaction */
|
||||
private $repository;
|
||||
|
||||
/**
|
||||
* ListsBankStatementDetails constructor.
|
||||
* @param StatementTransaction $repository
|
||||
*/
|
||||
public function __construct(StatementTransaction $repository)
|
||||
{
|
||||
$this->repository = $repository;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @return Builder
|
||||
*/
|
||||
public function getRepository(): Builder
|
||||
{
|
||||
return $this->repository->newQuery();
|
||||
}
|
||||
}
|
||||
@@ -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();
|
||||
|
||||
@@ -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
|
||||
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -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
|
||||
]);
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -23,6 +23,7 @@ class FileType
|
||||
'application/pdf' => 'pdf',
|
||||
'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet' => 'excel',
|
||||
'application/vnd.ms-excel' => 'excel',
|
||||
'text/plain' => 'text',
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,37 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\ValueObjects\Constants;
|
||||
|
||||
final class StatementTransactionOwnerType {
|
||||
|
||||
public const UNKNOWN = 0;
|
||||
|
||||
public const SALES = 1;
|
||||
|
||||
public const WALLET_TOP_UP = 2;
|
||||
|
||||
public const WALLET_WITHDRAWAL = 3;
|
||||
|
||||
public const CUSTOMER_REFUND = 4;
|
||||
|
||||
public const SUPPLIER_PAYMENT = 5;
|
||||
|
||||
public const INTERNAL_BANK_TRANSFER_OUT = 6;
|
||||
|
||||
public const INTERNAL_BANK_TRANSFER_IN = 7;
|
||||
|
||||
public const SALARY = 8;
|
||||
|
||||
public const STATUTORY = 9;
|
||||
|
||||
public const FPX_CHARGE = 10;
|
||||
|
||||
public const FPX_CHARGE_REFUND = 11;
|
||||
|
||||
public const BANK_CHARGE = 12;
|
||||
|
||||
public const CREDIT_CARD_PAYMENT = 13;
|
||||
|
||||
public const NON_OPERATIONAL = 14;
|
||||
|
||||
}
|
||||
@@ -2,34 +2,27 @@
|
||||
|
||||
namespace App\Http\Controllers\Accounting;
|
||||
|
||||
use App\Classes\Jobs\CreateBankStatementDetails;
|
||||
use App\Classes\Jobs\CreateBankStatementTransactionOwners;
|
||||
use App\Classes\Modules\Accounting\ControllersLogic\ImportBankStatementLogic;
|
||||
use App\Classes\Modules\Accounting\ControllersLogic\ListBankStatementDetailsLogic;
|
||||
use App\Classes\Modules\Accounting\ControllersLogic\ListBankStatementTransactionsLogic;
|
||||
use App\Classes\Modules\Accounting\ControllersLogic\UpdateBankStatementDetailLogic;
|
||||
use App\Classes\Modules\Imports\Services\BankStatementImport;
|
||||
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\StatementTransactionOwner;
|
||||
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 Illuminate\Support\Facades\Log;
|
||||
use DateTime;
|
||||
|
||||
|
||||
use PhpOffice\PhpSpreadsheet\Shared\Date;
|
||||
|
||||
class BankStatementController extends Controller
|
||||
{
|
||||
public function index(Request $request)
|
||||
@@ -55,134 +48,48 @@ class BankStatementController extends Controller
|
||||
});
|
||||
}
|
||||
|
||||
$statements = $statementsQuery->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 redirect()->back()->with('message', 'Rerun triggered successfully');
|
||||
return $logic->execute($request);
|
||||
}
|
||||
|
||||
public function rerun()
|
||||
{
|
||||
CreateBankStatementTransactionOwners::dispatch();
|
||||
return redirect()->back()->with('success', 'Rerun triggered successfully');
|
||||
}
|
||||
|
||||
public function show(AccountStatement $statement, Request $request)
|
||||
@@ -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,
|
||||
|
||||
@@ -1,37 +0,0 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class BankStatementDetailResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
return [
|
||||
'id' => $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,
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,65 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use App\Models\Booking;
|
||||
use App\Models\Group;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\Wallet;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class BankStatementTransactionOwnerResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
$reference = null;
|
||||
$referenceLink = null;
|
||||
if($this->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
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,36 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class BankStatementTransactionResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
|
||||
return [
|
||||
'id' => $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)
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
+10
-12
@@ -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');
|
||||
}
|
||||
@@ -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');
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType;
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateStatementTransactionOwnersTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('statement_transaction_owners', function (Blueprint $table) {
|
||||
$table->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');
|
||||
}
|
||||
}
|
||||
@@ -1,43 +0,0 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateStatementTransactionsDetailsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('statement_transactions_details', function (Blueprint $table) {
|
||||
$table->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');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
<template>
|
||||
<div class="row m-b-10">
|
||||
<div class="col">
|
||||
<div class="row p-b-10 b-b b-grey">
|
||||
<div class="col-2">{{ item.posting_date }}</div>
|
||||
<div class="col-2">{{ item.transaction_description_1 + ' - ' + item.transaction_description_2 }}</div>
|
||||
<div class="col-5" v-if="item.owners.length === 1">
|
||||
<div class="row">
|
||||
<div class="col">{{item.owners[0].system}}</div>
|
||||
<div class="col">{{ typeString(item.owners[0].type) }}</div>
|
||||
<div class="col"><a :href="item.owners[0].reference_link" target="_blank">{{item.owners[0].reference}}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5" v-if="item.owners.length > 1">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row" v-for="owner in item.owners">
|
||||
<div class="col">
|
||||
{{ owner.system }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="row" v-for="owner in item.owners">
|
||||
<div class="col">
|
||||
{{ typeString(owner.type) }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col">
|
||||
<div class="row" v-for="owner in item.owners">
|
||||
<div class="col">
|
||||
<a :href="owner.reference_link" target="_blank">{{ owner.reference }}</a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5" v-if="!item.owners.length">
|
||||
<div class="row">
|
||||
<div class="col">N/A</div>
|
||||
<div class="col">N/A</div>
|
||||
<div class="col">N/A</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1">{{ item.amount }}</div>
|
||||
</div>
|
||||
<!-- <span v-for="owner in item.owners">{{owner.system + ' - ' + owner.owner_id}}</span>-->
|
||||
<!-- [0].system + ' - ' + item.owner_guess[0].bill_no-->
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import componentHandler from '../../../general/mixins/componentHandler';
|
||||
export default {
|
||||
methods: {
|
||||
typeString(type){
|
||||
switch(type) {
|
||||
case 1:
|
||||
return 'Sales';
|
||||
case 2:
|
||||
return 'Wallet Top Up';
|
||||
case 3:
|
||||
return 'Wallet Withdrawal';
|
||||
case 4:
|
||||
return 'Payment Refund';
|
||||
case 5:
|
||||
return 'Supplier Payment';
|
||||
case 6:
|
||||
return 'Internal Bank Transfer Out';
|
||||
case 7:
|
||||
return 'Internal Bank Transfer In';
|
||||
case 8:
|
||||
return 'Salary Payment';
|
||||
case 9:
|
||||
return 'Statutory Payment';
|
||||
case 10:
|
||||
return 'FPX Charges';
|
||||
case 11:
|
||||
return 'FPX Charges Refund';
|
||||
case 12:
|
||||
return 'Bank Charges';
|
||||
case 13:
|
||||
return 'Credit Card Payment';
|
||||
case 14:
|
||||
return 'Non-Operational Payment';
|
||||
}
|
||||
}
|
||||
},
|
||||
mixins: [componentHandler]
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,59 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row" @keyup.enter="submitForm">
|
||||
<div class="col">
|
||||
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="$store.getters.isLoading(section)"></loading-component>
|
||||
<div class="row" v-show="!$store.getters.isLoading(section)">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<file-input-component :validator="$v.parameters.files" v-model="parameters.files">
|
||||
<template slot="label">
|
||||
<div class="font-heading fs-11 text-primary all-caps">Import Bank Statement CSV</div>
|
||||
</template>
|
||||
</file-input-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-sm btn-block p-t-10 p-b-10 p-r-35 p-l-35 btn-success b-rad-none" @click="submitForm">Upload</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
import formHandler from '../../../general/mixins/formHandler';
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
parameters: {
|
||||
files: []
|
||||
}
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
parameters: {
|
||||
files: {
|
||||
required
|
||||
}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitForm(){
|
||||
this.submit(this.route('api.accounting.statement.import'), 'post', this.section, true, false)
|
||||
}
|
||||
},
|
||||
mixins: [formHandler]
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,185 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row justify-content-center align-items-center m-t-50 m-b-50" v-show="step === 0">
|
||||
<div class="col-5">
|
||||
<div class="row text-center">
|
||||
<div class="col b-a b-grey padding-50 m-r-15 pointer" :class="[{'bg-complete': type === 1}, {'text-white': type === 1}]" @click="type=1">Receivable Mapping</div>
|
||||
<div class="col b-a b-grey padding-50 pointer" :class="[{'bg-complete': type === 2}, {'text-white': type === 2}]" @click="type=2">Payable Mapping</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center align-items-center m-t-50 m-b-50" v-if="type">
|
||||
<div class="col-8">
|
||||
<div class="row text-center m-b-50" v-if="step">
|
||||
<div class="col">
|
||||
<h4 class="all-caps">{{ type === 1 ? 'Receivable Mapping' : 'Payable Mapping'}}</h4>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center align-items-center">
|
||||
<div class="col b-a b-grey padding-30 pointer" :class="[{'bg-info': stage === 1}, {'text-white': stage === 1}]" @click="startMapping(1)">Mapping Approval</div>
|
||||
<div class="col-auto"><i class="fa fa-angle-double-right fs-20"></i></div>
|
||||
<div class="col b-a b-grey padding-30 pointer" :class="[{'bg-info': stage === 2}, {'text-white': stage === 2}]" @click="startMapping(2)">Mapping Review</div>
|
||||
<div class="col-auto"><i class="fa fa-angle-double-right fs-20"></i></div>
|
||||
<div class="col b-a b-grey padding-30 pointer" :class="[{'bg-info': stage === 3}, {'text-white': stage === 3}]" @click="startMapping(3)">Unknown</div>
|
||||
<div class="col-auto"><i class="fa fa-angle-double-right fs-20"></i></div>
|
||||
<div class="col b-a b-grey padding-30 pointer" :class="[{'bg-info': stage === 4}, {'text-white': stage === 4}]" @click="startMapping(4)">Pending Export</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center align-items-center m-t-50 m-b-50 hide" v-if="type">
|
||||
<div class="col-5">
|
||||
<div class="row text-center">
|
||||
<div class="col b-a b-grey padding-30 m-r-15 pointer" :class="[{'bg-complete': type === 1}, {'text-white': type === 1}]" @click="type=1">All</div>
|
||||
<div class="col b-a b-grey padding-30 m-r-15 pointer" :class="[{'bg-complete': type === 1}, {'text-white': type === 1}]" @click="type=1">Sales</div>
|
||||
<div class="col b-a b-grey padding-30 pointer" :class="[{'bg-complete': type === 2}, {'text-white': type === 2}]" @click="type=2">Wallet Top Up</div>
|
||||
<div class="col b-a b-grey padding-30 pointer" :class="[{'bg-complete': type === 2}, {'text-white': type === 2}]" @click="type=2">Internal Bank Transfer In</div>
|
||||
<div class="col b-a b-grey padding-30 pointer" :class="[{'bg-complete': type === 2}, {'text-white': type === 2}]" @click="type=2">Unknown</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row justify-content-center m-b-50" v-show="step === 0">
|
||||
<div class="col-4">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button type="button" class="btn btn-lg btn-block btn-primary b-rad-none" @click="startMapping(1)" v-if="type">Start Mapping</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row p-b-15 p-t-15 bg-master-lighter" v-show="step !== 0">
|
||||
<div class="col"></div>
|
||||
<div class="col-auto pointer bold text-danger" @click="step=0">X</div>
|
||||
</div>
|
||||
<div class="row" v-if="step > 0 && stage !== 4">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row m-t-10 m-b-10">
|
||||
<div class="col">
|
||||
<div class="row p-t-10 p-b-10 b-b b-grey text-master-light">
|
||||
<div class="col-2">Date</div>
|
||||
<div class="col-2">Description</div>
|
||||
<div class="col-5">
|
||||
<div class="row">
|
||||
<div class="col">System</div>
|
||||
<div class="col">Type</div>
|
||||
<div class="col">Reference</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1">Amount</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<list-component ref="bankTransactionsList" section="bankTransactionSection" :endpoint="route('api.accounting.bank.transaction')" :options="this.filter">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<statement-transaction-component :data="data"></statement-transaction-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="stage === 4">
|
||||
<div class="col">
|
||||
<div class="row text-center m-t-50 m-b-50 p-t-50 p-b-50" v-show="exportStage === 0">
|
||||
<div class="col">
|
||||
<div class="btn btn-lg btn-primary" @click="exportStage++">Export Invoices To AutoCount</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center m-t-50 m-b-50 p-t-50 p-b-50" v-show="exportStage === 1">
|
||||
<div class="col">
|
||||
<file-upload-component></file-upload-component>
|
||||
<div class="btn btn-lg btn-primary m-t-20" @click="exportStage++">Import Invoices</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center m-t-50 m-b-50 p-t-50 p-b-50" v-show="exportStage === 2">
|
||||
<div class="col">
|
||||
<div class="btn btn-lg btn-primary" @click="exportStage++">Export Receipts To AutoCount</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center m-t-50 m-b-50 p-t-50 p-b-50" v-show="exportStage === 3">
|
||||
<div class="col">
|
||||
<file-upload-component></file-upload-component>
|
||||
<div class="btn btn-lg btn-primary m-t-20" @click="exportStage++">Import Receipts</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center m-t-50 m-b-50 p-t-50 p-b-50" v-show="exportStage === 4">
|
||||
<div class="col">
|
||||
All Done, Good Job <span class="fs-50">👏</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
components: {},
|
||||
|
||||
|
||||
data(){
|
||||
return {
|
||||
type: null,
|
||||
stage: null,
|
||||
exportStage: 0,
|
||||
step: 0,
|
||||
filter: {}
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
startMapping(stage){
|
||||
|
||||
this.stage = stage;
|
||||
this.exportStage = 0;
|
||||
if(this.type === 1){
|
||||
switch(this.stage){
|
||||
case 1:
|
||||
this.filter = {min_amount: 0, is_mapped: true, is_mapped_with_multiple: false, statement_transaction_owner_type_in: [1, 2], per_page: 100, order_by: {column: 'posting_date', DESC: true}}
|
||||
break;
|
||||
case 2:
|
||||
this.filter = {min_amount: 0, is_mapped: true, is_mapped_with_multiple: true, statement_transaction_owner_type_in: [1, 2], per_page: 100, order_by: {column: 'posting_date', DESC: true}}
|
||||
break;
|
||||
case 3:
|
||||
this.filter = {min_amount: 0, is_mapped: false, statement_transaction_owner_type_in: [1, 2], 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}}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(this.type === 2){
|
||||
switch(this.stage){
|
||||
case 1:
|
||||
this.filter = {max_amount: 0, is_mapped: true, is_mapped_with_multiple: false, statement_transaction_owner_type_in: [3, 5], per_page: 100, order_by: {column: 'posting_date', DESC: true}}
|
||||
break;
|
||||
case 2:
|
||||
this.filter = {max_amount: 0, is_mapped: true, is_mapped_with_multiple: true, statement_transaction_owner_type_in: [3, 5], per_page: 100, order_by: {column: 'posting_date', DESC: true}}
|
||||
break;
|
||||
case 3:
|
||||
this.filter = {max_amount: 0, is_mapped: false, per_page: 100, order_by: {column: 'posting_date', DESC: true}}
|
||||
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}}
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
this.step = 1;
|
||||
|
||||
if(this.$refs.bankTransactionsList){
|
||||
this.$refs.bankTransactionsList.updateFilters(this.filter);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
</script>
|
||||
@@ -0,0 +1,12 @@
|
||||
@extends('layouts.base_portal')
|
||||
@section('inner_content')
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<list-component ref="paymentProofList" section="bankStatementSection" :endpoint="route('api.accounting.bank.transaction')" :options="{statement_transaction_account_id: {{$account}}, per_page: 100, order_by: {column: 'posting_date', DESC: true}}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<statement-transaction-component :data="data"></statement-transaction-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
File diff suppressed because one or more lines are too long
@@ -0,0 +1,461 @@
|
||||
@extends('layouts.base_portal')
|
||||
@section('inner_content')
|
||||
<upload-debtor-excel-component section="uploadDebtorExcelSection"></upload-debtor-excel-component>
|
||||
|
||||
<div class="container-fluid">
|
||||
<div class="row m-b-50">
|
||||
<div class="col-12">
|
||||
<h1 class="text-left">Accounting Dashboard</h1>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-md-4">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">Import Bank Statement</div>
|
||||
|
||||
<div class="card-body">
|
||||
@if (session('success'))
|
||||
<div class="alert alert-success">
|
||||
{{ session('success') }}
|
||||
</div>
|
||||
@endif
|
||||
@if (session('error'))
|
||||
<div class="alert alert-danger mt-3">
|
||||
{{ session('error') }}
|
||||
</div>
|
||||
@endif
|
||||
|
||||
<form method="POST" action="{{ route('statements.import') }}" enctype="multipart/form-data">
|
||||
@csrf
|
||||
<div class="form-group">
|
||||
<label for="file">Select CSV File</label>
|
||||
<input type="file" class="form-control-file" id="file" name="file" required>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Import</button>
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="card">
|
||||
<div class="card-header">Transaction Filtering</div>
|
||||
|
||||
<div class="card-body">
|
||||
<form>
|
||||
<div class="form-group">
|
||||
<label for="startDate">Start Date:</label>
|
||||
<input type="date" id="startDate" name="startDate" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="endDate">End Date:</label>
|
||||
<input type="date" id="endDate" name="endDate" class="form-control">
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="transactionType">Transaction Type:</label>
|
||||
<select id="transactionType" name="transactionType" class="form-control">
|
||||
<option value="">All</option>
|
||||
<option value="Deposit">Deposit</option>
|
||||
<option value="Withdrawal">Withdrawal</option>
|
||||
</select>
|
||||
</div>
|
||||
<div class="form-group">
|
||||
<label for="accountName">Account Name:</label>
|
||||
<select id="accountName" name="accountName" class="form-control">
|
||||
<option value="">All</option>
|
||||
<option value="Bank Account 1">Bank Account 1</option>
|
||||
<option value="Bank Account 2">Bank Account 2</option>
|
||||
<option value="Bank Account 3">Bank Account 3</option>
|
||||
</select>
|
||||
</div>
|
||||
<input type="submit" value="Filter" class="btn btn-primary">
|
||||
</form>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-md-8">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<ul class="nav nav-tabs no-border" id="myTab" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" id="tab1-tab" data-toggle="tab" href="#tab1" role="tab" aria-controls="tab1" aria-selected="true">Transactions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="tab2-tab" data-toggle="tab" href="#tab2" role="tab" aria-controls="tab2" aria-selected="false">Deposit Mapping</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="tab3-tab" data-toggle="tab" href="#tab3" role="tab" aria-controls="tab3" aria-selected="false">Withdrawal Mapping</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="tab4-tab" data-toggle="tab" href="#tab4" role="tab" aria-controls="tab4" aria-selected="false">Unknown Transactions</a>
|
||||
</li>
|
||||
<li class="nav-item ml-auto">
|
||||
<a class="nav-link" id="tab5-tab" data-toggle="tab" href="#tab5" role="tab" aria-controls="tab5" aria-selected="false">Statements</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="card no-border">
|
||||
<div class="card-body">
|
||||
<div class="tab-content" id="myTabContent">
|
||||
<div class="tab-pane fade show active" id="tab1" role="tabpanel" aria-labelledby="tab1-tab">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Transaction Type</th>
|
||||
<th>Account Name</th>
|
||||
<th>Description</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>2023-04-11</td>
|
||||
<td>Deposit</td>
|
||||
<td>Bank Account 1</td>
|
||||
<td>Salary Payment</td>
|
||||
<td>Pending</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2023-04-09</td>
|
||||
<td>Withdrawal</td>
|
||||
<td>Bank Account 2</td>
|
||||
<td>Vendor Payment</td>
|
||||
<td>Reconciled</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2023-04-07</td>
|
||||
<td>Deposit</td>
|
||||
<td>Bank Account 3</td>
|
||||
<td>Online Order Payment</td>
|
||||
<td>Exception</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="tab2" role="tabpanel" aria-labelledby="tab2-tab">
|
||||
<ul class="nav nav-pills nav-justified mb-3" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link active" data-toggle="pill" href="#step1">Step 1</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#step2">Step 2</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#step3">Step 3</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#step4">Step 4</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#step5">Step 5</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#step6">Step 6</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" data-toggle="pill" href="#step7">Step 7</a>
|
||||
</li>
|
||||
</ul>
|
||||
|
||||
<!-- Wizard Content -->
|
||||
<div class="tab-content">
|
||||
<div class="tab-pane fade show active" id="step1">
|
||||
<h4 class="card-title">Step 1: Start Mapping bank Transactions</h4>
|
||||
<p class="card-text">This is the first step in the wizard.</p>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="step2">
|
||||
<h4 class="card-title">Step 2: List of automatically mapped bank transactions</h4>
|
||||
<p class="card-text">This is the second step in the wizard.</p>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="step3">
|
||||
<h4 class="card-title">Step 3: List of bank transactions that require manual mapping</h4>
|
||||
<p class="card-text">This is the third step in the wizard.</p>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="step4">
|
||||
<h4 class="card-title">Step 4: Export invoices to accounting software</h4>
|
||||
<p class="card-text">This is the fourth step in the wizard.</p>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="step5">
|
||||
<h4 class="card-title">Step 5: Import invoices from accounting software</h4>
|
||||
<p class="card-text">This is the fifth step in the wizard.</p>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="step6">
|
||||
<h4 class="card-title">Step 6: Export payment receipts</h4>
|
||||
<p class="card-text">This is the sixth step in the wizard.</p>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="step7">
|
||||
<h4 class="card-title">Step 7: Import payment receipts</h4>
|
||||
<p class="card-text">This is the final step in the wizard.</p>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Wizard Navigation Buttons -->
|
||||
<ul class="list-inline">
|
||||
<li class="list-inline-item"><button type="button" class="btn btn-secondary prev-step">Previous</button></li>
|
||||
<li class="list-inline-item"><button type="button" class="btn btn-primary next-step">Next</button></li>
|
||||
<li class="list-inline-item"><button type="button" class="btn btn-success finish-step">Finish</button></li>
|
||||
</ul>
|
||||
|
||||
</div>
|
||||
<div class="tab-pane fade" id="tab3" role="tabpanel" aria-labelledby="tab3-tab">
|
||||
<h2>Tab 3 Content</h2>
|
||||
<p>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.</p>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="tab5" role="tabpanel" aria-labelledby="tab5-tab">
|
||||
<form method="GET" action="{{ route('statements.index') }}" class="form-inline mb-3">
|
||||
<div class="form-group mr-3">
|
||||
<label for="account">Account:</label>
|
||||
<select name="account" id="account" class="form-control ml-2">
|
||||
<option value="">All Accounts</option>
|
||||
@foreach($accounts as $account)
|
||||
<option value="{{ $account->id }}" {{ $account->id == $selectedAccount ? 'selected' : '' }}>{{ $account->name }} ({{ $account->number }})</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mr-2">Filter</button>
|
||||
<a href="{{ route('statements.index') }}" class="btn btn-secondary">Clear</a>
|
||||
</form>
|
||||
|
||||
<form method="GET" action="{{ route('statements.index') }}" class="form-inline mb-3">
|
||||
<div class="form-group mr-3">
|
||||
<label for="search">Search:</label>
|
||||
<input type="text" class="form-control ml-2" id="search" name="search" value="{{ $search }}">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Search</button>
|
||||
</form>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Account</th>
|
||||
<th>Date From</th>
|
||||
<th>Date To</th>
|
||||
<th>Total Amount</th>
|
||||
<th>Begin Balance</th>
|
||||
<th>End Balance</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($statements as $statement)
|
||||
<tr>
|
||||
<td>{{ $statement->account->name }} ({{ $statement->account->number }})</td>
|
||||
<td>{{ $statement->date_from->format('d-m-Y') }}</td>
|
||||
<td>{{ $statement->date_to->format('d-m-Y') }}</td>
|
||||
<td>{{ $statement->total_amount }}</td>
|
||||
<td>{{ $statement->begin_balance }}</td>
|
||||
<td>{{ $statement->end_balance }}</td>
|
||||
<td>
|
||||
<a href="{{ route('statements.show', $statement) }}" class="btn btn-primary btn-sm">View</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
{{ $statements->links() }}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<ul class="nav nav-tabs no-border" id="myTab" role="tablist">
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="tab3-tab" data-toggle="tab" href="#tab3" role="tab" aria-controls="tab3" aria-selected="false">Pending Transactions</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="tab3-tab" data-toggle="tab" href="#tab3" role="tab" aria-controls="tab3" aria-selected="false">Exception Handling</a>
|
||||
</li>
|
||||
<li class="nav-item">
|
||||
<a class="nav-link" id="tab3-tab" data-toggle="tab" href="#tab3" role="tab" aria-controls="tab3" aria-selected="false">Non-operational Transactions</a>
|
||||
</li>
|
||||
<li class="nav-item ml-auto">
|
||||
<a class="nav-link" id="tab3-tab" data-toggle="tab" href="#tab3" role="tab" aria-controls="tab3" aria-selected="false">Reconciled Transactions</a>
|
||||
</li>
|
||||
</ul>
|
||||
<div class="card no-border">
|
||||
<div class="card-body">
|
||||
<div class="tab-content" id="myTabContent">
|
||||
<div class="tab-pane fade show active" id="tab1" role="tabpanel" aria-labelledby="tab1-tab">
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Date</th>
|
||||
<th>Transaction Type</th>
|
||||
<th>Account Name</th>
|
||||
<th>Description</th>
|
||||
<th>Status</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
<tr>
|
||||
<td>2023-04-11</td>
|
||||
<td>Deposit</td>
|
||||
<td>Bank Account 1</td>
|
||||
<td>Salary Payment</td>
|
||||
<td>Pending</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2023-04-09</td>
|
||||
<td>Withdrawal</td>
|
||||
<td>Bank Account 2</td>
|
||||
<td>Vendor Payment</td>
|
||||
<td>Reconciled</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td>2023-04-07</td>
|
||||
<td>Deposit</td>
|
||||
<td>Bank Account 3</td>
|
||||
<td>Online Order Payment</td>
|
||||
<td>Exception</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<div class="tab-pane fade" id="tab2" role="tabpanel" aria-labelledby="tab2-tab">
|
||||
<form method="GET" action="{{ route('statements.index') }}" class="form-inline mb-3">
|
||||
<div class="form-group mr-3">
|
||||
<label for="account">Account:</label>
|
||||
<select name="account" id="account" class="form-control ml-2">
|
||||
<option value="">All Accounts</option>
|
||||
@foreach($accounts as $account)
|
||||
<option value="{{ $account->id }}" {{ $account->id == $selectedAccount ? 'selected' : '' }}>{{ $account->name }} ({{ $account->number }})</option>
|
||||
@endforeach
|
||||
</select>
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary mr-2">Filter</button>
|
||||
<a href="{{ route('statements.index') }}" class="btn btn-secondary">Clear</a>
|
||||
</form>
|
||||
|
||||
<form method="GET" action="{{ route('statements.index') }}" class="form-inline mb-3">
|
||||
<div class="form-group mr-3">
|
||||
<label for="search">Search:</label>
|
||||
<input type="text" class="form-control ml-2" id="search" name="search" value="{{ $search }}">
|
||||
</div>
|
||||
<button type="submit" class="btn btn-primary">Search</button>
|
||||
</form>
|
||||
|
||||
<table class="table">
|
||||
<thead>
|
||||
<tr>
|
||||
<th>Account</th>
|
||||
<th>Date From</th>
|
||||
<th>Date To</th>
|
||||
<th>Total Amount</th>
|
||||
<th>Begin Balance</th>
|
||||
<th>End Balance</th>
|
||||
<th>Actions</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@foreach($statements as $statement)
|
||||
<tr>
|
||||
<td>{{ $statement->account->name }} ({{ $statement->account->number }})</td>
|
||||
<td>{{ $statement->date_from->format('d-m-Y') }}</td>
|
||||
<td>{{ $statement->date_to->format('d-m-Y') }}</td>
|
||||
<td>{{ $statement->total_amount }}</td>
|
||||
<td>{{ $statement->begin_balance }}</td>
|
||||
<td>{{ $statement->end_balance }}</td>
|
||||
<td>
|
||||
<a href="{{ route('statements.show', $statement) }}" class="btn btn-primary btn-sm">View</a>
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
</table>
|
||||
{{ $statements->links() }}
|
||||
</div>
|
||||
<div class="tab-pane fade" id="tab3" role="tabpanel" aria-labelledby="tab3-tab">
|
||||
<h2>Tab 3 Content</h2>
|
||||
<p>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.</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
|
||||
// Initialize the wizard
|
||||
$('#rootwizard').bootstrapWizard({
|
||||
'tabClass': 'nav nav-pills',
|
||||
'nextSelector': '.next-step',
|
||||
'previousSelector': '.prev-step',
|
||||
'finishSelector': '.finish-step',
|
||||
'onTabClick': function (tab, navigation, index) {
|
||||
return false;
|
||||
},
|
||||
'onNext': function (tab, navigation, index) {
|
||||
return true;
|
||||
},
|
||||
'onPrevious': function (tab, navigation, index) {
|
||||
return true;
|
||||
},
|
||||
'onFinish': function (tab, navigation, index) {
|
||||
return true;
|
||||
}
|
||||
});
|
||||
|
||||
});
|
||||
</script>
|
||||
</body>
|
||||
</html>
|
||||
```
|
||||
Next, we add some custom CSS styles to the wizard to make it look more appealing.
|
||||
php
|
||||
Copy code
|
||||
<style>
|
||||
.card {
|
||||
margin-bottom: 30px;
|
||||
}
|
||||
.nav-pills .nav-link {
|
||||
border-radius: 0;
|
||||
}
|
||||
.nav-pills .nav-link.active {
|
||||
background-color: #007bff;
|
||||
color: #fff;
|
||||
}
|
||||
.btn {
|
||||
border-radius: 0;
|
||||
}
|
||||
.list-inline-item {
|
||||
margin-right: 10px;
|
||||
}
|
||||
</style>
|
||||
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
|
||||
<script>
|
||||
$(document).ready(function () {
|
||||
|
||||
// Initialize the wizard
|
||||
$('#rootwizard').bootstrapWizard({
|
||||
'tabClass': 'nav nav-pills',
|
||||
'nextSelector': '.next-step',
|
||||
'previousSelector': '.prev-step',
|
||||
'finishSelector': '.finish-step',
|
||||
'onTabClick': function (tab, navigation, index) {
|
||||
return false;
|
||||
},
|
||||
'onNext': function (tab, navigation, index) {
|
||||
return true;
|
||||
},
|
||||
'onPrevious': function (tab, navigation, index) {
|
||||
return true;
|
||||
},
|
||||
'onFinish': function (tab, navigation, index) {
|
||||
return true;
|
||||
}
|
||||
</script>
|
||||
@endsection
|
||||
@@ -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');
|
||||
|
||||
+5
-1
@@ -560,12 +560,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');
|
||||
|
||||
|
||||
Reference in New Issue
Block a user