mirror of
https://gitlab.com/CIEFWorldwideSdnBhd/exchange-2.0.git
synced 2026-08-19 04:23:55 +00:00
Merge branch 'master' of gitlab.com:CIEFWorldwideSdnBhd/exchange-2.0 into regenerate-invoice-with-first-bill-no
This commit is contained in:
@@ -16,6 +16,8 @@ class CreatedAfterOrEqual implements Filter
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->where('created_at', '>=', Carbon::parse($value));
|
||||
$table = $builder->getModel()->getTable();
|
||||
$startDate = Carbon::createFromFormat('d-m-Y', $value)->startOfDay();
|
||||
return $builder->where("{$table}.created_at", '>=', $startDate);
|
||||
}
|
||||
}
|
||||
@@ -15,6 +15,8 @@ class CreatedBeforeOrEqual implements Filter
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->where('created_at', '<=', Carbon::parse($value));
|
||||
$table = $builder->getModel()->getTable();
|
||||
$endDate = Carbon::createFromFormat('d-m-Y', $value)->endOfDay();
|
||||
return $builder->where("{$table}.created_at", '<=', $endDate);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -15,7 +15,7 @@ class HasAccountStatementId implements Filter
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->whereHas('statementTransaction', function ($query) use ($value) {
|
||||
return $builder->whereHas('transaction', function ($query) use ($value) {
|
||||
$query->where('account_statement_id', $value);
|
||||
});
|
||||
}
|
||||
|
||||
@@ -0,0 +1,23 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class IsMappedFalseOrMappedButStatusIn implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return Builder|mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->where(function($q) use ($value) {
|
||||
$q->whereDoesntHave('owners');
|
||||
$q->orwhereDoesntHave('owner_status');
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,8 @@ class OwnerId implements Filter
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->where('owner_id', $value);
|
||||
$table = $builder->getModel()->getTable();
|
||||
return $builder->where("{$table}.owner_id", $value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -14,7 +14,8 @@ class OwnerType implements Filter
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->where('owner_type', $value);
|
||||
$table = $builder->getModel()->getTable();
|
||||
return $builder->where("{$table}.owner_type", $value);
|
||||
}
|
||||
|
||||
}
|
||||
+24
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class StatementTransactionOwnerInvoiceOrReceiptRefNotNull implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->whereHas('owners', function ($query) {
|
||||
return $query->where(function ($q) {
|
||||
$q->orWhereNotNull('invoice_reference')->orWhereNotNull('receipt_reference');
|
||||
});
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class StatementTransactionPostingEnd implements Filter
|
||||
{
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->whereDate('posting_date', '<=', date('Y-m-d',strtotime($value)));
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,18 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
|
||||
class StatementTransactionPostingStart implements Filter
|
||||
{
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->whereDate('posting_date', '>=', date('Y-m-d',strtotime($value)));
|
||||
}
|
||||
}
|
||||
@@ -14,7 +14,8 @@ class StatusIn implements Filter
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->whereIn('status', $value);
|
||||
$table = $builder->getModel()->getTable();
|
||||
return $builder->whereIn("{$table}.status", $value);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,29 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\General\Eloquent\Filters;
|
||||
|
||||
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Models\Booking;
|
||||
use Illuminate\Database\Eloquent\Builder;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class WithBookingMarkingLike implements Filter
|
||||
{
|
||||
|
||||
/**
|
||||
* @param Builder $builder
|
||||
* @param $value
|
||||
* @return mixed
|
||||
*/
|
||||
public static function apply(Builder $builder, $value)
|
||||
{
|
||||
return $builder->join('transactions as t2', 't2.payment_reference', '=', 'transactions.bill_no')
|
||||
->join('bookings', function ($join) use ($value) {
|
||||
$join->on('bookings.id', '=', 't2.owner_id')
|
||||
->where('bookings.marking', 'LIKE', '%'.$value.'%');
|
||||
})
|
||||
->addSelect(['transactions.*','t2.owner_id as bookingId', 'bookings.marking as bookingMarking']);
|
||||
}
|
||||
}
|
||||
@@ -13,9 +13,15 @@ class CreateBankStatementTransactionOwners implements ShouldQueue
|
||||
{
|
||||
use Dispatchable, InteractsWithQueue, Queueable, SerializesModels;
|
||||
|
||||
private $transactions;
|
||||
|
||||
public function __construct($transactions) {
|
||||
$this->transactions = $transactions;
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
(App()->make(CreateBankStatementTransactionOwnersProcessor::class))->execute();
|
||||
(App()->make(CreateBankStatementTransactionOwnersProcessor::class))->execute($this->transactions);
|
||||
}
|
||||
|
||||
public function delay($delay)
|
||||
|
||||
+52
-60
@@ -135,7 +135,7 @@ class ApproveDuplicateBankStatementDetailsStatusLogic extends AbstractController
|
||||
public function logic(Request $request): JsonResponse
|
||||
{
|
||||
// Determine the approval status
|
||||
$status = $this->getApprovalStatus($request);
|
||||
$status = $this->getConstantStatus($request->route('status'));
|
||||
|
||||
// Find the statement transaction owner
|
||||
$owner = $this->getOwner($request);
|
||||
@@ -143,21 +143,33 @@ class ApproveDuplicateBankStatementDetailsStatusLogic extends AbstractController
|
||||
// Update owner status
|
||||
$this->updateOwnerStatus($owner, $status);
|
||||
|
||||
// If the status is 'approved', handle the approval process
|
||||
if ($status === ApprovalStatus::APPROVED) {
|
||||
$this->handleApprovedStatus($owner);
|
||||
}
|
||||
// handle the siblings process
|
||||
$this->handleSiblingsStatus($owner, $this->getSiblingsStatus($status));
|
||||
|
||||
// Check and approve remaining matches if any
|
||||
$this->checkAndApproveRemainingMatches($owner);
|
||||
$this->checkAndApproveRemainingMatches($owner, $status);
|
||||
|
||||
// Return an empty response
|
||||
return $this->response([]);
|
||||
}
|
||||
|
||||
private function getApprovalStatus(Request $request): int
|
||||
private function getConstantStatus(String $statusName=null): int
|
||||
{
|
||||
return $request->route('status') == 'approve' ? ApprovalStatus::APPROVED : ApprovalStatus::REJECTED;
|
||||
switch ($statusName) {
|
||||
case 'approve':
|
||||
return ApprovalStatus::APPROVED;
|
||||
|
||||
case 'pending_verification':
|
||||
return ApprovalStatus::PENDING_VERIFICATION;
|
||||
|
||||
default:
|
||||
return ApprovalStatus::REJECTED;
|
||||
}
|
||||
}
|
||||
|
||||
private function getSiblingsStatus(int $status): int
|
||||
{
|
||||
return $status == ApprovalStatus::APPROVED ? ApprovalStatus::REJECTED : ApprovalStatus::PENDING_VERIFICATION;
|
||||
}
|
||||
|
||||
private function getOwner(Request $request): StatementTransactionOwner
|
||||
@@ -170,23 +182,24 @@ class ApproveDuplicateBankStatementDetailsStatusLogic extends AbstractController
|
||||
$this->updatesBankStatementTransactionOwnerStatus->execute($owner, $status);
|
||||
}
|
||||
|
||||
private function handleApprovedStatus(StatementTransactionOwner $owner): void
|
||||
private function handleSiblingsStatus(StatementTransactionOwner $owner, int $siblingStatus): void
|
||||
{
|
||||
// Reject all other owners with the same system, owner type, and owner ID
|
||||
$this->rejectOtherOwners($owner);
|
||||
// update all other owners with the same system, owner type, and owner ID
|
||||
$this->updateOtherOwners($owner, $siblingStatus);
|
||||
|
||||
// Find all siblings and process them
|
||||
$siblings = $this->getSiblings($owner);
|
||||
$this->processSiblings($siblings);
|
||||
|
||||
foreach ($siblings as $sibling) {
|
||||
$this->processSibling($sibling, $siblingStatus);
|
||||
}
|
||||
}
|
||||
|
||||
private function rejectOtherOwners(StatementTransactionOwner $owner): void
|
||||
private function updateOtherOwners(StatementTransactionOwner $owner, int $status): void
|
||||
{
|
||||
StatementTransactionOwner::where('system', $owner->system)
|
||||
->where('owner_type', $owner->owner_type)
|
||||
->where('owner_id', $owner->owner_id)
|
||||
StatementTransactionOwner::getSiblingsOwner()
|
||||
->where('id', '!=', $owner->id)
|
||||
->update(['status' => ApprovalStatus::REJECTED]);
|
||||
->update(['status' => $status]);
|
||||
}
|
||||
|
||||
private function getSiblings(StatementTransactionOwner $owner): Collection
|
||||
@@ -196,86 +209,65 @@ class ApproveDuplicateBankStatementDetailsStatusLogic extends AbstractController
|
||||
->get();
|
||||
}
|
||||
|
||||
private function processSiblings(Collection $siblings): void
|
||||
{
|
||||
foreach ($siblings as $sibling) {
|
||||
$this->processSibling($sibling);
|
||||
}
|
||||
}
|
||||
|
||||
private function processSibling(StatementTransactionOwner $sibling): void
|
||||
private function processSibling(StatementTransactionOwner $sibling, int $siblingStatus): void
|
||||
{
|
||||
// Reject the sibling and save the changes
|
||||
$sibling->status = ApprovalStatus::REJECTED;
|
||||
$sibling->status = $siblingStatus;
|
||||
$sibling->save();
|
||||
|
||||
|
||||
// Find all twins and process them
|
||||
$twins = $this->getTwins($sibling);
|
||||
$this->processTwins($twins);
|
||||
}
|
||||
|
||||
private function getTwins(StatementTransactionOwner $sibling): Collection
|
||||
{
|
||||
return StatementTransactionOwner::where('system', $sibling->system)
|
||||
->where('owner_type', $sibling->owner_type)
|
||||
->where('owner_id', $sibling->owner_id)
|
||||
->where('id', '!=', $sibling->id)
|
||||
->get();
|
||||
}
|
||||
|
||||
private function processTwins(Collection $twins): void
|
||||
{
|
||||
foreach ($twins as $twin) {
|
||||
$this->processTwin($twin);
|
||||
}
|
||||
}
|
||||
|
||||
private function getTwins(StatementTransactionOwner $sibling): Collection
|
||||
{
|
||||
return StatementTransactionOwner::getSiblingsOwner()
|
||||
->where('id', '!=', $sibling->id)
|
||||
->get();
|
||||
}
|
||||
|
||||
private function processTwin(StatementTransactionOwner $twin): void
|
||||
{
|
||||
// Find all owners with the same statement transaction ID as the twin
|
||||
$owners = $this->getOwners($twin);
|
||||
$owners = $this->getSiblings($twin);
|
||||
|
||||
// If there is only one owner (the twin itself), approve it
|
||||
if ($owners->count() === 1) {
|
||||
$this->updateOwnerStatus($twin, ApprovalStatus::APPROVED);
|
||||
$this->updateOwnerStatus($twin, $this->getConstantStatus(request()->route('status')));
|
||||
}
|
||||
}
|
||||
|
||||
private function getOwners(StatementTransactionOwner $transactionOwner): Collection
|
||||
{
|
||||
return StatementTransactionOwner::where('statement_transaction_id', $transactionOwner->statement_transaction_id)
|
||||
->where('id', '!=', $transactionOwner->id)
|
||||
->get();
|
||||
}
|
||||
|
||||
private function checkAndApproveRemainingMatches(StatementTransactionOwner $owner): void
|
||||
private function checkAndApproveRemainingMatches(StatementTransactionOwner $owner, int $status): void
|
||||
{
|
||||
// Find all remaining matching owners for the related transaction
|
||||
$remainingMatches = $this->getRemainingMatches($owner);
|
||||
$checkStatus = ($status == ApprovalStatus::APPROVED ? ApprovalStatus::PENDING_VERIFICATION : ApprovalStatus::APPROVED);
|
||||
$remainingMatches = $this->getRemainingMatches($owner, $checkStatus);
|
||||
|
||||
// Process each remaining match
|
||||
foreach ($remainingMatches as $match) {
|
||||
$this->processRemainingMatch($match);
|
||||
$this->processRemainingMatch($match, $status);
|
||||
}
|
||||
}
|
||||
|
||||
private function getRemainingMatches(StatementTransactionOwner $owner): Collection
|
||||
private function getRemainingMatches(StatementTransactionOwner $owner, int $checkStatus): Collection
|
||||
{
|
||||
return StatementTransactionOwner::where('system', $owner->system)
|
||||
->where('owner_type', $owner->owner_type)
|
||||
->where('owner_id', $owner->owner_id)
|
||||
->where('status', ApprovalStatus::PENDING_VERIFICATION)
|
||||
return StatementTransactionOwner::getSiblingsOwner()
|
||||
->where('status', $checkStatus)
|
||||
->get();
|
||||
}
|
||||
|
||||
private function processRemainingMatch(StatementTransactionOwner $match): void
|
||||
private function processRemainingMatch(StatementTransactionOwner $match, int $status): void
|
||||
{
|
||||
// Find all owners with the same statement transaction ID as the match
|
||||
$owners = $this->getOwners($match);
|
||||
$owners = $this->getSiblings($match);
|
||||
|
||||
// If there is only one owner (the match itself), approve it
|
||||
if ($owners->count() === 1) {
|
||||
$this->updateOwnerStatus($match, ApprovalStatus::APPROVED);
|
||||
$this->updateOwnerStatus($match, $status);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+2
-7
@@ -57,13 +57,8 @@ class GroupApproveStatementTransactionLogic extends AbstractControllerLogic
|
||||
public function logic(Request $request): JsonResponse
|
||||
{
|
||||
|
||||
$filters = [
|
||||
"min_amount" => 0,
|
||||
"is_mapped" => true,
|
||||
"is_mapped_with_multiple" => false,
|
||||
"statement_transaction_owner_type_in" => [1, 2],
|
||||
"statement_transaction_owner_status_in" => [1]
|
||||
];
|
||||
$filters = $request->except(['per_page','order_by']);
|
||||
|
||||
$statementTransactions = $this->listsBankStatementTransactions->execute($filters);
|
||||
|
||||
foreach ($statementTransactions as $statementTransaction) {
|
||||
|
||||
@@ -19,6 +19,9 @@ use App\Models\Wallet;
|
||||
use Exception;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Classes\Modules\Accounting\Services\UpdatesBankStatementTransactionOwnerStatus;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Models\StatementTransactionOwner;
|
||||
|
||||
class UpdateBankStatementDetailLogic extends AbstractControllerLogic
|
||||
{
|
||||
@@ -40,14 +43,21 @@ class UpdateBankStatementDetailLogic extends AbstractControllerLogic
|
||||
/** @var ChecksBillNumber */
|
||||
private $checksBillNumber;
|
||||
|
||||
/** @var UpdatesBankStatementTransactionOwnerStatus */
|
||||
private $updatesBankStatementTransactionOwnerStatus;
|
||||
|
||||
/**
|
||||
* @param FetchesBankStatementTransaction $fetchesBankStatementTransaction
|
||||
* @param ChecksBillNumber $checksBillNumber
|
||||
*/
|
||||
public function __construct(FetchesBankStatementTransaction $fetchesBankStatementTransaction, ChecksBillNumber $checksBillNumber)
|
||||
public function __construct(
|
||||
FetchesBankStatementTransaction $fetchesBankStatementTransaction,
|
||||
ChecksBillNumber $checksBillNumber,
|
||||
UpdatesBankStatementTransactionOwnerStatus $updatesBankStatementTransactionOwnerStatus)
|
||||
{
|
||||
$this->fetchesBankStatementTransaction = $fetchesBankStatementTransaction;
|
||||
$this->checksBillNumber = $checksBillNumber;
|
||||
$this->updatesBankStatementTransactionOwnerStatus = $updatesBankStatementTransactionOwnerStatus;
|
||||
}
|
||||
|
||||
public function logic(Request $request): JsonResponse
|
||||
@@ -129,7 +139,10 @@ class UpdateBankStatementDetailLogic extends AbstractControllerLogic
|
||||
|
||||
$system = $systemReference != null ? SystemType::SYSTEM_NAMES[$systemReference] : '';
|
||||
|
||||
$this->createBankStatementTransactionOwner($bankStatementTransaction, $statementTransactionOwnerType, $system, $owner_type, $owner_id, $owner_reference);
|
||||
$statementTransactionOwner = $this->createBankStatementTransactionOwner($bankStatementTransaction, $statementTransactionOwnerType, $system, $owner_type, $owner_id, $owner_reference);
|
||||
|
||||
// this for edit a transaction already mapped
|
||||
if ($request->has('editMapped')) $this->editAccountMapped($statementTransactionOwner);
|
||||
|
||||
return $this->response([]);
|
||||
}
|
||||
@@ -144,9 +157,26 @@ class UpdateBankStatementDetailLogic extends AbstractControllerLogic
|
||||
'owner_reference' => $owner_reference,
|
||||
];
|
||||
|
||||
$bankStatementTransaction->owners()->firstOrCreate($ownerData);
|
||||
|
||||
return $bankStatementTransaction->owners()->firstOrCreate($ownerData);
|
||||
}
|
||||
|
||||
private function editAccountMapped(StatementTransactionOwner $owner){
|
||||
$this->updateOwnerStatus($owner, ApprovalStatus::APPROVED);
|
||||
|
||||
// update all other owners with the same system, owner type, and owner ID
|
||||
$this->updateOtherOwners($owner, ApprovalStatus::REJECTED);
|
||||
}
|
||||
|
||||
private function updateOwnerStatus(StatementTransactionOwner $owner, int $status)
|
||||
{
|
||||
$this->updatesBankStatementTransactionOwnerStatus->execute($owner, $status);
|
||||
}
|
||||
|
||||
private function updateOtherOwners(StatementTransactionOwner $owner, int $status): void
|
||||
{
|
||||
StatementTransactionOwner::where('statement_transaction_id', $owner->statement_transaction_id)
|
||||
->where('id', '!=', $owner->id)
|
||||
->update(['status' => $status]);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
+40
-34
@@ -23,15 +23,12 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
/**
|
||||
* @return void
|
||||
*/
|
||||
public function execute() {
|
||||
|
||||
$transactions = StatementTransaction::whereDoesntHave('owners', function($query){
|
||||
return $query->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
|
||||
})->orderBy('posting_date')->get();
|
||||
public function execute($transactions) {
|
||||
|
||||
// $transactions = StatementTransaction::whereDoesntHave('owners')->where('amount', '<', 0)->get();
|
||||
|
||||
foreach ($transactions as $transaction) {
|
||||
$mapped = false;
|
||||
$keywords = array_filter(explode(" ", $transaction->transaction_description . " " . $transaction->transaction_description_2));
|
||||
|
||||
if($transaction->amount > 0){
|
||||
@@ -39,21 +36,21 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
// Exchange Sales
|
||||
$creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::PAYMENT, Booking::class, PaymentMethodType::WALLET, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords);
|
||||
foreach ($creditTransactions as $creditTransaction) {
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$isArray = is_array($creditTransaction);
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::SALES,
|
||||
'system' => 'EXCHANGE',
|
||||
'owner_type' => Transaction::class,
|
||||
'owner_id'=> $creditTransaction->id,
|
||||
'owner_reference'=> $creditTransaction->owner->marking,
|
||||
'owner_id'=> $isArray ? $creditTransaction['owner_id'] : $creditTransaction->id,
|
||||
'owner_reference'=> $isArray ? $creditTransaction['owner_reference'] : $creditTransaction->owner->marking,
|
||||
]);
|
||||
}
|
||||
|
||||
|
||||
// Shipping Portal Sales
|
||||
$creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), 2, PaymentMethodType::WALLET);
|
||||
$creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), [2], PaymentMethodType::WALLET);
|
||||
foreach ($creditTransactions as $creditTransaction) {
|
||||
if($creditTransaction['owner_type'] === Wallet::class) continue;
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::SALES,
|
||||
'system' => 'SHIPPING_PORTAL',
|
||||
'owner_type' => $creditTransaction['owner_type'],
|
||||
@@ -65,18 +62,19 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
// Exchange Wallet Top Up
|
||||
$creditTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::TOP_UP, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords);
|
||||
foreach ($creditTransactions as $creditTransaction) {
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$isArray = is_array($creditTransaction);
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::WALLET_TOP_UP,
|
||||
'system' => 'EXCHANGE',
|
||||
'owner_type' => Transaction::class,
|
||||
'owner_id'=> $creditTransaction->id,
|
||||
'owner_reference'=> $creditTransaction->owner->owner->reference,
|
||||
'owner_id'=> $isArray ? $creditTransaction['owner_id'] : $creditTransaction->id,
|
||||
'owner_reference'=> $isArray ? $creditTransaction['owner_reference'] : $creditTransaction->owner->owner->reference,
|
||||
]);
|
||||
}
|
||||
|
||||
$creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), 5, null);
|
||||
$creditTransactions = $this->getTransactionsFromShippingPortal($transaction->amount, $this->getDateRange($transaction->posting_date, 1), [5,15], null);
|
||||
foreach ($creditTransactions as $creditTransaction) {
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::WALLET_TOP_UP,
|
||||
'system' => 'SHIPPING_PORTAL',
|
||||
'owner_type' => $creditTransaction['owner_type'],
|
||||
@@ -87,7 +85,7 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
|
||||
// fpx charge refund
|
||||
if($transaction->transaction_description === 'DUITNOW S/CHRG REFUND'){
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::FPX_CHARGE_REFUND
|
||||
]);
|
||||
}
|
||||
@@ -96,7 +94,7 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
|
||||
// INTERNAL_BANK_TRANSFER_IN
|
||||
if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE')){
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_IN
|
||||
]);
|
||||
}
|
||||
@@ -121,7 +119,7 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
->where('amount', '<=', (($transaction->amount * -1) + 0.01))->whereDate('created_at', '>=', $paymentDateStart)->whereDate('created_at', '<=', $paymentDateEnd)->get();
|
||||
|
||||
foreach ($debitTransactions as $debitTransaction) {
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::SUPPLIER_PAYMENT,
|
||||
'system' => 'EXCHANGE',
|
||||
'owner_type' => Group::class,
|
||||
@@ -136,12 +134,13 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
// Exchange Wallet Withdrawal
|
||||
$debitTransactions = $this->getTransactions($transaction->posting_date, $transaction->amount, TransactionType::DEBIT_NOTE, Wallet::class, null, [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED], $keywords);
|
||||
foreach ($debitTransactions as $debitTransaction) {
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$isArray = is_array($creditTransaction);
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::WALLET_WITHDRAWAL,
|
||||
'system' => 'EXCHANGE',
|
||||
'owner_type' => Transaction::class,
|
||||
'owner_id'=> $debitTransaction->id,
|
||||
'owner_reference'=> $debitTransaction->owner->owner->marking,
|
||||
'owner_id'=> $isArray ? $debitTransaction['owner_id'] : $debitTransaction->id,
|
||||
'owner_reference'=> $isArray ? $debitTransaction['owner_reference'] : $debitTransaction->owner->owner->marking,
|
||||
]);
|
||||
}
|
||||
|
||||
@@ -149,50 +148,52 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
|
||||
// STATUTORY
|
||||
if(str_contains($transaction->transaction_description_2, 'PEMBANGUNAN SUMBER') || str_contains($transaction->transaction_description_2, 'HASIL') || str_contains($transaction->transaction_description_2, 'PERTUBUHAN KESELAMAT') || str_contains($transaction->transaction_description_2, 'KUMPULAN WANG SIMPAN')){
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::STATUTORY
|
||||
]);
|
||||
}
|
||||
|
||||
// FPX_CHARGE
|
||||
if($transaction->transaction_description === 'DR DUITNOW S/CHRG' || str_contains($transaction->transaction_description, 'Manual FPX') || str_contains($transaction->transaction_description, 'CMS - DR FPX CHG')){
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::FPX_CHARGE
|
||||
]);
|
||||
}
|
||||
|
||||
// BANK_CHARGE
|
||||
if($transaction->transaction_description === 'CMS - DR CORP CHG' || $transaction->transaction_description === 'MONTHLY PROFIT DEBIT'){
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::BANK_CHARGE
|
||||
]);
|
||||
}
|
||||
|
||||
// CREDIT_CARD_PAYMENT
|
||||
if(str_contains($transaction->transaction_description_2, 'VISA CARD')){
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::CREDIT_CARD_PAYMENT
|
||||
]);
|
||||
}
|
||||
|
||||
// INTERNAL_BANK_TRANSFER_OUT
|
||||
if(str_contains($transaction->transaction_description_2, 'CIEF WORLDWIDE') || str_contains($transaction->transaction_description_2, 'CIEF WORLWIDE') || str_contains($transaction->transaction_description_2, 'IZYIM GLOBAL')){
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::INTERNAL_BANK_TRANSFER_OUT
|
||||
]);
|
||||
}
|
||||
|
||||
// non-operational charges
|
||||
if(str_contains($transaction->transaction_description_2, 'HIRE PURCHASE') || str_contains($transaction->transaction_description_2, 'TENAGA NASIONAL') || str_contains($transaction->transaction_description, 'CABLE CHARGE') || str_contains($transaction->transaction_description_2, 'CTOS DATA SYSTEMS') || str_contains($transaction->transaction_description_2, 'MAXIS')){
|
||||
$transaction->owners()->firstOrCreate([
|
||||
$data = $transaction->owners()->firstOrCreate([
|
||||
'type' => StatementTransactionOwnerType::NON_OPERATIONAL
|
||||
]);
|
||||
}
|
||||
}
|
||||
if (isset($data) && $data->wasRecentlyCreated) $mapped = true;
|
||||
$this->updateMappedRate($transaction, $mapped);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $keywords, $model = Transaction::class) {
|
||||
private function getTransactions($date, $amount, $type, $ownerType, $paymentMethod, $statuses, $keywords, $model = Transaction::class) {
|
||||
$dateRange = $this->getDateRange($date, 4);
|
||||
if (App::environment(['production'])) {
|
||||
$query = $model::whereIn('status', $statuses)
|
||||
@@ -271,10 +272,8 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
return $query->get();
|
||||
} else {
|
||||
$result = $this->getTransactionsFromExchange($amount, $dateRange, $type, $ownerType, $paymentMethod);
|
||||
$transactionsId = Arr::pluck($result, 'owner_id');
|
||||
$query = $model::whereIn('id', $transactionsId);
|
||||
|
||||
return $query->get();
|
||||
return $result;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -321,7 +320,7 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
try{
|
||||
|
||||
$client = new \GuzzleHttp\Client(['verify' => false]);
|
||||
$response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2]'.$paymentMethodFilter.',"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in":['.$type.']}');
|
||||
$response = $client->request('GET', $url.'?api-key=510acd13d8d24375cf038ad626c282565451461a9c2399357e0b65365300787e&filters={"order_by":{"column":"id","DESC":true},"status_in":[2]'.$paymentMethodFilter.',"created_after":"'.$dateRange['start_date'].'","created_before":"'.$dateRange['end_date'].'","amount_exceed":'.($amount - 0.01).',"amount_short":'.($amount + 0.01).',"type_in":'.json_encode($type).'}');
|
||||
$body = $response->getBody();
|
||||
$data = json_decode($body, true);
|
||||
$payload = $data['payload'];
|
||||
@@ -348,4 +347,11 @@ class CreateBankStatementTransactionOwnersProcessor
|
||||
'end_date' => $nextDay,
|
||||
];
|
||||
}
|
||||
|
||||
private function updateMappedRate($transaction, $mapped) {
|
||||
$statement = $transaction->statement;
|
||||
$statement->total_rows = StatementTransaction::where('account_statement_id',$transaction->account_statement_id)->count();
|
||||
$statement->mapped_rows = $mapped ? $statement->mapped_rows+1 : $statement->mapped_rows;
|
||||
$statement->save();
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,57 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Bookings\ControllersLogic;
|
||||
|
||||
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Modules\Bookings\Services\FetchesBooking;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ExpireBookingPaymentControllerLogic extends AbstractControllerLogic
|
||||
{
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function notification():array {
|
||||
return [
|
||||
'title' => 'Expire Payment',
|
||||
'message' => 'You have successfully expire the Payment'
|
||||
];
|
||||
}
|
||||
|
||||
/** @var FetchesBooking */
|
||||
private $fetchesBooking;
|
||||
|
||||
/**
|
||||
* DeletePurchaseOrderPdfLogic constructor.
|
||||
* @param FetchesBooking $fetchesBooking
|
||||
*/
|
||||
public function __construct(fetchesBooking $fetchesBooking)
|
||||
{
|
||||
$this->fetchesBooking = $fetchesBooking;
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return JsonResponse
|
||||
* @throws \App\Classes\Exceptions\MalformedRequestException
|
||||
*/
|
||||
public function logic(Request $request) : JsonResponse
|
||||
{
|
||||
$booking = $this->fetchesBooking->execute(['id' => $request->route('id')]);
|
||||
|
||||
$payment = $booking->transactions()
|
||||
->payments()->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
|
||||
->first();
|
||||
|
||||
$payment->status = ApprovalStatus::EXPIRED;
|
||||
$payment->save();
|
||||
|
||||
return $this->response([]);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -24,7 +24,7 @@ class GeneratesBookingMarking
|
||||
*/
|
||||
public function execute(): int {
|
||||
|
||||
$marking = mt_rand(20000, 99999);
|
||||
$marking = mt_rand(100000, 999999);
|
||||
return !$this->bookingMarkingExists->execute($marking) ? $marking : self::execute();
|
||||
}
|
||||
|
||||
|
||||
@@ -0,0 +1,94 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Companies\ControllersLogic;
|
||||
|
||||
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use ZipArchive;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Classes\Exceptions\MalformedRequestException;
|
||||
use Illuminate\Support\Facades\File;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\DocumentType;
|
||||
use App\Models\Company;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BulkDownloadCustomerInvoicesLogic
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return \Illuminate\Http\JsonResponse|\Symfony\Component\HttpFoundation\BinaryFileResponse
|
||||
*/
|
||||
public function execute(Request $request)
|
||||
{
|
||||
try {
|
||||
$company = Company::where('reference', $request->input('marking'))->first();
|
||||
|
||||
if (!$company) {
|
||||
return response()->json([
|
||||
'status' => 'Failed',
|
||||
'message' => 'Customer not found.',
|
||||
]);
|
||||
}
|
||||
|
||||
$startDate = Carbon::createFromFormat('d-m-Y', $request->input('startDate'))->startOfDay();
|
||||
$endDate = Carbon::createFromFormat('d-m-Y', $request->input('endDate'))->endOfDay();
|
||||
|
||||
$invoicebookings = $company->bookings()
|
||||
->whereDate('created_at', '>=', $startDate)
|
||||
->whereDate('created_at', '<=', $endDate)
|
||||
->whereHas('transactions', function ($query) {
|
||||
$query->where('transactions.type', TransactionType::INVOICE)
|
||||
->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
|
||||
})
|
||||
->orderBy('created_at')
|
||||
->get();
|
||||
|
||||
if ($invoicebookings->isEmpty()) {
|
||||
return response()->json([
|
||||
'status' => 'Failed',
|
||||
'message' => 'No invoices found for this customer in the given date range.',
|
||||
]);
|
||||
}
|
||||
|
||||
$zipDirectory = storage_path('app/bulk_invoice'); // Update this with the actual directory path
|
||||
|
||||
if (!file_exists($zipDirectory)) {
|
||||
mkdir($zipDirectory, 0755, true);
|
||||
}
|
||||
|
||||
$zip_file = "{$zipDirectory}/invoices_{$request->input('startDate')}_to_{$request->input('endDate')}_{$company->reference}.zip";
|
||||
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($zip_file, ZipArchive::CREATE | ZipArchive::OVERWRITE)) {
|
||||
foreach ($invoicebookings as $booking) {
|
||||
$invoice_file = $booking->documents()->where('document_type', DocumentType::INVOICE)->whereNull('deleted_at')->first()->files()->first();
|
||||
$zip->addFile(Storage::disk('documents')->path($invoice_file->file->file_info->original->file), 'invoice-' . $booking->created_at->format('d_m_Y') . '_' . $booking->marking . '.pdf');
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
|
||||
while (ob_get_level()) {
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
return response()->download($zip_file);
|
||||
} else {
|
||||
return response()->json([
|
||||
'status' => 'Error',
|
||||
'message' => 'Failed to create the Zip archive.',
|
||||
]);
|
||||
}
|
||||
} catch (\Exception $e) {
|
||||
// Log the exception for debugging
|
||||
Log::error('Error in BulkDownloadCustomerInvoicesLogic: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'status' => 'Error',
|
||||
'message' => 'An error occurred while processing the request.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
+78
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Companies\ControllersLogic;
|
||||
|
||||
use ZipArchive;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Storage;
|
||||
use App\Classes\Exceptions\MalformedRequestException;
|
||||
use App\Classes\ValueObjects\Constants\DocumentType;
|
||||
use App\Models\Company;
|
||||
use App\Models\Group;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
|
||||
class BulkDownloadSupplierWhiteFormsLogic
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return void
|
||||
* @throws MalformedRequestException
|
||||
*/
|
||||
public function execute(Request $request)
|
||||
{
|
||||
try {
|
||||
|
||||
$startDate = Carbon::createFromFormat('d-m-Y', $request->input('startDate'))->startOfDay();
|
||||
$endDate = Carbon::createFromFormat('d-m-Y', $request->input('endDate'))->endOfDay();
|
||||
|
||||
$companyReference = Company::find($request->input('supplier'))->reference;
|
||||
$groups = Group::where('issuer', $request->input('supplier'))
|
||||
->whereDate('created_at', '>=', $startDate)
|
||||
->whereDate('created_at', '<=', $endDate)
|
||||
->orderBy('created_at', 'DESC')
|
||||
->get();
|
||||
|
||||
if (count($groups) > 0) {
|
||||
|
||||
$zipDirectory = storage_path('app/bulk_whiteform'); // Update this with the actual directory path
|
||||
|
||||
if (!file_exists($zipDirectory)) {
|
||||
mkdir($zipDirectory, 0755, true);
|
||||
}
|
||||
|
||||
$zip_file = "{$zipDirectory}/currency_vendor_orders_{$request->input('startDate')}_to_{$request->input('endDate')}_{$companyReference}.zip";
|
||||
|
||||
$zip = new ZipArchive();
|
||||
if ($zip->open($zip_file, ZIPARCHIVE::CREATE | ZipArchive::OVERWRITE)) {
|
||||
foreach($groups as $group) {
|
||||
$document = $group->documents()->where('document_type', DocumentType::CURRENCY_VENDOR_ORDER)->whereNull('deleted_at')->first()->files()->first();
|
||||
$created_at = $group->created_at->format('Y-m-d');
|
||||
$zip->addFile(Storage::disk('documents')->path($document->file->file_info->original->file), $created_at . "_" . $group->amount . "_" . $group->reference . '.pdf');
|
||||
}
|
||||
|
||||
$zip->close();
|
||||
while (ob_get_level()) {
|
||||
ob_end_clean();
|
||||
}
|
||||
|
||||
return response()->download($zip_file);
|
||||
}
|
||||
}
|
||||
|
||||
return response()->json([
|
||||
'status' => 'Failed',
|
||||
'message' => 'No white form found for this supplier in the given date range.',
|
||||
]);
|
||||
|
||||
} catch (\Exception $e) {
|
||||
// Log the exception for debugging
|
||||
Log::error('Error in BulkDownloadSupplierWhiteFormsLogic: ' . $e->getMessage());
|
||||
|
||||
return response()->json([
|
||||
'status' => 'Error',
|
||||
'message' => 'An error occurred while processing the request.',
|
||||
]);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,107 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Exports\Services;
|
||||
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\Company;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Request;
|
||||
use Maatwebsite\Excel\Concerns\Exportable;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
|
||||
class ExportsCustomersWalletTransactionHistory implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
|
||||
{
|
||||
use Exportable;
|
||||
|
||||
private $request;
|
||||
private $runningBalance = 0;
|
||||
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'Date',
|
||||
'Description',
|
||||
'Incoming',
|
||||
'Outgoing',
|
||||
'Balance',
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection|mixed
|
||||
*/
|
||||
public function query()
|
||||
{
|
||||
$company = Company::where('reference', $this->request->route('marking'))->first();
|
||||
$transactions = $company->wallets()->first()->transactions()->whereIn('transactions.status', [2, 3])->orderBy('id');
|
||||
// dd($transactions->get()->toArray());
|
||||
|
||||
return $transactions;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Transaction $transaction
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function map($transaction): array
|
||||
{
|
||||
// dd($transaction);
|
||||
|
||||
$decimals = $this->request->route('is_precise') == 'true' ? 5 : 2;
|
||||
|
||||
$description = '';
|
||||
switch ((int) $transaction->type) {
|
||||
case 5:
|
||||
$description = (float) $transaction->amount . ' Credit Top up';
|
||||
break;
|
||||
case 9:
|
||||
$description = 'Credit Voucher for ' . $transaction->payment_reference;
|
||||
break;
|
||||
case 1:
|
||||
$booking = Transaction::where('payment_reference', $transaction->bill_no)->first()->owner;
|
||||
|
||||
if (!$booking) {
|
||||
$description = 'Payment for unknown booking, please contact tech support.';
|
||||
break;
|
||||
}
|
||||
|
||||
$marking = $booking->marking;
|
||||
$description = 'Payment For booking refs' . $marking;
|
||||
break;
|
||||
case 11:
|
||||
$description = 'Debit Voucher for ' . $transaction->payment_reference;
|
||||
break;
|
||||
}
|
||||
|
||||
$incoming = $outgoing = '';
|
||||
|
||||
if (in_array($transaction->type, [TransactionType::TOP_UP, TransactionType::CREDIT_NOTE])) {
|
||||
$incoming = number_format($transaction->amount, $decimals, '.', ',');
|
||||
$this->runningBalance += $transaction->amount;
|
||||
}
|
||||
|
||||
if (in_array($transaction->type, [TransactionType::PAYMENT, TransactionType::DEBIT_NOTE])) {
|
||||
$outgoing = number_format($transaction->amount, $decimals, '.', ',');
|
||||
$this->runningBalance -= $transaction->amount;
|
||||
}
|
||||
|
||||
return [
|
||||
Carbon::parse($transaction->created_at)->format('d-m-Y h:i:s A'),
|
||||
$description,
|
||||
$incoming,
|
||||
$outgoing,
|
||||
number_format($this->runningBalance, $decimals, '.', ',')
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Exports\Services;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Arr;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\TransactionMappingLog;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
use Maatwebsite\Excel\Concerns\Exportable;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
||||
|
||||
class ExportsImportedInvoiceMappeds implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
|
||||
{
|
||||
use Exportable;
|
||||
|
||||
private $dateTime;
|
||||
private $count;
|
||||
private $counter = 1;
|
||||
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->dateTime = $request->input('date').' '.$request->input('time');
|
||||
$this->count = 0;
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
'No',
|
||||
'Doc No',
|
||||
'Date',
|
||||
'Debtor Code',
|
||||
'Debtor Name',
|
||||
'Shipping Info',
|
||||
'Net Total',
|
||||
'Cancelled',
|
||||
'Mapped Status',
|
||||
'Mapped Reference No'
|
||||
];
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection|mixed
|
||||
*/
|
||||
public function query()
|
||||
{
|
||||
return TransactionMappingLog::where('imported_date', $this->dateTime);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Transaction $transaction
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function map($transaction): array
|
||||
{
|
||||
// dd($transaction);
|
||||
$this->count += 1;
|
||||
$data = $transaction->data;
|
||||
return [
|
||||
$this->count,
|
||||
Arr::get($data,'doc_no'),
|
||||
Arr::get($data,'date'),
|
||||
Arr::get($data,'debtor_code'),
|
||||
Arr::get($data,'debtor_name'),
|
||||
Arr::get($data,'shipping_info'),
|
||||
Arr::get($data,'net_total'),
|
||||
Arr::get($data,'cancelled'),
|
||||
Arr::get($data,'mapped_status'),
|
||||
Arr::get($data,'mapped_result_reference'),
|
||||
];
|
||||
|
||||
}
|
||||
}
|
||||
@@ -4,7 +4,6 @@ namespace App\Classes\Modules\Exports\Services;
|
||||
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\StatementTransactionOwnerType;
|
||||
use App\Models\StatementTransactionOwner;
|
||||
use App\Models\Transaction;
|
||||
use Maatwebsite\Excel\Concerns\Exportable;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
@@ -18,6 +17,8 @@ use App\Classes\Modules\Accounting\Processors\ListShippingPortalTransactions;
|
||||
use App\Classes\ValueObjects\Constants\ShippingTransactionType;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Classes\General\Eloquent\ApplyFiltersToQuery;
|
||||
use App\Models\StatementTransaction;
|
||||
|
||||
class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
|
||||
{
|
||||
@@ -33,7 +34,7 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
return [
|
||||
$header = [
|
||||
'DocNo',
|
||||
'DocDate',
|
||||
'DebtorCode',
|
||||
@@ -49,6 +50,7 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading
|
||||
'AccNo',
|
||||
'DeptNo'
|
||||
];
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -56,9 +58,10 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading
|
||||
*/
|
||||
public function query()
|
||||
{
|
||||
return StatementTransactionOwner::whereNull('invoice_reference')
|
||||
->whereIn('type', [StatementTransactionOwnerType::SALES, StatementTransactionOwnerType::WALLET_TOP_UP])
|
||||
->whereIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::APPROVED]);
|
||||
$data = (new ApplyFiltersToQuery())->execute(StatementTransaction::query(), json_decode($this->request->input('filter'), true));
|
||||
if ($this->request->has('bankStatementTransactionId')) $data = $data->whereIn('id',json_decode($this->request->input('bankStatementTransactionId'), true));
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -68,11 +71,12 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading
|
||||
*/
|
||||
public function map($transaction): array
|
||||
{
|
||||
$statementTransactionOwner = $transaction->owners()->whereIn('status', [ApprovalStatus::APPROVED])->first();
|
||||
$logArray = [
|
||||
'counter' => $this->counter,
|
||||
'system' => $transaction->system,
|
||||
'StatementTransactionOwner_id' => $transaction->id,
|
||||
'transaction_table_id' => $transaction->owner_id,
|
||||
'system' => $statementTransactionOwner->system,
|
||||
'StatementTransactionOwner_id' => $statementTransactionOwner->id,
|
||||
'transaction_table_id' => $statementTransactionOwner->owner_id,
|
||||
];
|
||||
$this->counter += 1;
|
||||
$logArray = json_encode($logArray);
|
||||
@@ -82,8 +86,8 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading
|
||||
$textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' ' . $logArray . PHP_EOL;
|
||||
file_put_contents($filePath, $textToAppend, FILE_APPEND);
|
||||
|
||||
if ($transaction->system == 'EXCHANGE') {
|
||||
$row = (App()->make($transaction->owner_type))->where('id', $transaction->owner_id)->first();
|
||||
if ($statementTransactionOwner->system == 'EXCHANGE') {
|
||||
$row = (App()->make($statementTransactionOwner->owner_type))->where('id', $statementTransactionOwner->owner_id)->first();
|
||||
$company = $row->type === TransactionType::PAYMENT ? $row->owner->company : $row->owner->owner;
|
||||
|
||||
$booking = $row->owner;
|
||||
@@ -106,15 +110,15 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading
|
||||
];
|
||||
} else {
|
||||
$row = (App()->make(ListShippingPortalTransactions::class))->execute([
|
||||
'id' => $transaction->owner_id,
|
||||
'id' => $statementTransactionOwner->owner_id,
|
||||
'with_company' => true,
|
||||
]);
|
||||
|
||||
if (empty($row) || $row[0]['status'] != 'success') {
|
||||
$textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' Fetch Shipping Transaction Fail ' . json_encode([
|
||||
'id' => $transaction->owner_id,
|
||||
'id' => $statementTransactionOwner->owner_id,
|
||||
'with_company' => true,
|
||||
'StatementTransactionOwner_id' => $transaction->id,
|
||||
'StatementTransactionOwner_id' => $statementTransactionOwner->id,
|
||||
]) . PHP_EOL;
|
||||
file_put_contents($errorFilePath, $textToAppend, FILE_APPEND);
|
||||
|
||||
@@ -123,7 +127,24 @@ class ExportsInvoiceTransactions implements FromQuery, WithHeadings, WithHeading
|
||||
|
||||
Log::info('Error in Exports Invoice Transactions ' . $this->counter);
|
||||
|
||||
return [];
|
||||
return [
|
||||
'Transaction Not Found',
|
||||
$transaction->posting_date->format('m/d/Y H:m'),
|
||||
$transaction->transaction_description.' - '.$transaction->transaction_description_2,
|
||||
$statementTransactionOwner->system,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
0,
|
||||
$transaction->amount,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
''
|
||||
];
|
||||
}
|
||||
|
||||
$row = $row[0];
|
||||
|
||||
@@ -0,0 +1,132 @@
|
||||
<?php
|
||||
|
||||
namespace App\Classes\Modules\Exports\Services;
|
||||
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use Maatwebsite\Excel\Concerns\Exportable;
|
||||
use Maatwebsite\Excel\Concerns\FromQuery;
|
||||
use Maatwebsite\Excel\Concerns\ShouldAutoSize;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadingRow;
|
||||
use Maatwebsite\Excel\Concerns\WithHeadings;
|
||||
use Maatwebsite\Excel\Concerns\WithMapping;
|
||||
use Illuminate\Http\Request;
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use App\Classes\General\Eloquent\ApplyFiltersToQuery;
|
||||
use App\Models\StatementTransaction;
|
||||
use App\Models\Company;
|
||||
|
||||
class ExportsReceiptTransactions implements FromQuery, WithHeadings, WithHeadingRow, WithMapping, ShouldAutoSize
|
||||
{
|
||||
use Exportable;
|
||||
|
||||
private $request;
|
||||
private $counter = 1;
|
||||
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$this->request = $request;
|
||||
}
|
||||
|
||||
public function headings(): array
|
||||
{
|
||||
$header = [
|
||||
'DocNo',
|
||||
'DocDate',
|
||||
'DebtorCode',
|
||||
'Description',
|
||||
'DocNo2',
|
||||
'ProjNo',
|
||||
'DeptNo',
|
||||
'CurrencyCode',
|
||||
'ToHomeRate',
|
||||
'ToDebtorRate',
|
||||
'Note',
|
||||
'PaymentMethod',
|
||||
'ChequeNo',
|
||||
'PaymentAmt',
|
||||
'BankCharge',
|
||||
'ToBankRate',
|
||||
'BankChargeTaxType',
|
||||
'BankChargeTaxRefNo',
|
||||
'BankChargeProjNo',
|
||||
'BankChargeDeptNo',
|
||||
'PaymentBy',
|
||||
'FloatDay',
|
||||
'IsRCHQ',
|
||||
'RCHQDate',
|
||||
'KnockOffDocType',
|
||||
'KnockOffDocNo',
|
||||
'KnockOffAmt',
|
||||
'',
|
||||
];
|
||||
return $header;
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Support\Collection|mixed
|
||||
*/
|
||||
public function query()
|
||||
{
|
||||
$data = (new ApplyFiltersToQuery())->execute(StatementTransaction::query(), json_decode($this->request->input('filter'), true));
|
||||
if ($this->request->has('bankStatementTransactionId')) $data = $data->whereIn('id',json_decode($this->request->input('bankStatementTransactionId'), true));
|
||||
|
||||
return $data;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param StatementTransaction $transaction
|
||||
*
|
||||
* @return array
|
||||
*/
|
||||
public function map($transaction): array
|
||||
{
|
||||
$statementTransactionOwner = $transaction->owners()->whereIn('status', [ApprovalStatus::APPROVED])->first();
|
||||
$logArray = [
|
||||
'counter' => $this->counter,
|
||||
'system' => $statementTransactionOwner->system,
|
||||
'StatementTransactionOwner_id' => $statementTransactionOwner->id,
|
||||
'transaction_table_id' => $statementTransactionOwner->owner_id,
|
||||
];
|
||||
$this->counter += 1;
|
||||
$logArray = json_encode($logArray);
|
||||
|
||||
$filePath = storage_path('logs/exports_receipt_transactions.log');
|
||||
$errorFilePath = storage_path('logs/exports_receipt_transactions_error.log');
|
||||
$textToAppend = Carbon::now()->format('[Y-m-d H:i:s]') . ' ' . $logArray . PHP_EOL;
|
||||
file_put_contents($filePath, $textToAppend, FILE_APPEND);
|
||||
|
||||
$company = Company::where('name',$transaction->transaction_description_2)->first();
|
||||
|
||||
return [
|
||||
'<<New>>',
|
||||
Carbon::parse($transaction->posting_date)->format('d/m/Y'),
|
||||
($company ? $company->debtor : null),
|
||||
$transaction->transaction_description,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'MYR',
|
||||
1,
|
||||
1,
|
||||
'',
|
||||
'MBB',
|
||||
'',
|
||||
$transaction->amount,
|
||||
'',
|
||||
1,
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'',
|
||||
'0',
|
||||
'',
|
||||
'',
|
||||
'RI',
|
||||
$transaction->transaction_ref,
|
||||
$transaction->amount,
|
||||
'',
|
||||
];
|
||||
}
|
||||
}
|
||||
+111
@@ -0,0 +1,111 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Classes\Modules\Transactions\ControllersLogic;
|
||||
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Modules\Bookings\Services\FetchesBooking;
|
||||
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
|
||||
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
|
||||
use App\Classes\Modules\Transactions\Processors\CreatePurchaseOrderTransactionProcessor;
|
||||
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\PaymentMethodType;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Http\Resources\TransactionResource;
|
||||
use App\Models\Booking;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Log;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
|
||||
class ImportPurchaseOrderTransactionLogic extends AbstractControllerLogic
|
||||
{
|
||||
|
||||
/**
|
||||
* @return array
|
||||
*/
|
||||
protected function notification():array {
|
||||
return [
|
||||
'title' => 'Update Purchase Order',
|
||||
'message' => 'You have successfully updated you booking\'s purchase order'
|
||||
];
|
||||
}
|
||||
|
||||
/** @var FetchesBooking */
|
||||
private $fetchesBooking;
|
||||
|
||||
/** @var GeneratesTransactionBillNumber */
|
||||
private $generatesTransactionBillNumber;
|
||||
|
||||
/** @var CreatePurchaseOrderTransactionProcessor */
|
||||
private $createPurchaseOrderTransactionProcessor;
|
||||
|
||||
/**
|
||||
* CreatePurchaseOrderTransactionLogic constructor.
|
||||
* @param FetchesBooking $fetchesBooking
|
||||
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
|
||||
* @param CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor
|
||||
*/
|
||||
public function __construct(FetchesBooking $fetchesBooking, GeneratesTransactionBillNumber $generatesTransactionBillNumber, CreatePurchaseOrderTransactionProcessor $createPurchaseOrderTransactionProcessor)
|
||||
{
|
||||
$this->fetchesBooking = $fetchesBooking;
|
||||
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
|
||||
$this->createPurchaseOrderTransactionProcessor = $createPurchaseOrderTransactionProcessor;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param string $id
|
||||
* @return JsonResponse
|
||||
* @throws \App\Classes\Exceptions\MalformedRequestException
|
||||
*/
|
||||
public function logic(Request $request, $id = '') : JsonResponse
|
||||
{
|
||||
$files = $request->file('files');
|
||||
|
||||
$object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports');
|
||||
foreach ($object->getFiles() as $file){
|
||||
$collection = Excel::toCollection(null, json_decode($file)->file_info->original->file, null, null, true);
|
||||
|
||||
$sheet = $collection->first()->skip(1);
|
||||
|
||||
$products = $sheet->map(function ($row) {
|
||||
Log::info($row);
|
||||
$stockCode = $row[0];
|
||||
$description = $row[1];
|
||||
$quantity = $row[2];
|
||||
$unit_price = $row[3];
|
||||
|
||||
return [
|
||||
'stockCode' => $stockCode,
|
||||
'description' => $description,
|
||||
'quantity' => $quantity,
|
||||
'unit_price' => $unit_price
|
||||
];
|
||||
})->all();
|
||||
}
|
||||
|
||||
// dd($products);
|
||||
|
||||
/** @var Booking $booking */
|
||||
$booking = $this->fetchesBooking->execute(['id' => $request->route('id') ?? $id]);
|
||||
|
||||
$billNumber = $this->generatesTransactionBillNumber->execute('PO-');
|
||||
|
||||
$total = collect($products)->sum(function($product){
|
||||
return $product['quantity'] * floatval(str_replace(',', '', $product['unit_price']));
|
||||
});
|
||||
|
||||
$object = new TransactionObject($billNumber, TransactionType::PURCHASE_ORDER, $booking->company->id, 1,
|
||||
1, PaymentMethodType::CASH,
|
||||
$total, $total, $booking->fix_currency_id, $booking->fix_currency_id,
|
||||
1, 0, 0, null, ApprovalStatus::PENDING_SUBMISSION, $products);
|
||||
|
||||
|
||||
$transaction = $this->createPurchaseOrderTransactionProcessor->execute($booking, $object);
|
||||
|
||||
return $this->resourceResponse(new TransactionResource($transaction));
|
||||
|
||||
}
|
||||
}
|
||||
@@ -5,8 +5,12 @@ namespace App\Classes\Modules\Transactions\ControllersLogic;
|
||||
|
||||
use App\Classes\General\Abstracts\AbstractControllerLogic;
|
||||
use App\Classes\Modules\Transactions\Services\ListsTransactions;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\ValueObjects\Constants\TransactionType;
|
||||
use App\Http\Resources\BookingResource;
|
||||
use App\Http\Resources\WalletTransactionResource ;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\Wallet;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
@@ -39,6 +43,36 @@ class ListWalletTransactionsLogic extends AbstractControllerLogic
|
||||
|
||||
$query = $this->listsTransactions->execute($this->listsTransactions->deserializeFilters($request->input('filters')));
|
||||
|
||||
if (str_contains($request->input('filters'), "owner_id") && $query->count() > 0) {
|
||||
$wallet_total_incoming = Transaction::where('owner_type', $query->first()->owner_type)
|
||||
->where('owner_id', $query->first()->owner_id)
|
||||
->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
|
||||
->whereIn('type', [TransactionType::TOP_UP, TransactionType::CREDIT_NOTE])
|
||||
->sum('amount');
|
||||
|
||||
$wallet_total_outgoing = Transaction::where('owner_type', $query->first()->owner_type)
|
||||
->where('owner_id', $query->first()->owner_id)
|
||||
->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
|
||||
->whereIn('type', [TransactionType::PAYMENT, TransactionType::DEBIT_NOTE])
|
||||
->sum('amount');
|
||||
|
||||
$currentWalletBalance = $wallet_total_incoming - $wallet_total_outgoing;
|
||||
$incoming = Transaction::where('owner_type', $query->first()->owner_type)
|
||||
->where('owner_id', $query->first()->owner_id)
|
||||
->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
|
||||
->whereIn('type', [TransactionType::TOP_UP, TransactionType::CREDIT_NOTE])
|
||||
->where('id', '>', $query->first()->id)
|
||||
->sum('amount');
|
||||
$outgoing = Transaction::where('owner_type', $query->first()->owner_type)
|
||||
->where('owner_id', $query->first()->owner_id)
|
||||
->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])
|
||||
->whereIn('type', [TransactionType::PAYMENT, TransactionType::DEBIT_NOTE])
|
||||
->where('id', '>', $query->first()->id)
|
||||
->sum('amount');
|
||||
$runningBalanceInReverse = $currentWalletBalance - $incoming + $outgoing;
|
||||
$request['running_balance'] = $runningBalanceInReverse;
|
||||
}
|
||||
|
||||
return $this->collectionResponse(WalletTransactionResource::collection($query));
|
||||
|
||||
}
|
||||
|
||||
@@ -34,7 +34,8 @@ class GeneratesTransactionBillNumber
|
||||
|
||||
$attempt = 0;
|
||||
while ($attempt < 10) { // Retry up to 10 times
|
||||
$billNumber = $prefix . $date->format('Y') . $date->format('m') . '-' . microtime(true);
|
||||
// $billNumber = $prefix . $date->format('Y') . $date->format('m') . '-' . intval(microtime(true));
|
||||
$billNumber = $prefix . $date->format('Y') . $date->format('m') . '-' . mt_rand(1000000, 9999999);
|
||||
if (!$this->checksIfTransactionBillNumberExists->execute($billNumber)) {
|
||||
return $billNumber;
|
||||
}
|
||||
|
||||
@@ -8,9 +8,21 @@ final class SystemType {
|
||||
|
||||
public const SHIPPING_PORTAL = 'SHIPPING_PORTAL';
|
||||
|
||||
public const CNTR = 'CNTR';
|
||||
|
||||
public const LITE = 'LITE';
|
||||
|
||||
public const PROBASHI = 'PROBASHI';
|
||||
|
||||
public const PETS = 'PETS';
|
||||
|
||||
public const SYSTEM_NAMES = [
|
||||
'exchange' => self::EXCHANGE,
|
||||
'shipping_portal' => self::SHIPPING_PORTAL,
|
||||
'izyim' => self::SHIPPING_PORTAL,
|
||||
'lite' => self::LITE,
|
||||
'cntr' => self::CNTR,
|
||||
'probashi' => self::PROBASHI,
|
||||
'pets' => self::PETS
|
||||
];
|
||||
}
|
||||
|
||||
@@ -0,0 +1,44 @@
|
||||
<?php
|
||||
|
||||
namespace App\Console\Commands;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Console\Command;
|
||||
use Illuminate\Support\Facades\File;
|
||||
|
||||
class DeleteBulkInvoiceFiles extends Command
|
||||
{
|
||||
protected $signature = 'delete:bulk-download-files';
|
||||
|
||||
protected $description = 'Delete all the bulk download files';
|
||||
|
||||
public function __construct()
|
||||
{
|
||||
parent::__construct();
|
||||
}
|
||||
|
||||
public function handle()
|
||||
{
|
||||
$directories = [
|
||||
storage_path('app/bulk_invoice'),
|
||||
storage_path('app/bulk_whiteform'),
|
||||
];
|
||||
|
||||
foreach ($directories as $directory) {
|
||||
$start = new Carbon();
|
||||
$this->info(Carbon::now() . ' Start cleaning - ' . $directory);
|
||||
|
||||
if (File::isDirectory($directory)) {
|
||||
File::cleanDirectory($directory);
|
||||
$this->info('All files have been deleted.');
|
||||
} else {
|
||||
$this->info('Directory does not exist.');
|
||||
}
|
||||
|
||||
$end = new Carbon();
|
||||
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
|
||||
|
||||
$this->info(Carbon::now() . ' Process ended. ElapsedTime: ' . $elapsedTime);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -38,10 +38,10 @@ class Kernel extends ConsoleKernel
|
||||
->dailyAt('01:00')
|
||||
->appendOutputTo(storage_path().'/logs/soft-delete-seasonal-segmant-company.log')
|
||||
->withoutOverlapping();
|
||||
|
||||
$schedule->command('regenerateInvoice')
|
||||
->everyMinute()
|
||||
->appendOutputTo(storage_path().'/logs/regenerateInvoice.log')
|
||||
|
||||
$schedule->command('delete:bulk-download-files')
|
||||
->hourly()
|
||||
->appendOutputTo(storage_path().'/logs/delete-bulk-download-files.log')
|
||||
->withoutOverlapping();
|
||||
}
|
||||
|
||||
|
||||
@@ -22,6 +22,7 @@ use App\Http\Controllers\Controller;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
use DateTime;
|
||||
use App\Models\StatementTransaction;
|
||||
|
||||
class BankStatementController extends Controller
|
||||
{
|
||||
@@ -88,7 +89,9 @@ class BankStatementController extends Controller
|
||||
|
||||
public function rerun()
|
||||
{
|
||||
CreateBankStatementTransactionOwners::dispatch();
|
||||
foreach (StatementTransaction::doesntMapStatement()->get()->chunk(30) as $key => $transaction) {
|
||||
CreateBankStatementTransactionOwners::dispatch($transaction);
|
||||
}
|
||||
return redirect()->back()->with('success', 'Rerun triggered successfully');
|
||||
}
|
||||
|
||||
@@ -129,7 +132,7 @@ class BankStatementController extends Controller
|
||||
->download($statement->date_from->format('Y-m-d') . '_' . $statement->date_to->format('Y-m-d') . '_statement.csv');
|
||||
}
|
||||
|
||||
public function fetch(Request $request, ListBankStatementDetailsLogic $logic): JsonResponse
|
||||
public function fetch(Request $request, ListBankStatementTransactionsLogic $logic): JsonResponse
|
||||
{
|
||||
return $logic->execute($request);
|
||||
}
|
||||
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Bookings;
|
||||
|
||||
use App\Classes\Modules\Bookings\ControllersLogic\ExpireBookingPaymentControllerLogic;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class ExpireBookingPaymentController
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param DeleteBookingPaymentControllerLogic $logic
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function expire(Request $request, ExpireBookingPaymentControllerLogic $logic): JsonResponse {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Companies;
|
||||
|
||||
use App\Classes\Modules\Companies\ControllersLogic\BulkDownloadCustomerInvoicesLogic;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BulkDownloadCustomerInvoicesController
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param BulkDownloadCustomerInvoicesLogic $logic
|
||||
* @return void
|
||||
* @throws \App\Classes\Exceptions\MalformedRequestException
|
||||
*/
|
||||
public function download(Request $request, BulkDownloadCustomerInvoicesLogic $logic) {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,20 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Companies;
|
||||
|
||||
use App\Classes\Modules\Companies\ControllersLogic\BulkDownloadSupplierWhiteFormsLogic;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
class BulkDownloadSupplierWhiteFormsController
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param BulkDownloadSupplierWhiteFormsLogic $logic
|
||||
* @return void
|
||||
* @throws \App\Classes\Exceptions\MalformedRequestException
|
||||
*/
|
||||
public function download(Request $request, BulkDownloadSupplierWhiteFormsLogic $logic) {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
|
||||
}
|
||||
@@ -15,6 +15,9 @@ use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Maatwebsite\Excel\Excel;
|
||||
use App\Classes\Modules\Exports\Services\ExportsImportedInvoiceMappeds;
|
||||
use App\Models\TransactionMappingLog;
|
||||
use App\Classes\Modules\Exports\Services\ExportsReceiptTransactions;
|
||||
|
||||
class ExportCustomersToExcelController
|
||||
{
|
||||
@@ -64,6 +67,13 @@ class ExportCustomersToExcelController
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function receiptTransactions(Request $request){
|
||||
$exportsTransactions = new ExportsReceiptTransactions($request);
|
||||
$response = $exportsTransactions->download('receipt-transactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
|
||||
ob_end_clean();
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function bookingTransactions(ExportsBookingTransactions $exportsBookingTransactions, Request $request){
|
||||
$response = $exportsBookingTransactions->download('bookingTransactions.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
|
||||
ob_end_clean();
|
||||
@@ -75,4 +85,10 @@ class ExportCustomersToExcelController
|
||||
ob_end_clean();
|
||||
return $response;
|
||||
}
|
||||
|
||||
public function importedInvoiceMapped(ExportsImportedInvoiceMappeds $exportsImportedInvoiceMappeds, Request $request) {
|
||||
$response = $exportsImportedInvoiceMappeds->download($request->input('fileName').'.xls', Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
|
||||
ob_end_clean();
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,32 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Controllers\Exports;
|
||||
|
||||
use App\Classes\Modules\Exports\Services\ExportsCustomersWalletTransactionHistory;
|
||||
use App\Models\User;
|
||||
use Illuminate\Http\Request;
|
||||
use Illuminate\Support\Facades\Auth;
|
||||
use Maatwebsite\Excel\Excel;
|
||||
|
||||
class ExportCustomersWalletTransactionToExcelController
|
||||
{
|
||||
|
||||
/**
|
||||
* ExportCustomersWalletTransactionToExcelController constructor.
|
||||
* @param Request $request
|
||||
*/
|
||||
public function __construct(Request $request)
|
||||
{
|
||||
$token = Auth::fromUser(User::find(1));
|
||||
$request->headers->set('Authorization', 'Bearer ' . $token);
|
||||
}
|
||||
|
||||
public function export(Request $request)
|
||||
{
|
||||
$exportsTransactions = new ExportsCustomersWalletTransactionHistory($request);
|
||||
$filename = $request->route('marking') . '-wallet-' . ($request->route('is_precise') == 'true' ? 'precise-' : '') . 'transaction-history.xls';
|
||||
$response = $exportsTransactions->download($filename, Excel::XLS, ['Content-Type' => 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet']);
|
||||
ob_end_clean();
|
||||
return $response;
|
||||
}
|
||||
}
|
||||
@@ -2,33 +2,47 @@
|
||||
|
||||
namespace App\Http\Controllers\Imports;
|
||||
|
||||
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
|
||||
use App\Classes\Modules\Imports\Services\GenericImport;
|
||||
use App\Classes\Modules\Segments\DataTransferObjects\SeasonalSegmentObject;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Models\Segment;
|
||||
use App\Models\User;
|
||||
use Carbon\Carbon;
|
||||
use DateTime;
|
||||
use Carbon\Carbon;
|
||||
use App\Models\User;
|
||||
use App\Models\Company;
|
||||
use App\Models\Segment;
|
||||
use App\Models\Transaction;
|
||||
use Illuminate\Http\Request;
|
||||
use App\Models\SeasonalSegment;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
use Maatwebsite\Excel\Facades\Excel;
|
||||
use App\Models\TransactionMappingLog;
|
||||
use App\Classes\ValueObjects\Constants\HttpStatus;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
use App\Classes\Modules\Imports\Services\GenericImport;
|
||||
use App\Classes\ValueObjects\Response\ApiResponseObject;
|
||||
use App\Classes\Modules\Accounting\Processors\ChecksBillNumber;
|
||||
use App\Classes\Modules\Segments\Services\CreatesSeasonalSegment;
|
||||
use App\Classes\Modules\Companies\Processors\AssignSegmentProcessor;
|
||||
use App\Models\Company;
|
||||
use App\Models\SeasonalSegment;
|
||||
use App\Models\Transaction;
|
||||
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
|
||||
use App\Classes\Modules\Segments\DataTransferObjects\SeasonalSegmentObject;
|
||||
|
||||
class ImportStatementInvoiceController
|
||||
{
|
||||
private $responseTitle;
|
||||
private $responseMessage;
|
||||
|
||||
public function __construct() {
|
||||
$this->responseTitle = 'Import Invoice Mapping';
|
||||
$this->responseMessage = 'You have successfully imported invoice mapping';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return array
|
||||
* @throws \App\Classes\Exceptions\MalformedRequestException
|
||||
*/
|
||||
public function import(Request $request)
|
||||
public function import(Request $request) : JsonResponse
|
||||
{
|
||||
ini_set('memory_limit', '-1');
|
||||
|
||||
$importDate = date('Y-m-d H:i:s');
|
||||
$object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports');
|
||||
$file = json_decode($object->getFiles()[0])->file_info->original->file;
|
||||
|
||||
@@ -37,26 +51,37 @@ class ImportStatementInvoiceController
|
||||
$excelRows = $import->rows;
|
||||
$excelRows = $excelRows->toArray();
|
||||
|
||||
$data = [];
|
||||
foreach ($excelRows as $row) {
|
||||
dd($row);
|
||||
// $row['debtor_code']
|
||||
|
||||
// attempt 1 - try map by amount and date
|
||||
// $transactionDate = $this->changeExcelDate($row['date']);
|
||||
// $transaction = Transaction::where('original_amount', $row['total'])->whereDate('created_at', $transactionDate)->get();
|
||||
// if ($transaction) {
|
||||
// // check company
|
||||
// // $company = Company::where('debtor', $row['debtor_code'])->first();
|
||||
// // dd($company);
|
||||
// // try to verify is it the correct transaction
|
||||
// }
|
||||
$row['mapped_result_reference'] = null;
|
||||
$row['mapped_status'] = 'failed';
|
||||
$row['date'] = date('Y-m-d', strtotime($row['date']));
|
||||
|
||||
// Shipping Info
|
||||
// TOPUP -> map with transaction.bill_no
|
||||
if (str_starts_with($row['shipping_info'], 'TOPUP')) {
|
||||
// find in exchange first, if cannont then find in izyim
|
||||
// (App()->make(ChecksBillNumber::class))->execute($bill_no, 'exchange');
|
||||
foreach (['exchange','izyim'] as $system) {
|
||||
$returnReference = $this->mappingTopUp($row, $system);
|
||||
if ($returnReference) {
|
||||
$row['mapped_result_reference'] = $returnReference;
|
||||
$row['mapped_status'] = 'success';
|
||||
}
|
||||
}
|
||||
} else {
|
||||
$returnReference = $this->mappingExchange($row);
|
||||
if ($returnReference) {
|
||||
$row['mapped_result_reference'] = $returnReference;
|
||||
$row['mapped_status'] = 'success';
|
||||
}
|
||||
}
|
||||
|
||||
TransactionMappingLog::create([
|
||||
'imported_date'=>$importDate,
|
||||
'data'=>$row,
|
||||
]);
|
||||
array_push($data, $row);
|
||||
|
||||
|
||||
// if 5 digits -> exchange booking reference
|
||||
// find transation
|
||||
@@ -88,12 +113,53 @@ class ImportStatementInvoiceController
|
||||
|
||||
|
||||
}
|
||||
|
||||
return $this->response(['data'=>$data,'importedDate'=>$importDate]);
|
||||
}
|
||||
|
||||
public function changeExcelDate($date)
|
||||
{
|
||||
$unixTime = (($date - 25569) * 86400);
|
||||
$date = new DateTime("@$unixTime");
|
||||
return $date->format('Y-m-d'); // Change the format to 'Y-m-d'
|
||||
public function response(?array $data = []) : JsonResponse {
|
||||
return (new ApiResponseObject($this->responseTitle,
|
||||
$this->responseMessage,
|
||||
HttpStatus::OK_WITH_MESSAGE, $data))->handler();
|
||||
}
|
||||
|
||||
private function mappingTopUp(Array $row, String $system) {
|
||||
try {
|
||||
if ($data = (App()->make(ChecksBillNumber::class))->execute($row['shipping_info'], $system)) {
|
||||
if ($system == 'izyim' && isset($data['owner_reference'])) return $data['owner_reference'];
|
||||
|
||||
if ($system == 'exchange') return $this->updateTransactionOwnerReference($data, $row['doc_no']);
|
||||
}
|
||||
} catch (\Throwable $th) {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
private function mappingExchange(Array $row) {
|
||||
$date = $row['date'];
|
||||
$transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where('statement_transactions.amount', $row['net_total'])->whereRaw("DATE(posting_date) = '$date'")->get();
|
||||
|
||||
if ($transactions && $transactions->count() == 0) {
|
||||
$transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where(DB::raw('FLOOR(statement_transactions.amount)'), floor($row['net_total']))->whereRaw("DATE(posting_date) = '$date'")->get();
|
||||
}
|
||||
|
||||
if ($transactions && $transactions->count() == 1) {
|
||||
foreach ($transactions as $key => $transaction) {
|
||||
return $this->updateTransactionOwnerReference($transaction, $row['doc_no']);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function updateTransactionOwnerReference($transaction, String $docNo) {
|
||||
$transactionOwner = $transaction->transaction_owner;
|
||||
if ($transactionOwner) {
|
||||
$transactionOwner->update([
|
||||
'invoice_reference'=>$docNo,
|
||||
'status'=>ApprovalStatus::COMPLETED
|
||||
]);
|
||||
return $transactionOwner->owner_reference;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -17,9 +17,22 @@ use App\Classes\Modules\Companies\Processors\AssignSegmentProcessor;
|
||||
use App\Models\Company;
|
||||
use App\Models\SeasonalSegment;
|
||||
use App\Models\Transaction;
|
||||
use App\Models\TransactionMappingLog;
|
||||
use App\Classes\ValueObjects\Response\ApiResponseObject;
|
||||
use App\Classes\ValueObjects\Constants\HttpStatus;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Support\Facades\DB;
|
||||
|
||||
class ImportStatementReceiptsController
|
||||
{
|
||||
private $responseTitle;
|
||||
private $responseMessage;
|
||||
|
||||
public function __construct() {
|
||||
$this->responseTitle = 'Import Receipt Mapping';
|
||||
$this->responseMessage = 'You have successfully imported receipt mapping';
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Request $request
|
||||
* @return array
|
||||
@@ -27,6 +40,7 @@ class ImportStatementReceiptsController
|
||||
*/
|
||||
public function import(Request $request)
|
||||
{
|
||||
$importDate = date('Y-m-d H:i:s');
|
||||
$object = new DocumentObject('', $request->input('files'), '', ApprovalStatus::APPROVED, 'imports');
|
||||
$file = json_decode($object->getFiles()[0])->file_info->original->file;
|
||||
|
||||
@@ -35,16 +49,59 @@ class ImportStatementReceiptsController
|
||||
$excelRows = $import->rows;
|
||||
$excelRows = $excelRows->toArray();
|
||||
|
||||
$data = [];
|
||||
foreach ($excelRows as $row) {
|
||||
// if has date column
|
||||
// $transactionDate = $this->changeExcelDate($row['date']);
|
||||
$row['mapped_result_reference'] = null;
|
||||
$row['mapped_status'] = 'failed';
|
||||
$row['date'] = date('Y-m-d', strtotime($row['doc_date']));
|
||||
|
||||
$returnReference = $this->mappingExchange($row);
|
||||
if ($returnReference) {
|
||||
$row['mapped_result_reference'] = $returnReference;
|
||||
$row['mapped_status'] = 'success';
|
||||
}
|
||||
|
||||
TransactionMappingLog::create([
|
||||
'imported_date'=>$importDate,
|
||||
'data'=>$row,
|
||||
]);
|
||||
array_push($data, $row);
|
||||
}
|
||||
|
||||
return $this->response(['data'=>$data,'importedDate'=>$importDate]);
|
||||
}
|
||||
|
||||
public function changeExcelDate($date)
|
||||
{
|
||||
$unixTime = (($date - 25569) * 86400);
|
||||
$date = new DateTime("@$unixTime");
|
||||
return $date->format('Y-m-d'); // Change the format to 'Y-m-d'
|
||||
public function response(?array $data = []) : JsonResponse {
|
||||
return (new ApiResponseObject($this->responseTitle,
|
||||
$this->responseMessage,
|
||||
HttpStatus::OK_WITH_MESSAGE, $data))->handler();
|
||||
}
|
||||
|
||||
private function mappingExchange(Array $row) {
|
||||
$date = $row['date'];
|
||||
$transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where('statement_transactions.amount', $row['payment_amount'])->whereRaw("DATE(posting_date) = '$date'")->get();
|
||||
|
||||
if ($transactions && $transactions->count() == 0) {
|
||||
$transactions = Transaction::getReceiverWithJoinStatementTransactionAndOwner($row)->select('transactions.*')->where(DB::raw('FLOOR(statement_transactions.amount)'), floor($row['payment_amount']))->whereRaw("DATE(posting_date) = '$date'")->get();
|
||||
}
|
||||
|
||||
if ($transactions && $transactions->count() == 1) {
|
||||
foreach ($transactions as $key => $transaction) {
|
||||
return $this->updateTransactionOwnerReference($transaction, $row['doc_no']);
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
public function updateTransactionOwnerReference($transaction, String $docNo) {
|
||||
$transactionOwner = $transaction->transaction_owner;
|
||||
if ($transactionOwner) {
|
||||
$transactionOwner->update([
|
||||
'receipt_reference'=>$docNo,
|
||||
'status'=>ApprovalStatus::COMPLETED
|
||||
]);
|
||||
return $transactionOwner->owner_reference;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -0,0 +1,21 @@
|
||||
<?php
|
||||
|
||||
|
||||
namespace App\Http\Controllers\Transactions;
|
||||
|
||||
use App\Classes\Modules\Transactions\ControllersLogic\ImportPurchaseOrderTransactionLogic;
|
||||
use Illuminate\Http\JsonResponse;
|
||||
use Illuminate\Http\Request;
|
||||
|
||||
|
||||
class ImportPurchaseOrderTransactionController
|
||||
{
|
||||
/**
|
||||
* @param Request $request
|
||||
* @param ImportPurchaseOrderTransactionLogic $logic
|
||||
* @return JsonResponse
|
||||
*/
|
||||
public function import(Request $request, ImportPurchaseOrderTransactionLogic $logic) : JsonResponse {
|
||||
return $logic->execute($request);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
namespace App\Http\Resources;
|
||||
|
||||
use Carbon\Carbon;
|
||||
use Illuminate\Http\Resources\Json\JsonResource;
|
||||
|
||||
class BankStatementDetailResource extends JsonResource
|
||||
{
|
||||
/**
|
||||
* Transform the resource collection into an array.
|
||||
*
|
||||
* @param \Illuminate\Http\Request $request
|
||||
* @return array
|
||||
*/
|
||||
public function toArray($request)
|
||||
{
|
||||
$transaction = $this->transaction;
|
||||
$accountStatement = $transaction->statement;
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'date' => Carbon::parse($transaction->posting_date)->format('Y-m-d'),
|
||||
'transaction_description_1' => $transaction->transaction_description,
|
||||
'transaction_description_2' => $transaction->transaction_description_2,
|
||||
'transaction_description_3' => $transaction->transaction_description_3,
|
||||
'transaction_description_4' => $transaction->transaction_description_4,
|
||||
'transaction_description_5' => $transaction->transaction_description_5,
|
||||
'pay_for' => $transaction->transaction_description_2,
|
||||
'system_references' => $this->system,
|
||||
'amount' => $transaction->amount,
|
||||
'account_statement_date_from' => Carbon::parse($accountStatement->date_from)->format('Y-m-d'),
|
||||
'account_statement_date_to' => Carbon::parse($accountStatement->date_to)->format('Y-m-d'),
|
||||
];
|
||||
}
|
||||
}
|
||||
@@ -28,7 +28,7 @@ class BankStatementTransactionOwnerResource extends JsonResource
|
||||
}
|
||||
|
||||
if($this->type === StatementTransactionOwnerType::WALLET_TOP_UP){
|
||||
$referenceLink = route('booking.details', $this->owner_reference);
|
||||
$referenceLink = route('wallet.details', $this->owner_reference);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -16,6 +16,7 @@ class TransactionDetailResource extends JsonResource
|
||||
{
|
||||
|
||||
return [
|
||||
'id' => $this->id,
|
||||
'stockCode' => $this->product_code,
|
||||
'description' => $this->product_name,
|
||||
'quantity' => $this->quantity,
|
||||
|
||||
@@ -21,7 +21,7 @@ class WalletResource extends JsonResource
|
||||
'currency_id' => $this->currency_id,
|
||||
'amount' => (double) $this->amount,
|
||||
'company_id' => (int) $this->owner->id,
|
||||
'transactions' => $this->whenLoaded('transactions', WalletTransactionResource::collection($this->transactions()->whereIn('status', [2, 3])->orderBy('id', 'DESC')->get()), []),
|
||||
// 'transactions' => $this->whenLoaded('transactions', WalletTransactionResource::collection($this->transactions()->whereIn('status', [2, 3])->orderBy('id', 'DESC')->get()), []),
|
||||
'top_up_records' => $this->whenLoaded('transactions', WalletTransactionResource::collection($this->transactions()->whereNotIn('status', [0])->where('type', TransactionType::TOP_UP)->orderBy('id', 'DESC')->get()), []),
|
||||
];
|
||||
}
|
||||
|
||||
@@ -20,12 +20,15 @@ class WalletTransactionResource extends JsonResource
|
||||
public function toArray($request)
|
||||
{
|
||||
$description = '';
|
||||
$current_running_balance = $request['running_balance'];
|
||||
switch((int) $this->type){
|
||||
case 5:
|
||||
$description = (double) $this->amount.' Credit Top up';
|
||||
$request['running_balance'] = bcsub($request['running_balance'], $this->amount, 5);
|
||||
break;
|
||||
case 9:
|
||||
$description = 'Credit Voucher for '.$this->payment_reference;
|
||||
$request['running_balance'] = bcsub($request['running_balance'], $this->amount, 5);
|
||||
break;
|
||||
case 1:
|
||||
$booking = Transaction::where('payment_reference', $this->bill_no)->first()->owner;
|
||||
@@ -35,11 +38,13 @@ class WalletTransactionResource extends JsonResource
|
||||
break;
|
||||
}
|
||||
|
||||
$request['running_balance'] = bcadd($request['running_balance'], $this->amount, 5);
|
||||
$marking = $booking->marking;
|
||||
$description = 'Payment For booking refs.'.'<a href="'.route('booking.details', $marking).'">'.$marking.'</a>';
|
||||
break;
|
||||
case 11:
|
||||
$description = 'Debit Voucher for '.$this->payment_reference;
|
||||
$request['running_balance'] = bcadd($request['running_balance'], $this->amount, 5);
|
||||
break;
|
||||
|
||||
}
|
||||
@@ -53,6 +58,7 @@ class WalletTransactionResource extends JsonResource
|
||||
'payment_method' => (float) $this->payment_method,
|
||||
'issuer_name' => $this->issuerCompany->name,
|
||||
'amount' => (double) $this->amount,
|
||||
'running_balance' => (double) $current_running_balance,
|
||||
'service_charge' => (double) $this->service_charge,
|
||||
'tax' => (double) $this->tax,
|
||||
'status' => (int) $this->status,
|
||||
|
||||
@@ -16,6 +16,8 @@ class AccountStatement extends Model
|
||||
'total_amount',
|
||||
'begin_balance',
|
||||
'end_balance',
|
||||
'total_rows',
|
||||
'mapped_rows',
|
||||
];
|
||||
|
||||
protected $casts = [
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Staudenmeir\EloquentHasManyDeep\HasRelationships;
|
||||
use App\Classes\ValueObjects\Constants\ApprovalStatus;
|
||||
|
||||
class StatementTransaction extends Model
|
||||
{
|
||||
@@ -47,4 +48,16 @@ class StatementTransaction extends Model
|
||||
{
|
||||
return $this->hasMany(StatementTransactionOwner::class);
|
||||
}
|
||||
|
||||
public function owner_status()
|
||||
{
|
||||
return $this->owners()->whereIn('status',[ApprovalStatus::APPROVED,ApprovalStatus::COMPLETED,ApprovalStatus::PENDING_VERIFICATION]);
|
||||
}
|
||||
|
||||
public function scopeDoesntMapStatement($query)
|
||||
{
|
||||
$query->whereDoesntHave('owners', function($query){
|
||||
return $query->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED]);
|
||||
})->orderBy('posting_date');
|
||||
}
|
||||
}
|
||||
|
||||
@@ -5,6 +5,7 @@ namespace App\Models;
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
use Illuminate\Database\Eloquent\Relations\BelongsTo;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
|
||||
class StatementTransactionOwner extends Model
|
||||
{
|
||||
@@ -21,9 +22,20 @@ class StatementTransactionOwner extends Model
|
||||
'receipt_reference',
|
||||
'status',
|
||||
];
|
||||
|
||||
public function owner(): morphTo
|
||||
{
|
||||
return $this->morphTo();
|
||||
}
|
||||
|
||||
public function transaction(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(StatementTransaction::class, 'statement_transaction_id', 'id');
|
||||
}
|
||||
|
||||
public function scopeGetSiblingsOwner($query) {
|
||||
$query->where('system', $this->system)
|
||||
->where('owner_type', $this->owner_type)
|
||||
->where('owner_id', $this->owner_id);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -18,6 +18,7 @@ use Illuminate\Database\Eloquent\Relations\HasOneThrough;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphMany;
|
||||
use Illuminate\Database\Eloquent\Relations\MorphTo;
|
||||
use Staudenmeir\EloquentHasManyDeep\HasTableAlias;
|
||||
use App\Models\StatementTransactionOwner;
|
||||
|
||||
|
||||
class Transaction extends AbstractModel implements Documentable, Transactionable, Voucherifiable
|
||||
@@ -53,6 +54,14 @@ class Transaction extends AbstractModel implements Documentable, Transactionable
|
||||
return $this->MorphOne(Transaction::class, 'owner')->where('type', TransactionType::CREDIT_NOTE);
|
||||
}
|
||||
|
||||
/**
|
||||
* @return \Illuminate\Database\Eloquent\Relations\MorphOne
|
||||
*/
|
||||
public function transaction_owner()
|
||||
{
|
||||
return $this->MorphOne(StatementTransactionOwner::class, 'owner','owner_type','owner_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo
|
||||
*/
|
||||
@@ -69,6 +78,16 @@ class Transaction extends AbstractModel implements Documentable, Transactionable
|
||||
return $this->BelongsTo( Company::class, 'issuer', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* Get the user that owns the Transaction
|
||||
*
|
||||
* @return BelongsTo
|
||||
*/
|
||||
public function receiverCompany(): BelongsTo
|
||||
{
|
||||
return $this->belongsTo(Company::class, 'receiver', 'id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return BelongsTo
|
||||
*/
|
||||
@@ -202,6 +221,22 @@ class Transaction extends AbstractModel implements Documentable, Transactionable
|
||||
return $query->whereIn('status', [ApprovalStatus::APPROVED]);
|
||||
}
|
||||
|
||||
/**
|
||||
* @param Builder $query
|
||||
* @return Builder
|
||||
*/
|
||||
public function scopeGetReceiverWithJoinStatementTransactionAndOwner(Builder $query, Array $row) {
|
||||
$query->join('companies',function($q) use ($row) {
|
||||
$q->on('companies.id','=','transactions.receiver');
|
||||
$q->where('debtor',$row['debtor_code']);
|
||||
})
|
||||
->join('statement_transaction_owners', function ($q) {
|
||||
$q->on('statement_transaction_owners.owner_id','=','transactions.id');
|
||||
$q->where('statement_transaction_owners.owner_type','=',Transaction::class);
|
||||
})
|
||||
->join('statement_transactions','statement_transactions.id','=','statement_transaction_owners.statement_transaction_id');
|
||||
}
|
||||
|
||||
/**
|
||||
* @return MorphMany
|
||||
*/
|
||||
|
||||
@@ -0,0 +1,24 @@
|
||||
<?php
|
||||
|
||||
namespace App\Models;
|
||||
|
||||
use Illuminate\Database\Eloquent\Factories\HasFactory;
|
||||
use Illuminate\Database\Eloquent\Model;
|
||||
|
||||
class TransactionMappingLog extends Model
|
||||
{
|
||||
protected $fillable = ['imported_by','data','imported_date'];
|
||||
|
||||
protected $casts = [
|
||||
'data' => 'array',
|
||||
];
|
||||
|
||||
public static function boot() {
|
||||
parent::boot();
|
||||
|
||||
static::creating(function ($model) {
|
||||
$model->imported_by = auth()->user()->id;
|
||||
});
|
||||
}
|
||||
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class CreateTransactionMappingLogsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::create('transaction_mapping_logs', function (Blueprint $table) {
|
||||
$table->id();
|
||||
$table->bigInteger('imported_by')->unsigned();
|
||||
$table->foreign('imported_by')->references('id')->on('users');
|
||||
$table->dateTime('imported_date')->nullable();
|
||||
$table->text('data')->nullable();
|
||||
$table->timestamps();
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::dropIfExists('transaction_mapping_logs');
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,34 @@
|
||||
<?php
|
||||
|
||||
use Illuminate\Database\Migrations\Migration;
|
||||
use Illuminate\Database\Schema\Blueprint;
|
||||
use Illuminate\Support\Facades\Schema;
|
||||
|
||||
class AddMappedRateToAccountStatementsTable extends Migration
|
||||
{
|
||||
/**
|
||||
* Run the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function up()
|
||||
{
|
||||
Schema::table('account_statements', function (Blueprint $table) {
|
||||
$table->integer('total_rows')->unsigned()->default(0)->after('end_balance');
|
||||
$table->integer('mapped_rows')->unsigned()->default(0)->after('end_balance');
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Reverse the migrations.
|
||||
*
|
||||
* @return void
|
||||
*/
|
||||
public function down()
|
||||
{
|
||||
Schema::table('account_statements', function (Blueprint $table) {
|
||||
$table->dropColumn('total_rows');
|
||||
$table->dropColumn('mapped_rows');
|
||||
});
|
||||
}
|
||||
}
|
||||
Binary file not shown.
@@ -77,6 +77,13 @@
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
|
||||
export default {
|
||||
props:{
|
||||
editMapped: {
|
||||
type: Boolean,
|
||||
default: false,
|
||||
required: false
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
error: '',
|
||||
@@ -116,6 +123,8 @@
|
||||
system_references : this.system_references ? this.system_references.toLowerCase() : '',
|
||||
transaction_reference : this.transaction_reference
|
||||
};
|
||||
|
||||
if (this.editMapped) this.parameters['editMapped'] = true;
|
||||
|
||||
this.submit(this.route('api.accounting.statement.details.update', this.data.id), 'put', this.section, true, true);
|
||||
},
|
||||
|
||||
+55
-2
@@ -11,6 +11,46 @@
|
||||
<div class="col"><a :href="item.owners.pending_verification[0].reference_link" target="_blank">{{item.owners.pending_verification[0].reference}}</a></div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<!-- Pending Export tab -->
|
||||
<div class="col-5" v-if="item.owners.approved.length === 1">
|
||||
<div class="row">
|
||||
<div class="col">{{item.owners.approved[0].system}}</div>
|
||||
<div class="col">{{ typeString(item.owners.approved[0].type) }}</div>
|
||||
<div class="col">
|
||||
<div class="col d-flex justify-content-between">
|
||||
<a :href="item.owners.approved[0].reference_link" target="_blank">{{item.owners.approved[0].reference}}</a>
|
||||
<div v-if="stage === 4">
|
||||
<!-- revert button -->
|
||||
<button class="btn btn-xs btn-outline-danger b-rad-none m-r-5 requestModal" data-type="approveCorrectMappingTransaction">
|
||||
<i class="fa fa-times fa-fw"></i>
|
||||
</button>
|
||||
<modal-component class="animate__animated animate__fast animate__fadeIn" type="approveCorrectMappingTransaction">
|
||||
<general-confirmation-form-component
|
||||
:contentText="returnTextRevert(item.owners.approved[0].reference)"
|
||||
modalType="confirm"
|
||||
class="text-center"
|
||||
:apiRoute="route('api.accounting.bankStatement.details.status.update', item.owners.approved[0].id, 'pending_verification')"
|
||||
apiMethod="post"
|
||||
:section="section"
|
||||
>
|
||||
</general-confirmation-form-component>
|
||||
</modal-component>
|
||||
|
||||
<!-- edit button -->
|
||||
<button class="btn btn-xs btn-outline-success b-rad-none m-r-5 requestModal" data-type="updateOwner">
|
||||
<i class="fa fa-edit"></i>
|
||||
</button>
|
||||
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="updateOwner">
|
||||
<edit-single-item-in-list-component :data="item" :section="section" editMapped="true"></edit-single-item-in-list-component>
|
||||
</modal-component>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-5" v-if="item.owners.pending_verification.length > 1">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@@ -52,7 +92,8 @@
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-5" v-if="!item.owners.pending_verification.length">
|
||||
|
||||
<div class="col-5" v-if="!item.owners.pending_verification.length && !item.owners.approved.length">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<button class="btn btn-xs btn-outline-success b-rad-none m-r-5 requestModal" data-type="updateOwner">
|
||||
@@ -81,7 +122,13 @@
|
||||
|
||||
</div>
|
||||
<div class="col-1">{{ item.amount }}</div>
|
||||
<div class="col-1 text-success" v-if="item.owners.approved.length">{{ [6, 7, 8, 9, 10, 11, 12, 13, 14].include(item.owners.approved[0].type) ? 'Miscellaneous' : 'Approved' }}</div>
|
||||
<div class="col-1 text-success" v-if="item.owners.approved.length">{{ [6, 7, 8, 9, 10, 11, 12, 13, 14].includes(item.owners.approved[0].type) ? 'Miscellaneous' : 'Approved' }}</div>
|
||||
|
||||
<!-- Pending Export tab for checkbox here -->
|
||||
<div class="col-1" v-if="item.owners.approved.length === 1">
|
||||
<input type="checkbox" class="request_export_item" v-model="selectAll" :value="item.id">
|
||||
</div>
|
||||
|
||||
<div class="col-1 text-danger" v-if="!item.owners.approved.length">Pending...</div>
|
||||
<div class="col-1" v-if="stage === 1">
|
||||
<button class="btn btn-xs btn-outline-danger b-rad-none m-r-5 requestModal" data-type="deleteMappingTransaction">
|
||||
@@ -117,6 +164,9 @@
|
||||
section:{
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
selectAll: {
|
||||
type:Boolean
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
@@ -154,6 +204,9 @@
|
||||
},
|
||||
returnTextWithVariable(variable) {
|
||||
return "Are you sure you want to choose this mapping " + variable + "?";
|
||||
},
|
||||
returnTextRevert(variable) {
|
||||
return "Are you sure you want to revert this mapping " + variable + "?";
|
||||
}
|
||||
},
|
||||
mixins: [componentHandler]
|
||||
|
||||
+72
@@ -0,0 +1,72 @@
|
||||
<template>
|
||||
<div class="row m-b-10 parentContainer">
|
||||
<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-7">
|
||||
<div class="row">
|
||||
<div class="col">{{item.owners.approved[0].system}}</div>
|
||||
<div class="col">{{ typeString(item.owners.approved[0].type) }}</div>
|
||||
<div class="col"><a :href="item.owners.approved[0].reference_link" target="_blank">{{item.owners.approved[0].reference}}</a></div>
|
||||
<div class="col">{{item.owners.approved[0].invoice_reference}}</div>
|
||||
<div class="col">{{item.owners.approved[0].receipt_reference}}</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-1">{{ item.amount }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import componentHandler from '../../../general/mixins/componentHandler';
|
||||
export default {
|
||||
props: {
|
||||
stage: {
|
||||
type: Number,
|
||||
default: 0
|
||||
},
|
||||
section:{
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
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>
|
||||
+126
@@ -0,0 +1,126 @@
|
||||
<template>
|
||||
<div class="row h-100 parentContainer">
|
||||
<div class="col-12" style="min-height: 20px;">
|
||||
<loading-component style="height: 20px; top: 0;" key="1" color="success" v-show="isLoading"></loading-component>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<div class="card">
|
||||
<div class="card-header">
|
||||
<h3>{{ componentTitle }}</h3>
|
||||
<div class="text-right">
|
||||
<button class="btn btn-xs btn-outline-success b-rad-none m-r-5" @click="downloadInvoiceMapped">
|
||||
Download Invoices Mapped
|
||||
</button>
|
||||
</div>
|
||||
</div>
|
||||
<!-- /.card-header -->
|
||||
<div class="card-body table-responsive p-0">
|
||||
<table class="table table-hover">
|
||||
<thead>
|
||||
<tr>
|
||||
<th v-for="item in tableHeaders">{{ item }}</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody v-show="!isLoading">
|
||||
<tr v-for="(item, index) in $store.getters.getListData(section)">
|
||||
<td>{{index+1}}</td>
|
||||
<td>{{item.doc_no }}</td>
|
||||
<td>{{item.date}}</td>
|
||||
<td>{{item.debtor_code }}}</td>
|
||||
<td>{{item.debtor_name}}</td>
|
||||
<td>{{item.shipping_info}}</td>
|
||||
<td>{{item.net_total}}</td>
|
||||
<td>{{item.cancelled}}</td>
|
||||
<td>{{item.mapped_status}}</td>
|
||||
<td>{{item.mapped_result_reference}}</td>
|
||||
</tr>
|
||||
</tbody>
|
||||
</table>
|
||||
</div>
|
||||
<!-- /.card-body -->
|
||||
<div class="card-footer">
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="col-12">
|
||||
<pagination-component :section="section" class="mb-5" ref="pagination"></pagination-component>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
files: {
|
||||
required: true
|
||||
},
|
||||
type: {
|
||||
type: String,
|
||||
required: true,
|
||||
},
|
||||
section:{
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
isLoading: false,
|
||||
importedDate: null,
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pendingQueue() {
|
||||
return this.$store.getters.isInCompleteQueue(this.section);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
pendingQueue(inComplete, oldValue){
|
||||
if(inComplete){
|
||||
this.importInvoice();
|
||||
}
|
||||
},
|
||||
},
|
||||
created(){
|
||||
this.appendComponentTitle();
|
||||
this.appendComponentTableHeader();
|
||||
this.$store.dispatch('updateListQueue', {'name': this.section});
|
||||
},
|
||||
methods: {
|
||||
appendComponentTitle() {
|
||||
this.componentTitle = this.section == 'importInvoiceMapping' ? 'Imported Invoices Mapped' : 'Imported Receipts Mapped';
|
||||
},
|
||||
appendComponentTableHeader() {
|
||||
if (this.section == 'importInvoiceMapping') {
|
||||
this.tableHeaders = ['No','Doc No','Date','Debtor Code','Debtor Name','Shipping Info','Net Total','Cancelled','Mapped Status','Mapped Reference No'];
|
||||
} else {
|
||||
this.tableHeaders = ['No','OR No','Date','Creditor Code','Creditor Name','Shipping Info','Net Total','Cancelled','Mapped Status','Mapped Reference No'];
|
||||
}
|
||||
},
|
||||
importInvoice(){
|
||||
this.isLoading = true;
|
||||
this.parameters = {
|
||||
files: this.files
|
||||
};
|
||||
this.submit(this.route('api.'+(this.section == 'importInvoiceMapping' ? 'import_invoices' : 'import_receipts')+'.upload'), 'post', this.section, true, false);
|
||||
},
|
||||
|
||||
successHandler(response){
|
||||
this.$store.dispatch('completeList', {'name': this.section, 'data': response.payload.data});
|
||||
this.importedDate = response.payload.importedDate;
|
||||
this.isLoading = false;
|
||||
},
|
||||
|
||||
downloadInvoiceMapped() {
|
||||
var arrDateTime = this.importedDate.split(" ");
|
||||
const fileName = this.section == 'importInvoiceMapping' ? 'InvoiceMapped' : 'ReceiptMapped';
|
||||
|
||||
window.open(this.route('importedInvoiceMapped.export')+'?date='+arrDateTime[0]+'&time='+arrDateTime[1]+'&fileName='+fileName, '_blank');
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
</script>
|
||||
+67
@@ -0,0 +1,67 @@
|
||||
<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-20 m-r-15 pointer bg-complete text-white" @click="getReportFilter()">Mapped Report</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="step == 1">
|
||||
<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-7">
|
||||
<div class="row">
|
||||
<div class="col">System</div>
|
||||
<div class="col">Type</div>
|
||||
<div class="col">Reference</div>
|
||||
<div class="col">Invoice Reference</div>
|
||||
<div class="col">Receipt Reference</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1">Amount</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<list-component ref="TransactionsMappedList" section="TransactionsMappedSection" :endpoint="route('api.accounting.bank.transaction')" :options="filter">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<statement-transaction-mapped-component :data="data" :section="section"></statement-transaction-mapped-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
step: 0,
|
||||
filter: {},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
getReportFilter() {
|
||||
this.filter = {min_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [2], statement_transaction_owner_invoice_or_receipt_ref_not_null: true, per_page: 100, order_by: {column: 'posting_date', DESC: true}};
|
||||
|
||||
this.step = 1
|
||||
}
|
||||
},
|
||||
}
|
||||
|
||||
</script>
|
||||
+12
-12
@@ -65,10 +65,12 @@
|
||||
<thead>
|
||||
<tr>
|
||||
<th>ID</th>
|
||||
<th>Date</th>
|
||||
<th>Posting Date</th>
|
||||
<th>Description 1</th>
|
||||
<th>Pay For</th>
|
||||
<th>System References</th>
|
||||
<th>Description 2</th>
|
||||
<th>Description 3</th>
|
||||
<th>Description 4</th>
|
||||
<th>Description 5</th>
|
||||
<th>Amount</th>
|
||||
<th>Action</th>
|
||||
</tr>
|
||||
@@ -76,10 +78,12 @@
|
||||
<tbody v-show="!isLoading">
|
||||
<tr v-for="item in $store.getters.getListData(section)" :key="item.id">
|
||||
<td>{{item.id}}</td>
|
||||
<td>{{item.date}}</td>
|
||||
<td>{{item.transaction_description_1 | truncate(30, '...')}}</td>
|
||||
<td>{{item.pay_for}}</td>
|
||||
<td>{{item.system_references}}</td>
|
||||
<td>{{item.posting_date}}</td>
|
||||
<td>{{item.transaction_description_1}}</td>
|
||||
<td>{{item.transaction_description_2}}</td>
|
||||
<td>{{item.transaction_description_3}}</td>
|
||||
<td>{{item.transaction_description_4}}</td>
|
||||
<td>{{item.transaction_description_5}}</td>
|
||||
<td>{{item.amount}}</td>
|
||||
<td>
|
||||
<a href="#">
|
||||
@@ -183,11 +187,7 @@ export default {
|
||||
},
|
||||
created(){
|
||||
this.setDecoratorDefault();
|
||||
if (this.statement === 0) {
|
||||
this.filters = { 'per_page': 10, order_by: {column: 'id', DESC: true} };
|
||||
} else {
|
||||
this.filters = { 'per_page': 10, order_by: {column: 'id', DESC: true}, 'has_account_statement_id': this.statement };
|
||||
}
|
||||
this.filters = { 'per_page': 10, order_by: {column: 'id', DESC: true} };
|
||||
this.$store.dispatch('updateListQueue', {'name': this.section, 'page': 1, 'filters': this.filters});
|
||||
},
|
||||
methods: {
|
||||
|
||||
+105
-17
@@ -55,7 +55,7 @@
|
||||
<div class="col"></div>
|
||||
<div class="col-auto pointer bold text-danger" @click="step=0">X</div>
|
||||
</div>
|
||||
<div class="row parentContainer" v-if="step > 0 && stage !== 4">
|
||||
<div class="row parentContainer" v-if="step > 0">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@@ -68,11 +68,38 @@
|
||||
class="text-center"
|
||||
:apiRoute="route('api.accounting.statement_transaction.owner.groupApprove')"
|
||||
apiMethod="post"
|
||||
:params="filter"
|
||||
:section="section"
|
||||
>
|
||||
</general-confirmation-form-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
|
||||
<!-- filter for Pending Export tab -->
|
||||
<div v-if="stage === 4">
|
||||
<div class="row pt-3 pb-3">
|
||||
<div class="col-5 col-md-3 ">
|
||||
<validation-wrapper-component :validator="$v.parameters.startDate">
|
||||
<label class="all-caps">Start Date</label>
|
||||
<date-picker-component :parameters="parameters" v-model.lazy="parameters.startDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-5 col-md-3 ">
|
||||
<validation-wrapper-component :validator="$v.parameters.endDate">
|
||||
<label class="all-caps">End Date</label>
|
||||
<date-picker-component :parameters="parameters" v-model.lazy="parameters.endDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-2 col-md-auto">
|
||||
<div class="btn btn-lg btn-primary fs-11 w-100 h-100 d-flex justify-content-center align-items-center" @click="startMapping(4)">
|
||||
<span>
|
||||
Search
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<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">
|
||||
@@ -86,19 +113,23 @@
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-1">Amount</div>
|
||||
<div class="col-1" v-if="stage === 4"></div>
|
||||
<div class="col-1" v-if="stage === 4">Select <input type="checkbox" v-model="selectAll">
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<list-component ref="bankTransactionsList" section="bankTransactionSection" :endpoint="route('api.accounting.bank.transaction')" :options="this.filter">
|
||||
|
||||
<list-component :key="stage" ref="bankTransactionsList" section="bankTransactionSection" :endpoint="route('api.accounting.bank.transaction')" :options="this.filter">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<statement-transaction-component :data="data" :section="section" :stage="stage"></statement-transaction-component>
|
||||
<statement-transaction-component :data="data" :section="section" :stage="stage" :selectAll="selectAll"></statement-transaction-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="stage === 4">
|
||||
<div class="row parentContainer" 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">
|
||||
@@ -122,7 +153,7 @@
|
||||
</file-input-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn btn-lg btn-primary m-t-20" @click="importInvoice">Import Invoices</div>
|
||||
<div class="btn btn-lg btn-primary m-t-20 requestModal" data-type="ModalImportInvoice" @click="importInvoice">Import Invoices</div>
|
||||
<!-- todo-new: delete later --><br><div class="btn btn-lg btn-primary m-t-20" @click="exportStage++">Nest Step</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
@@ -130,11 +161,19 @@
|
||||
<a href="https://docs.google.com/presentation/d/1XwKcdBCpHQSCQmsgnUHsypcqk5kdc8uZMqkjW9JXiw4/edit?usp=sharing" target="_blank">Learn How to do this step?</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="ModalImportInvoice">
|
||||
<imported-invoice-mapped-component section="importInvoiceMapping" v-if="mappedTrue" :files="files"></imported-invoice-mapped-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
</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 class="btn btn-lg btn-primary" @click="exportReceiptToAutoCount">Export Receipts To AutoCount</div>
|
||||
<!-- todo-new: delete later --><br><div class="btn btn-lg btn-primary m-t-20" @click="exportStage++">Nest Step</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
@@ -153,7 +192,7 @@
|
||||
</file-input-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="btn btn-lg btn-primary m-t-20" @click="importReceipts">Import Receipts</div>
|
||||
<div class="btn btn-lg btn-primary m-t-20 requestModal" data-type="ModalImportInvoice" @click="importReceipts">Import Receipts</div>
|
||||
<!-- todo-new: delete later --><br><div class="btn btn-lg btn-primary m-t-20" @click="exportStage++">Nest Step</div>
|
||||
<br>
|
||||
<div class="row">
|
||||
@@ -161,6 +200,13 @@
|
||||
<a href="https://docs.google.com/presentation/d/1xMiWjU1hqPaihMhbgflFSDsu1sC_0Lk7OFmwDaXVt-w/edit?usp=sharing" target="_blank">Learn How to do this step?</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="ModalImportInvoice">
|
||||
<imported-invoice-mapped-component section="importReceiptMapping" v-if="mappedTrue" :files="files"></imported-invoice-mapped-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row text-center m-t-50 m-b-50 p-t-50 p-b-50" v-show="exportStage === 4">
|
||||
@@ -182,6 +228,10 @@ export default {
|
||||
|
||||
data(){
|
||||
return {
|
||||
parameters: {
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
},
|
||||
type: null,
|
||||
stage: null,
|
||||
exportStage: 0,
|
||||
@@ -190,28 +240,57 @@ export default {
|
||||
files: [],
|
||||
parameters: {},
|
||||
section: 'bankTransactionSection',
|
||||
mappedTrue: false,
|
||||
selectAll: false,
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
parameters: {
|
||||
startDate: {
|
||||
required
|
||||
},
|
||||
endDate: {
|
||||
required
|
||||
},
|
||||
},
|
||||
files: {
|
||||
// required // todo-new: set required if is pdf section
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
importInvoice(){
|
||||
this.parameters = {
|
||||
files: this.files
|
||||
};
|
||||
this.submit(this.route('api.import_invoices.upload'), 'post', this.section, true, false);
|
||||
this.mappedTrue = true;
|
||||
},
|
||||
importReceipts(){
|
||||
this.parameters = {
|
||||
files: this.files
|
||||
};
|
||||
this.submit(this.route('api.import_receipts.upload'), 'post', this.section, true, false);
|
||||
this.mappedTrue = true;
|
||||
},
|
||||
exportInvoiceToAutoCount(){
|
||||
window.open(this.route('invoiceTransactions.export'), '_blank');
|
||||
const checkedStatementTransactions = this.getCheckedStatementOwners();
|
||||
|
||||
let route = this.route('invoiceTransactions.export')+'?filter='+JSON.stringify(this.filter);
|
||||
if (checkedStatementTransactions) {
|
||||
route += '&bankStatementTransactionId='+checkedStatementTransactions;
|
||||
}
|
||||
|
||||
window.open(route, '_blank');
|
||||
},
|
||||
exportReceiptToAutoCount(){
|
||||
const checkedStatementTransactions = this.getCheckedStatementOwners();
|
||||
|
||||
this.filter['statement_transaction_owner_type_in'] = [3,4,5,7,13,14];
|
||||
let route = this.route('receiptTransactions.export')+'?filter='+JSON.stringify(this.filter);
|
||||
if (checkedStatementTransactions) {
|
||||
route += '&bankStatementTransactionId='+checkedStatementTransactions;
|
||||
}
|
||||
|
||||
window.open(route, '_blank');
|
||||
},
|
||||
getCheckedStatementOwners() {
|
||||
let bankStatementTransactionId = [];
|
||||
$('.request_export_item:checked').each(function() {
|
||||
bankStatementTransactionId.push($(this).val());
|
||||
});
|
||||
return (bankStatementTransactionId.length > 0 ? JSON.stringify(bankStatementTransactionId) : null);
|
||||
},
|
||||
successHandler(){
|
||||
this.step += 1;
|
||||
@@ -233,10 +312,14 @@ export default {
|
||||
this.filter = {min_amount: 0, is_mapped: true, is_mapped_with_multiple: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [1], per_page: 100, order_by: {column: 'posting_date', DESC: true}}
|
||||
break;
|
||||
case 3:
|
||||
this.filter = {min_amount: 0, is_mapped: false, per_page: 100, order_by: {column: 'posting_date', DESC: true}}
|
||||
this.filter = {min_amount: 0, is_mapped_false_or_mapped_but_status_in: [4], per_page: 100, order_by: {column: 'posting_date', DESC: true}}
|
||||
break;
|
||||
case 4:
|
||||
this.filter = {min_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [1, 2], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}}
|
||||
|
||||
if (typeof this.parameters.startDate != 'undefined' && this.parameters.startDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_start: this.parameters.startDate}};
|
||||
|
||||
if (typeof this.parameters.endDate != 'undefined' && this.parameters.endDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_end:this.parameters.endDate}};
|
||||
break;
|
||||
}
|
||||
}
|
||||
@@ -254,6 +337,11 @@ export default {
|
||||
break;
|
||||
case 4:
|
||||
this.filter = {max_amount: 0, is_mapped: true, statement_transaction_owner_type_in: [3, 5], statement_transaction_owner_status_in: [2], per_page: 100, order_by: {column: 'posting_date', DESC: true}}
|
||||
|
||||
if (typeof this.parameters.startDate != 'undefined' && this.parameters.startDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_start: this.parameters.startDate}};
|
||||
|
||||
if (typeof this.parameters.endDate != 'undefined' && this.parameters.endDate != '') this.filter = {...this.filter, ...{statement_transaction_posting_end:this.parameters.endDate}};
|
||||
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
+1
-1
@@ -6,7 +6,7 @@
|
||||
<div class="col">
|
||||
<div class="row p-b-5 b-b b-grey m-b-10 m-l-0 m-r-0">
|
||||
<div class="col no-padding">
|
||||
<h6>Transaction History</h6>
|
||||
<h6>Account Statement - Transaction History</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="transaction">
|
||||
|
||||
+98
@@ -0,0 +1,98 @@
|
||||
<template>
|
||||
<div class="row m-b-15">
|
||||
<div class="col-12">
|
||||
<div class="row">
|
||||
<div class="col-12">
|
||||
<div class="row m-l-0 m-r-0">
|
||||
<div class="col mb-2 mb-md-0 p-l-3 p-r-3 p-md-0">
|
||||
<validation-wrapper-component selectable :validator="$v.parameters.supplier">
|
||||
<label>Supplier</label>
|
||||
<selectable-component :disableOnFetch="true" :endpoint="route('api.company.list') + '?filters=' + JSON.stringify({'business_type': 3, 'status_in': [1, 2, 0]})" section="exportSupplierFilterSection" valueColumn="id" :labelColumn="['name']" v-model="parameters.supplier"></selectable-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col mb-2 mb-md-0 p-l-3 p-r-3 p-md-0">
|
||||
<validation-wrapper-component :validator="$v.parameters.startDate">
|
||||
<label class="all-caps">Start Date</label>
|
||||
<date-picker-component :parameters="parameters" v-model.lazy="parameters.startDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col mb-2 mb-md-0 p-l-3 p-r-3 p-md-0">
|
||||
<validation-wrapper-component :validator="$v.parameters.endDate">
|
||||
<label class="all-caps">End Date</label>
|
||||
<date-picker-component :parameters="parameters" v-model.lazy="parameters.endDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-auto p-l-3 p-r-3 p-md-0">
|
||||
<div class="btn btn-lg btn-primary fs-11 w-100 h-100 d-flex justify-content-center align-items-center" @click="bulkDownloadWhiteForm()">
|
||||
<span>
|
||||
Export
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center justify-content-center bg-white p-t-50 p-b-50 p-l-15 p-r-15 margin-15" v-if="returnData">
|
||||
<div class="col-10">
|
||||
<div class="row align-items-center justify-content-center hint-text">
|
||||
<div class="col-4 hint-text"><img src="/images/not-found-illustration.png" class="w-100 hint-text" /></div>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<div class="col">
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<p class="all-caps no-margin fs-11" :class="[{'text-danger': returnData.status == 'Error'}]" style="letter-spacing: 2px;">{{ returnData.message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
import componentHandler from "../../../general/mixins/componentHandler";
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
returnData: null,
|
||||
parameters: {
|
||||
startDate: '',
|
||||
endDate: '',
|
||||
supplier: ''
|
||||
},
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
parameters: {
|
||||
supplier: {
|
||||
required
|
||||
},
|
||||
startDate: {
|
||||
required
|
||||
},
|
||||
endDate: {
|
||||
required
|
||||
},
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
bulkDownloadWhiteForm(){
|
||||
this.submit(this.route('api.suppliers.white_forms'), 'post', this.section, false, false);
|
||||
},
|
||||
successHandler(response) {
|
||||
this.isLoading = false;
|
||||
if (response.message) {
|
||||
this.returnData = response;
|
||||
} else {
|
||||
this.returnData = null;
|
||||
}
|
||||
},
|
||||
},
|
||||
mixins: [componentHandler]
|
||||
};
|
||||
</script>
|
||||
@@ -0,0 +1,121 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row">
|
||||
<div class="col-8 p-l-0">
|
||||
<small class="all-caps muted fs-10">Export Payment Transactions CSV</small>
|
||||
<download-billing-with-dates-component section="paymentsReportSection" ></download-billing-with-dates-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-8 p-l-0">
|
||||
<small class="all-caps muted fs-10">Download Zip White Form</small>
|
||||
<download-supplier-white-form-component section="paymentsReportSection" ></download-supplier-white-form-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6">
|
||||
<div class="row">
|
||||
<div class="col p-l-0">
|
||||
<small class="all-caps muted fs-10">Filter Supplier</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col padding-0">
|
||||
<validation-wrapper-component selectable :validator="$v.filterSupplier">
|
||||
<label>Supplier</label>
|
||||
<selectable-component :disableOnFetch="true" :endpoint="route('api.company.list') + '?filters=' + JSON.stringify({'business_type': 3, 'status_in': [1, 2, 0]})" section="supplierFilterSection" valueColumn="id" :labelColumn="['name']" v-model="filterSupplier"></selectable-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col-2 p-l-0">
|
||||
<button type="button" class="btn btn-lg btn-complete fs-11 h-100 d-flex justify-content-center align-items-center" @click="reset()">Reset</button>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col bg-white p-t-15 p-b-15">
|
||||
<div class="row no-margin">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="row m-b-15 p-b-10 b-b b-grey">
|
||||
<div class="col">
|
||||
<small class="all-caps muted fs-10">Complete Payments</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<list-component key="2" section="paymentVerificationSection" :endpoint="route('api.transaction.list')" :options="{'type': 1, 'status': 3, 'payment_method_not_in': [4]}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<payment-verification-component section="paymentVerificationSection" :data="data" :no_action="true"></payment-verification-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="row m-b-15 p-b-10 b-b b-grey">
|
||||
<div class="col">
|
||||
<small class="all-caps muted fs-10">Complete Currency Orders</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<list-component :key="currencyOrderKey" section="completeTransactionGroupsListSection" :options="{'per_page': 20, 'status': 3, ...this.filterSupplier && {'issuer_in': [this.filterSupplier]}}" :endpoint="route('api.transaction.group.list')">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<transaction-group-component section="transactionGroupsListSection" :data="data"></transaction-group-component>
|
||||
</template>
|
||||
</list-component>
|
||||
<!-- <list-component key="2" section="currencyOrdersListSection" :options="{'per_page': 20, 'document_type_in': ['CURRENCY_VENDOR_ORDER'], 'status': 2, 'with_company': true}" :endpoint="route('api.document.list')">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<currency-order-component section="currencyOrdersListSection" :data="data"></currency-order-component>
|
||||
</template>
|
||||
</list-component> -->
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="row m-b-15 p-b-10 b-b b-grey">
|
||||
<div class="col">
|
||||
<small class="all-caps muted fs-10">Open Currency Orders</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<list-component :key="currencyOrderKey" section="transactionGroupsListSection" :options="{'per_page': 20, 'status_in': [0, 1, 2], ...this.filterSupplier && {'issuer_in': [this.filterSupplier]}}" :endpoint="route('api.transaction.group.list')">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<transaction-group-component section="transactionGroupsListSection" :data="data"></transaction-group-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
|
||||
<script>
|
||||
export default {
|
||||
data(){
|
||||
return {
|
||||
filterSupplier: "",
|
||||
currencyOrderKey: 1,
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
filterSupplier: {}
|
||||
},
|
||||
watch: {
|
||||
filterSupplier() {
|
||||
this.currencyOrderKey += 1;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
reset() {
|
||||
this.filterSupplier = ""
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
File diff suppressed because one or more lines are too long
@@ -289,6 +289,22 @@
|
||||
<regenerate-booking-invoices-component :data="booking" :section="section" class="text-center"></regenerate-booking-invoices-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
<div class="row m-t-10" v-if="$store.getters.isSuperAdmin">
|
||||
<div class="col-sm col-md-auto">
|
||||
<div class="btn btn-sm btn block all-caps b-rad-none btn-danger pointer requestModal" data-type="deleteTransfer">Delete Transfer</div>
|
||||
</div>
|
||||
<modal-component class="animate__animated animate__fast animate__fadeIn" type="deleteTransfer">
|
||||
<general-confirmation-form-component
|
||||
contentText="Are you sure you want to delete this Order?"
|
||||
modalType="delete"
|
||||
class="text-center"
|
||||
:apiRoute="route('api.booking.payment.expire', booking.id)"
|
||||
apiMethod="post"
|
||||
:section="section"
|
||||
>
|
||||
</general-confirmation-form-component>
|
||||
</modal-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-sm-12 col-md-5 mt-3 mt-sm-0">
|
||||
<booking-payment-quotation-component :data="booking" :section="section"></booking-payment-quotation-component>
|
||||
|
||||
@@ -0,0 +1,104 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row m-b-5" @keyup.enter="submitSearch">
|
||||
<div class="col p-r-0">
|
||||
<validation-wrapper-component :validator="$v.parameters.marking">
|
||||
<label class="all-caps">Marking</label>
|
||||
<!-- <input type="text" class="form-control" v-model="parameters.marking" :class="[{ 'not-allowed': hasMarkingParameter }]" :disabled="hasMarkingParameter"> -->
|
||||
<input type="text" class="form-control" v-model="parameters.marking" :class="[{ 'not-allowed': hasMarking }]" :disabled="hasMarking">
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col p-r-0">
|
||||
<validation-wrapper-component :validator="$v.parameters.startDate">
|
||||
<label class="all-caps">Start Date</label>
|
||||
<date-picker-component v-model.lazy="parameters.startDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col p-r-0">
|
||||
<validation-wrapper-component :validator="$v.parameters.endDate">
|
||||
<label class="all-caps">End Date</label>
|
||||
<date-picker-component v-model.lazy="parameters.endDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col col-md-auto d-flex justify-content-center align-items-center">
|
||||
<button type="button" class="btn btn-lg btn-primary fs-11 w-100"
|
||||
@click="submitSearch()">Download</button>
|
||||
</div>
|
||||
</div>
|
||||
<loading-component style="height: 100px; top: 0;" key="1" color="success" v-show="isLoading"></loading-component>
|
||||
<div class="row align-items-center justify-content-center bg-white p-t-50 p-b-50 p-l-15 p-r-15 margin-15" v-if="!isLoading && returnData">
|
||||
<div class="col-10">
|
||||
<div class="row align-items-center justify-content-center hint-text">
|
||||
<div class="col-4 hint-text"><img src="/images/not-found-illustration.png" class="w-100 hint-text" /></div>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<div class="col">
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<p class="all-caps no-margin fs-11" :class="[{'text-danger': returnData.status == 'Error'}]" style="letter-spacing: 2px;">{{ returnData.message }}</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import { required } from "vuelidate/lib/validators";
|
||||
|
||||
export default {
|
||||
data() {
|
||||
return {
|
||||
key: 1,
|
||||
returnData: null,
|
||||
isLoading: false,
|
||||
hasMarking: false,
|
||||
parameters: {
|
||||
marking: null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
},
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
parameters: {
|
||||
marking: { required },
|
||||
startDate: { required },
|
||||
endDate: { required },
|
||||
}
|
||||
},
|
||||
created() {
|
||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||
if (urlSearchParams.has('marking')) {
|
||||
this.parameters.marking = urlSearchParams.get('marking');
|
||||
}
|
||||
this.hasMarkingParameter();
|
||||
},
|
||||
methods: {
|
||||
submitSearch() {
|
||||
this.isLoading = true;
|
||||
this.submit(this.route('api.customers.invoices'), 'post', this.section, false, false);
|
||||
},
|
||||
errorHandler(error) {
|
||||
this.isLoading = false;
|
||||
console.log(error);
|
||||
},
|
||||
successHandler(response) {
|
||||
this.isLoading = false;
|
||||
if (response.message) {
|
||||
this.returnData = response;
|
||||
} else {
|
||||
this.returnData = null;
|
||||
}
|
||||
},
|
||||
hasMarkingParameter() {
|
||||
const urlSearchParams = new URLSearchParams(window.location.search);
|
||||
this.hasMarking = urlSearchParams.has('marking');
|
||||
},
|
||||
|
||||
},
|
||||
}
|
||||
</script>
|
||||
@@ -99,6 +99,7 @@
|
||||
updateFilters(filters){
|
||||
this.filters = filters;
|
||||
this.setDecoratorDefault();
|
||||
this.$store.dispatch('updateListQueue', {'name': this.section, 'page': 1, 'filters': this.filters});
|
||||
this.submit(this.endpoint + '?page=1&filters=' + JSON.stringify(this.filters), 'get', this.section, false, false)
|
||||
},
|
||||
successHandler(response){
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
<div class="btn btn-sm btn-default btn-block bg-master-lighter" data-dismiss="modal">Cancel</div>
|
||||
</div>
|
||||
<div class="col p-l-5">
|
||||
<div class="btn btn-sm btn-block b-rad-none" :class="[{'btn-danger': modalType !== 'confirm'}, {'btn-success': modalType === 'confirm'}]" @click="submit(apiRoute, apiMethod, section, true, true)">{{ buttonText }}</div>
|
||||
<div class="btn btn-sm btn-block b-rad-none" :class="[{'btn-danger': modalType !== 'confirm'}, {'btn-success': modalType === 'confirm'}]" @click="submitForm()">{{ buttonText }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -32,6 +32,10 @@
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
params: {
|
||||
type: Array,
|
||||
required: false
|
||||
},
|
||||
modalType: {
|
||||
type: String,
|
||||
default: 'confirm'
|
||||
@@ -50,6 +54,10 @@
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
submitForm() {
|
||||
if (this.params) this.parameters = this.params;
|
||||
return this.submit(this.apiRoute, this.apiMethod, this.section, true, true);
|
||||
}
|
||||
},
|
||||
mixins: [componentHandler, ModalFormHandler]
|
||||
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<select class="form-control">
|
||||
<select class="form-control" :disabled="this.options.length === 0 && this.disableOnFetch">
|
||||
<option disabled></option>
|
||||
</select>
|
||||
</template>
|
||||
@@ -13,6 +13,10 @@
|
||||
},
|
||||
value: {
|
||||
required: false
|
||||
},
|
||||
disableOnFetch: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
mounted(){
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
<template>
|
||||
<select-component :options="$store.getters.getSelectableList(section)" :value="value" @input="(val) => {$emit('input', val)}"></select-component>
|
||||
<select-component :disableOnFetch="disableOnFetch" :options="$store.getters.getSelectableList(section)" :value="value" @input="(val) => {$emit('input', val)}"></select-component>
|
||||
</template>
|
||||
<script>
|
||||
|
||||
@@ -23,6 +23,10 @@
|
||||
valueColumn: {
|
||||
type: String,
|
||||
required: true
|
||||
},
|
||||
disableOnFetch: {
|
||||
type: Boolean,
|
||||
default: false
|
||||
}
|
||||
},
|
||||
created(){
|
||||
|
||||
@@ -0,0 +1,111 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row m-b-5" @keyup.enter="submitSearch">
|
||||
<div class="col p-r-0">
|
||||
<validation-wrapper-component :validator="$v.parameters.reference_no">
|
||||
<label class="all-caps">Booking Reference</label>
|
||||
<input type="text" class="form-control" v-model="parameters.reference_no">
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col p-r-0">
|
||||
<validation-wrapper-component :validator="$v.parameters.startDate">
|
||||
<label class="all-caps">Start Date</label>
|
||||
<date-picker-component v-model.lazy="parameters.startDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col p-r-0">
|
||||
<validation-wrapper-component :validator="$v.parameters.endDate">
|
||||
<label class="all-caps">End Date</label>
|
||||
<date-picker-component v-model.lazy="parameters.endDate"></date-picker-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
<div class="col col-md-auto d-flex justify-content-center align-items-center">
|
||||
<button type="button" class="btn btn-lg btn-primary fs-11 w-100" @click="submitSearch()">Search</button>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<div class="row padding-10">
|
||||
<div class="col-3 fs-10">Date</div>
|
||||
<div class="col fs-10">Description</div>
|
||||
<div class="col-2 fs-10 text-center">Incoming</div>
|
||||
<div class="col-2 fs-10 text-center">Outgoing</div>
|
||||
<div class="col-2 fs-10 text-right">Balance</div>
|
||||
</div>
|
||||
|
||||
<list-component :key="key" section="topUp" :endpoint="route('api.transaction.wallet.list')" :options="options">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<customer-wallet-transaction-component :data="data" :deciamls="deciamls"></customer-wallet-transaction-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
deciamls: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
showingTransactionCount: {
|
||||
required: true
|
||||
},
|
||||
wallet_id: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
key: 1,
|
||||
parameters: {
|
||||
reference_no: null,
|
||||
startDate: null,
|
||||
endDate: null,
|
||||
},
|
||||
options: {
|
||||
status_in: [2, 3],
|
||||
owner_type: 'App\\Models\\Wallet',
|
||||
owner_id: this.wallet_id,
|
||||
per_page: this.showingTransactionCount
|
||||
}
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
parameters: {
|
||||
reference_no: { },
|
||||
startDate: { },
|
||||
endDate: { },
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
showingTransactionCount() {
|
||||
this.options.per_page = this.showingTransactionCount;
|
||||
this.key ++;
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
submitSearch() {
|
||||
delete this.options.with_booking_marking_like;
|
||||
delete this.options.created_after_or_equal;
|
||||
delete this.options.created_before_or_equal;
|
||||
|
||||
if (this.parameters.reference_no) {
|
||||
this.options.with_booking_marking_like = this.parameters.reference_no
|
||||
}
|
||||
if (this.parameters.startDate) {
|
||||
this.options.created_after_or_equal = this.parameters.startDate
|
||||
}
|
||||
if (this.parameters.endDate) {
|
||||
this.options.created_before_or_equal = this.parameters.endDate
|
||||
}
|
||||
|
||||
this.key ++;
|
||||
},
|
||||
},
|
||||
}
|
||||
</script>
|
||||
-174
@@ -1,174 +0,0 @@
|
||||
<template>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<loading-component style="height: 200px; top: 0;" key="1" color="success"
|
||||
v-show="isLoading"></loading-component>
|
||||
<div class="row" v-if="company">
|
||||
<div class="col-8">
|
||||
<div class="row p-b-5 b-b b-grey m-b-10 m-l-0 m-r-0">
|
||||
<div class="col no-padding">
|
||||
<h6>Transaction History</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="company.wallet">
|
||||
<div class="col">
|
||||
<div class="row padding-10">
|
||||
<div class="col-3 fs-10">Date</div>
|
||||
<div class="col fs-10">Description</div>
|
||||
<div class="col-2 fs-10 text-center">Incoming</div>
|
||||
<div class="col-2 fs-10 text-center">Outgoing</div>
|
||||
<div class="col-2 fs-10 text-right">Balance</div>
|
||||
</div>
|
||||
|
||||
<div class="row bg-white padding-10 m-b-10 rounded"
|
||||
v-for="(item, index) in company.wallet.transactions" v-bind:key="item.id" :data="item">
|
||||
<div class="col-3 fs-12">{{ item.created_at }}</div>
|
||||
<div class="col fs-12">
|
||||
<span v-html="item.description"></span>
|
||||
<a target=”_blank” v-if="[9, 11].includes(item.type)"
|
||||
:href="route('transaction.credit_note.download', item.id)">
|
||||
<i class="fa fa-download fs-11 m-l-5 text-secondary hover-primary"></i>
|
||||
</a>
|
||||
</div>
|
||||
<div class="col-2 text-success text-center">
|
||||
{{ [5, 9].includes(parseFloat(item.type)) ? (Math.round((parseFloat(item.amount) + Number.EPSILON) * 100000) / 100000).toLocaleString('en-US', { minimumFractionDigits: 5, maximumFractionDigits: 5 }) : '' }}
|
||||
</div>
|
||||
<div class="col-2 text-danger text-center">
|
||||
{{ [1, 11].includes(parseFloat(item.type)) ? '- ' + (Math.round((parseFloat(item.amount) + Number.EPSILON) * 100000) / 100000).toLocaleString('en-US', { minimumFractionDigits: 5, maximumFractionDigits: 5 }) : '' }}
|
||||
</div>
|
||||
<div class="col-2 text-right">{{ remainingBalance(index) }}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row align-items-center justify-content-center p-t-50 p-b-50"
|
||||
v-if="!company.wallet || !company.wallet.transactions.length">
|
||||
<div class="col-10">
|
||||
<div class="row align-items-center justify-content-center hint-text">
|
||||
<div class="col-4 hint-text"><img src="/images/not-found-illustration.png"
|
||||
class="w-100 hint-text"></div>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<div class="col">
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<p class="all-caps no-margin fs-11" style="letter-spacing: 2px;">Nothing To Show
|
||||
Here</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-5 align-items-center justify-content-center">
|
||||
<div class="col">
|
||||
<small class="fs-9 muted all-caps font-lato" style="letter-spacing: 2px">There
|
||||
is no results found, Try adjusting your filters to find what you are looking
|
||||
for.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3 m-l-15">
|
||||
<wallet-component :data="company" :creditable=true></wallet-component>
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<div class="row m-b-10">
|
||||
<div class="col">
|
||||
<div class="font-head fs-10 all-caps">Top Up Records</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="company.wallet">
|
||||
<div class="col">
|
||||
<wallet-top-up-history-component v-for="item in company.wallet.top_up_records"
|
||||
v-bind:key="item.id" :data="item"></wallet-top-up-history-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center justify-content-center p-t-50 p-b-50"
|
||||
v-if="!company.wallet || !company.wallet.top_up_records.length">
|
||||
<div class="col-10">
|
||||
<div class="row align-items-center justify-content-center hint-text">
|
||||
<div class="col-4 hint-text"><img src="/images/not-found-illustration.png"
|
||||
class="w-100 hint-text"></div>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<div class="col">
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<p class="all-caps no-margin fs-11" style="letter-spacing: 2px;">Nothing
|
||||
To Show Here</p>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-5 align-items-center justify-content-center">
|
||||
<div class="col">
|
||||
<small class="fs-9 muted all-caps font-lato"
|
||||
style="letter-spacing: 2px">There is no results found, Try adjusting
|
||||
your filters to find what you are looking for.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
export default {
|
||||
props: {
|
||||
id: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data() {
|
||||
return {
|
||||
section: 'customerTransactionSection',
|
||||
isLoading: true,
|
||||
company: null,
|
||||
attention: false
|
||||
}
|
||||
},
|
||||
computed: {
|
||||
pendingQueue() {
|
||||
return this.$store.getters.isInCompleteQueue(this.section);
|
||||
}
|
||||
},
|
||||
watch: {
|
||||
pendingQueue(inComplete) {
|
||||
if (inComplete) {
|
||||
this.fetchCompany();
|
||||
}
|
||||
}
|
||||
},
|
||||
created() {
|
||||
this.$store.dispatch('updateListQueue', { 'name': this.section });
|
||||
},
|
||||
methods: {
|
||||
fetchCompany() {
|
||||
this.isLoading = true;
|
||||
this.submit(route('api.company.show', this.id), 'get', this.section, false, false)
|
||||
},
|
||||
remainingBalance(index) {
|
||||
let tempBalance = 0;
|
||||
|
||||
if (this.company.wallet) {
|
||||
let transactions = this.company.wallet.transactions.slice().reverse();
|
||||
transactions.slice(0, transactions.length - index).map(function (transaction) {
|
||||
[1, 11].includes(transaction.type) ? tempBalance -= (transaction.amount) : tempBalance += (transaction.amount);
|
||||
return tempBalance
|
||||
}, 0);
|
||||
}
|
||||
|
||||
return (Math.round((tempBalance + Number.EPSILON) * 100000) / 100000).toLocaleString('en-US', { minimumFractionDigits: 5, maximumFractionDigits: 5 });
|
||||
},
|
||||
successHandler(response) {
|
||||
this.isLoading = false;
|
||||
this.company = response.payload.data;
|
||||
}
|
||||
}
|
||||
}
|
||||
</script>
|
||||
+64
-87
@@ -2,84 +2,65 @@
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<loading-component style="height: 200px; top: 0;" key="1" color="success" v-show="isLoading"></loading-component>
|
||||
<div class="row" v-if="company">
|
||||
<div class="col-8">
|
||||
<div class="row p-b-5 b-b b-grey m-b-10 m-l-0 m-r-0">
|
||||
<div class="col no-padding">
|
||||
<h6>Transaction History</h6>
|
||||
<div v-if="!isLoading">
|
||||
<div class="row">
|
||||
<div class="col-8">
|
||||
<div class="row p-b-5 b-b b-grey m-b-10 m-l-0 m-r-0">
|
||||
<div class="col no-padding">
|
||||
<h6>Wallet Transaction History</h6>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-10 m-b-10">
|
||||
<div class="col">
|
||||
<div class="d-flex align-items-center h-100">
|
||||
<span class="btn btn-md fs-11 bg-primary text-white fs-12 m-r-5" :class="[{'bg-primary-darker': showingPreciseAmount}]" @click="showingPreciseAmount=!showingPreciseAmount">{{ showingPreciseAmount ? 'Showing Precise Wallet Transaction' : 'Show Precise Wallet Transaction'}}</span>
|
||||
<a v-if="company" :href="route('wallet.details-export', company.reference, showingPreciseAmount)" target="_blank" class="btn btn-md btn-primary fs-11"><i class="fa fa-download m-r-5"></i>{{ showingPreciseAmount ? 'Download Precise Transaction' : 'Download Transaction'}}</a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-2">
|
||||
<validation-wrapper-component selectable :validator="$v.showingTransactionCount">
|
||||
<label>Showing Rows</label>
|
||||
<select-component :options="[5, 10, 20, 30, 50]" v-model="showingTransactionCount"></select-component>
|
||||
</validation-wrapper-component>
|
||||
</div>
|
||||
</div>
|
||||
<div v-show="!showingPreciseAmount">
|
||||
<customer-transaction-component :deciamls="2" :wallet_id="wallet_id" :showingTransactionCount="showingTransactionCount"></customer-transaction-component>
|
||||
</div>
|
||||
<div v-show="showingPreciseAmount">
|
||||
<customer-transaction-component :deciamls="5" :wallet_id="wallet_id" :showingTransactionCount="showingTransactionCount"></customer-transaction-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="company.wallet">
|
||||
<div class="col">
|
||||
<div class="row padding-10">
|
||||
<div class="col-3 fs-10">Date</div>
|
||||
<div class="col fs-10">Description</div>
|
||||
<div class="col-2 fs-10 text-center">Incoming</div>
|
||||
<div class="col-2 fs-10 text-center">Outgoing</div>
|
||||
<div class="col-2 fs-10 text-right">Balance</div>
|
||||
</div>
|
||||
|
||||
<div class="row bg-white padding-10 m-b-10 rounded" v-for="(item, index) in company.wallet.transactions" v-bind:key="item.id" :data="item">
|
||||
<div class="col-3 fs-12">{{item.created_at}}</div>
|
||||
<div class="col fs-12"><span v-html="item.description"></span> <a target=”_blank” v-if="[9,11].includes(item.type) " :href="route('transaction.credit_note.download', item.id)"><i class="fa fa-download fs-11 m-l-5 text-secondary hover-primary"></i></a></div>
|
||||
<div class="col-2 text-success text-center">{{[5, 9].includes(parseFloat(item.type)) ? (Math.round((parseFloat(item.amount) + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : ''}}</div>
|
||||
<div class="col-2 text-danger text-center">{{[1, 11].includes(parseFloat(item.type)) ? '- ' + (Math.round((parseFloat(item.amount) + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",") : ''}}</div>
|
||||
<div class="col-2 text-right">{{remainingBalance(index)}}</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div class="row align-items-center justify-content-center p-t-50 p-b-50" v-if="!company.wallet || !company.wallet.transactions.length">
|
||||
<div class="col-10">
|
||||
<div class="row align-items-center justify-content-center hint-text">
|
||||
<div class="col-4 hint-text"><img src="/images/not-found-illustration.png" class="w-100 hint-text"></div>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<div class="col">
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<p class="all-caps no-margin fs-11" style="letter-spacing: 2px;">Nothing To Show Here</p>
|
||||
<div class="col-3 m-l-15">
|
||||
<wallet-component :data="company" :creditable=true></wallet-component>
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<div class="row m-b-10">
|
||||
<div class="col">
|
||||
<div class="font-head fs-10 all-caps">Top Up Records</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="company.wallet">
|
||||
<div class="col">
|
||||
<wallet-top-up-history-component v-for="item in company.wallet.top_up_records" v-bind:key="item.id" :data="item"></wallet-top-up-history-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center justify-content-center p-t-50 p-b-50" v-if="!company.wallet || !company.wallet.top_up_records.length">
|
||||
<div class="col-10">
|
||||
<div class="row align-items-center justify-content-center hint-text">
|
||||
<div class="col-4 hint-text"><img src="/images/not-found-illustration.png" class="w-100 hint-text"></div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-5 align-items-center justify-content-center">
|
||||
<div class="col">
|
||||
<small class="fs-9 muted all-caps font-lato" style="letter-spacing: 2px">There is no results found, Try adjusting your filters to find what you are looking for.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-3 m-l-15">
|
||||
<wallet-component :data="company" :creditable=true></wallet-component>
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<div class="row m-b-10">
|
||||
<div class="col">
|
||||
<div class="font-head fs-10 all-caps">Top Up Records</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row" v-if="company.wallet">
|
||||
<div class="col">
|
||||
<wallet-top-up-history-component v-for="item in company.wallet.top_up_records" v-bind:key="item.id" :data="item"></wallet-top-up-history-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row align-items-center justify-content-center p-t-50 p-b-50" v-if="!company.wallet || !company.wallet.top_up_records.length">
|
||||
<div class="col-10">
|
||||
<div class="row align-items-center justify-content-center hint-text">
|
||||
<div class="col-4 hint-text"><img src="/images/not-found-illustration.png" class="w-100 hint-text"></div>
|
||||
</div>
|
||||
<div class="row text-center">
|
||||
<div class="col">
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<p class="all-caps no-margin fs-11" style="letter-spacing: 2px;">Nothing To Show Here</p>
|
||||
<div class="row text-center">
|
||||
<div class="col">
|
||||
<div class="row m-t-20">
|
||||
<div class="col">
|
||||
<p class="all-caps no-margin fs-11" style="letter-spacing: 2px;">Nothing To Show Here</p>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-5 align-items-center justify-content-center">
|
||||
<div class="col">
|
||||
<small class="fs-9 muted all-caps font-lato" style="letter-spacing: 2px">There is no results found, Try adjusting your filters to find what you are looking for.</small>
|
||||
<div class="row m-t-5 align-items-center justify-content-center">
|
||||
<div class="col">
|
||||
<small class="fs-9 muted all-caps font-lato" style="letter-spacing: 2px">There is no results found, Try adjusting your filters to find what you are looking for.</small>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -99,6 +80,10 @@ export default {
|
||||
id: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
wallet_id: {
|
||||
type: Number,
|
||||
required: true
|
||||
}
|
||||
},
|
||||
data(){
|
||||
@@ -106,6 +91,8 @@ export default {
|
||||
section: 'customerTransactionSection',
|
||||
isLoading: true,
|
||||
company: null,
|
||||
showingPreciseAmount: false,
|
||||
showingTransactionCount: 10,
|
||||
attention: false
|
||||
}
|
||||
},
|
||||
@@ -121,6 +108,9 @@ export default {
|
||||
}
|
||||
}
|
||||
},
|
||||
validations: {
|
||||
showingTransactionCount: { },
|
||||
},
|
||||
created(){
|
||||
this.$store.dispatch('updateListQueue', {'name': this.section});
|
||||
},
|
||||
@@ -129,19 +119,6 @@ export default {
|
||||
this.isLoading = true;
|
||||
this.submit(route('api.company.show', this.id), 'get', this.section, false, false)
|
||||
},
|
||||
remainingBalance(index) {
|
||||
let tempBalance = 0;
|
||||
|
||||
if(this.company.wallet){
|
||||
let transactions = this.company.wallet.transactions.slice().reverse();
|
||||
transactions.slice(0, transactions.length - index).map(function(transaction) {
|
||||
[1, 11].includes(transaction.type) ? tempBalance -= (transaction.amount) : tempBalance += (transaction.amount);
|
||||
return tempBalance
|
||||
}, 0);
|
||||
}
|
||||
|
||||
return (Math.round((tempBalance + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
|
||||
},
|
||||
successHandler(response){
|
||||
this.isLoading = false;
|
||||
this.company = response.payload.data;
|
||||
|
||||
+35
@@ -0,0 +1,35 @@
|
||||
<template>
|
||||
<div class="row bg-white padding-10 m-b-10 rounded">
|
||||
<div class="col-3 fs-12">{{data.created_at}}</div>
|
||||
<div class="col fs-12"><span v-html="data.description"></span> <a target=”_blank” v-if="[9,11].includes(data.type) " :href="route('transaction.credit_note.download', data.id)"><i class="fa fa-download fs-11 m-l-5 text-secondary hover-primary"></i></a></div>
|
||||
<div class="col-2 text-success text-center">{{[5, 9].includes(parseFloat(data.type)) ? formatValue(data.amount) : ''}}</div>
|
||||
<div class="col-2 text-danger text-center">{{[1, 11].includes(parseFloat(data.type)) ? '- ' + (formatValue(data.amount)) : ''}}</div>
|
||||
<div class="col-2 text-right">{{formatValue(data.running_balance)}}</div>
|
||||
</div>
|
||||
</template>
|
||||
<script>
|
||||
import componentHandler from '../../../general/mixins/componentHandler';
|
||||
|
||||
export default {
|
||||
props: {
|
||||
data: {
|
||||
required: true,
|
||||
type: Object
|
||||
},
|
||||
deciamls: {
|
||||
type: Number,
|
||||
required: true
|
||||
},
|
||||
},
|
||||
methods: {
|
||||
formatValue(value) {
|
||||
if (this.deciamls != 2) {
|
||||
return (Math.round((parseFloat(value) + Number.EPSILON) * 100000) / 100000).toLocaleString('en-US', { minimumFractionDigits: 5, maximumFractionDigits: 5 });
|
||||
}
|
||||
|
||||
return (Math.round((parseFloat(value) + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")
|
||||
}
|
||||
},
|
||||
mixins: [componentHandler],
|
||||
}
|
||||
</script>
|
||||
@@ -35,7 +35,7 @@
|
||||
<div class="col-auto">
|
||||
<div class="btn btn-xs p-l-15 p-r-20 b-rad-none font-heading btn-rounded bg-white" @click="reload = true"><i class="fa fa-plus fs-8 m-r-5"></i> Reload</div>
|
||||
</div>
|
||||
<div class="col-auto p-l-0" v-if="!mini">
|
||||
<div class="col-auto p-l-0" v-if="!mini && data.wallet">
|
||||
<a class="text-white fs-10" :href="route('wallet.details', data.reference)" target="_blank">Transaction History<i class="fa fa-angle-right p-l-5"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
@@ -52,9 +52,18 @@
|
||||
<wallet-top-up-form-component :data="data" :amount="(!data.wallet ? amount : (Math.round((((amount - data.wallet.amount) < '0.00' ? '0.00' : (amount - data.wallet.amount)) + Number.EPSILON) * 100) / 100).toFixed(2))" :creditable="creditable"></wallet-top-up-form-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-20" v-if="$store.getters.isAdmin">
|
||||
<div class="row m-t-10" v-if="$store.getters.isAdmin">
|
||||
<div class="col">
|
||||
<a :href="route('account.statment', data.reference)">View Account Statement<i class="fa fa-angle-right p-l-5"></i></a>
|
||||
<div class="row m-t-10" v-if="$store.getters.isSuperAdmin">
|
||||
<div class="col">
|
||||
<a :href="route('account.statment', data.reference)">View Account Statement<i class="fa fa-angle-right p-l-5"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row m-t-10">
|
||||
<div class="col">
|
||||
<a :href="downloadInvoiceUrl()">Download All Invoices<i class="fa fa-angle-right p-l-5"></i></a>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
@@ -79,6 +88,11 @@
|
||||
default: false
|
||||
}
|
||||
},
|
||||
methods: {
|
||||
downloadInvoiceUrl(){
|
||||
return this.route('customers.invoices') + '?marking=' + this.data.reference;
|
||||
},
|
||||
},
|
||||
data(){
|
||||
return {
|
||||
reload: false,
|
||||
|
||||
+29
-9
@@ -13,19 +13,39 @@ export default {
|
||||
let statusCode = response.status,
|
||||
success = response.ok;
|
||||
|
||||
response.json().then(response => {
|
||||
if (response.headers.get("content-type") === "application/zip") {
|
||||
const fileName = response.headers.get('Content-Disposition').split('filename=')[1].replaceAll('"', '');
|
||||
|
||||
if(!success){
|
||||
this.openModal();
|
||||
errorNotification ? this.$store.dispatch('createNotification', {title: response.title, message: response.message, type: 'error'}): null;
|
||||
this.errorHandler(response, statusCode); return;
|
||||
}
|
||||
response.blob().then(response => {
|
||||
if (!success) {
|
||||
this.openModal();
|
||||
errorNotification ? this.$store.dispatch('createNotification', { title: response.title, message: response.message, type: 'error' }) : null;
|
||||
this.errorHandler(response, statusCode); return;
|
||||
}
|
||||
|
||||
successNotification ? this.$store.dispatch('createNotification', {title: response.title, message: response.message, type: 'success'}): null;
|
||||
this.successHandler(response)
|
||||
successNotification ? this.$store.dispatch('createNotification', { title: response.title, message: response.message, type: 'success' }) : null;
|
||||
|
||||
const link = document.createElement('a');
|
||||
link.href = window.URL.createObjectURL(response);
|
||||
link.download = fileName.trim();
|
||||
link.click();
|
||||
this.successHandler(response)
|
||||
});
|
||||
} else {
|
||||
response.json().then(response => {
|
||||
|
||||
if (!success) {
|
||||
this.openModal();
|
||||
errorNotification ? this.$store.dispatch('createNotification', { title: response.title, message: response.message, type: 'error' }) : null;
|
||||
this.errorHandler(response, statusCode); return;
|
||||
}
|
||||
|
||||
successNotification ? this.$store.dispatch('createNotification', { title: response.title, message: response.message, type: 'success' }) : null;
|
||||
this.successHandler(response)
|
||||
|
||||
|
||||
});
|
||||
});
|
||||
}
|
||||
}).catch((error) => {
|
||||
console.log(error);
|
||||
this.$store.dispatch('createNotification', {title: 'Unexpected Error', message: 'An unexpected error has occurred. Try again!', type: 'error'});
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
<div class="row justify-content-end">
|
||||
<div class="col">
|
||||
<div class="row fs-12 text-center">
|
||||
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton" tab-name="complete">
|
||||
<div class="col p-t-20 p-b-20 bg-master-lighter tabButton" tab-name="ReportMapped">
|
||||
<div class="row justify-content-center m-b-5">
|
||||
<div class="col-auto">
|
||||
<svg xmlns="http://www.w3.org/2000/svg" x="0px" y="0px"
|
||||
@@ -312,6 +312,14 @@
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
{{-- tab for report & Analysis --}}
|
||||
<div class="row tabsContainer tabContent" tab-name="ReportMapped">
|
||||
<div class="col">
|
||||
<report-transactions-mapped-component></report-transactions-mapped-component>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -0,0 +1,8 @@
|
||||
@extends('layouts.base_portal')
|
||||
@section('inner_content')
|
||||
<div class="row" v-if="$store.getters.isAdmin">
|
||||
<div class="col">
|
||||
<bulk-download-invoice-component section="BulkDownloadInvoiceComponent"></bulk-download-invoice-component>
|
||||
</div>
|
||||
</div>
|
||||
@endsection
|
||||
@@ -1,67 +1,4 @@
|
||||
@extends('layouts.base_portal')
|
||||
@section('inner_content')
|
||||
<div class="row">
|
||||
<div class="col-12 col-md-6 no-padding">
|
||||
<download-billing-with-dates-component section="paymentsReportSection" ></download-billing-with-dates-component>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col bg-white p-t-15 p-b-15">
|
||||
<div class="row no-margin">
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="row m-b-15 p-b-10 b-b b-grey">
|
||||
<div class="col">
|
||||
<small class="all-caps muted fs-10">Complete Payments</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<list-component key="2" section="paymentVerificationSection" :endpoint="route('api.transaction.list')" :options="{'type': 1, 'status': 3, 'payment_method_not_in': [4]}">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<payment-verification-component section="paymentVerificationSection" :data="data" :no_action="true"></payment-verification-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="row m-b-15 p-b-10 b-b b-grey">
|
||||
<div class="col">
|
||||
<small class="all-caps muted fs-10">Complete Currency Orders</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<list-component key="2" section="completeTransactionGroupsListSection" :options="{'per_page': 20, 'status': 3}" :endpoint="route('api.transaction.group.list')">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<transaction-group-component section="transactionGroupsListSection" :data="data"></transaction-group-component>
|
||||
</template>
|
||||
</list-component>
|
||||
{{--<list-component key="2" section="currencyOrdersListSection" :options="{'per_page': 20, 'document_type_in': ['CURRENCY_VENDOR_ORDER'], 'status': 2, 'with_company': true}" :endpoint="route('api.document.list')">--}}
|
||||
{{--<template slot="list" slot-scope="{data}">--}}
|
||||
{{--<currency-order-component section="currencyOrdersListSection" :data="data"></currency-order-component>--}}
|
||||
{{--</template>--}}
|
||||
{{--</list-component>--}}
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div class="col-12 col-md-4">
|
||||
<div class="row m-b-15 p-b-10 b-b b-grey">
|
||||
<div class="col">
|
||||
<small class="all-caps muted fs-10">Open Currency Orders</small>
|
||||
</div>
|
||||
</div>
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<list-component key="2" section="transactionGroupsListSection" :options="{'per_page': 20, 'status_in': [0, 1, 2]}" :endpoint="route('api.transaction.group.list')">
|
||||
<template slot="list" slot-scope="{data}">
|
||||
<transaction-group-component section="transactionGroupsListSection" :data="data"></transaction-group-component>
|
||||
</template>
|
||||
</list-component>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<payment-component></payment-component>
|
||||
@endsection
|
||||
@@ -69,109 +69,8 @@
|
||||
|
||||
<br>
|
||||
<br>
|
||||
<table class="line-table" style="overflow: wrap" autosize="1">
|
||||
<!-- Table Header -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%">No</th>
|
||||
<th class="stock-code" width="10%">Stock Code</th>
|
||||
<th class="description">Description</th>
|
||||
<th width="10%">Quantity</th>
|
||||
<th width="15%">Unit Price (RM)</th>
|
||||
<th width="10%">Total Amount<br>(RM)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@php
|
||||
$subtotal = "0";
|
||||
$voucherDiscount = $voucher_redemption ? bcmul((string)$voucher_redemption->value, "-1", 5) : "0";
|
||||
$displayedSubtotal = "0";
|
||||
$exactTotal = "0";
|
||||
@endphp
|
||||
@include('pages.pdfs.purchase_order_table')
|
||||
|
||||
@foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail)
|
||||
@php
|
||||
$exactUnitPrice = bcdiv($transaction_detail->price, $transaction->currency_rate, 5);
|
||||
$itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5);
|
||||
|
||||
// Round half to even for displayed item total
|
||||
$displayedItemTotal = round(bcmul($exactUnitPrice, $transaction_detail->quantity, 2), 2, PHP_ROUND_HALF_EVEN);
|
||||
|
||||
$displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2);
|
||||
$subtotal = bcadd($subtotal, $itemTotal, 5);
|
||||
$exactTotal = bcadd($exactTotal, $displayedItemTotal, 5);
|
||||
@endphp
|
||||
<tr>
|
||||
<td width="5%" class="center top">{{ $key + 1 }}</td>
|
||||
<td class="stock-code top" width="10%">{{ $transaction_detail->product_code }}</td>
|
||||
<td class="description">{{ $transaction_detail->product_name }}</td>
|
||||
<td width="10%" class="center top">{{ $transaction_detail->quantity }}</td>
|
||||
<td width="15%" class="center top">
|
||||
{{ number_format($exactUnitPrice, 2) }}
|
||||
</td>
|
||||
<td width="20%" class="right top">
|
||||
{{ number_format($itemTotal, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
<tfoot>
|
||||
@php
|
||||
$subtotalWithDiscount = bcsub($subtotal, $voucherDiscount, 5);
|
||||
@endphp
|
||||
<tr class="subtotal">
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Subtotal</td>
|
||||
<td class="right middle">{{ number_format($subtotal, 2) }}</td>
|
||||
</tr>
|
||||
<tr class="billingcharges">
|
||||
<td colspan="4"></td>
|
||||
<td class="right">Service Charges</td>
|
||||
<td class="right">{{ number_format($transaction->service_charge, 2) }}</td>
|
||||
</tr>
|
||||
|
||||
@if($voucher_redemption)
|
||||
<tr class="voucher">
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Voucher ({{ $voucher_redemption->voucher->code }})</td>
|
||||
<td class="right middle">-{{ number_format($voucherDiscount, 2) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if($transaction->tax > 0)
|
||||
<tr class="billingcharges">
|
||||
<td colspan="4"></td>
|
||||
<td class="right">Tax</td>
|
||||
<td class="right">{{ number_format($transaction->tax, 2) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
@php
|
||||
// Calculate the totals with 5 decimal places
|
||||
$expectedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5);
|
||||
|
||||
// Calculate the displayed totals with 2 decimal places
|
||||
$displayedTotal = bcadd(bcadd(bcadd($displayedSubtotal, $transaction->service_charge, 2), $transaction->tax, 2), $voucherDiscount, 2);
|
||||
|
||||
// Calculate the discrepancy
|
||||
$discrepancy = bcsub($expectedTotal, $displayedTotal, 5);
|
||||
|
||||
// Calculate the final total
|
||||
$total = bcadd($expectedTotal, $discrepancy, 5);
|
||||
@endphp
|
||||
<tr>
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Adjustment</td>
|
||||
<td class="right middle">{{number_format($discrepancy, 5)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Total</td>
|
||||
<td class="total right middle">
|
||||
{{ number_format($total, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<htmlpagefooter name="page-footer">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
|
||||
@@ -58,97 +58,8 @@
|
||||
<br>
|
||||
|
||||
<!-- Invoice Table -->
|
||||
<table class="line-table" style="overflow: wrap" autosize="1">
|
||||
<!-- Table Header -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%">No</th>
|
||||
<th class="stock-code" width="10%">Stock Code</th>
|
||||
<th class="description">Description</th>
|
||||
<th width="10%">Quantity</th>
|
||||
<th width="15%">Unit Price (RM)</th>
|
||||
<th width="10%">Total Amount<br>(RM)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@php
|
||||
$subtotal = "0";
|
||||
$voucherDiscount = $voucher_redemption ? bcmul((string)$voucher_redemption->value, "-1", 2) : "0";
|
||||
$displayedSubtotal = 0;
|
||||
@endphp
|
||||
@include('pages.pdfs.purchase_order_table')
|
||||
|
||||
@foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail)
|
||||
@php
|
||||
$exactUnitPrice = bcdiv($transaction_detail->price, $transaction->currency_rate, 7);
|
||||
$itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5);
|
||||
$displayedItemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 2);
|
||||
$displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2);
|
||||
$subtotal = bcadd($subtotal, $itemTotal, 5);
|
||||
@endphp
|
||||
<tr>
|
||||
<td width="5%" class="center top">{{ $key + 1 }}</td>
|
||||
<td class="stock-code top" width="10%">{{ $transaction_detail->product_code }}</td>
|
||||
<td class="description">{{ $transaction_detail->product_name }}</td>
|
||||
<td width="10%" class="center top">{{ $transaction_detail->quantity }}</td>
|
||||
<td width="15%" class="center top">
|
||||
{{ number_format($exactUnitPrice, 2) }}
|
||||
</td>
|
||||
<td width="20%" class="right top">
|
||||
{{ number_format($itemTotal, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
<tfoot>
|
||||
@php
|
||||
$subtotalWithDiscount = bcsub($subtotal, $voucherDiscount, 5);
|
||||
@endphp
|
||||
<tr class="subtotal">
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Subtotal</td>
|
||||
<td class="right middle">{{ number_format($subtotal, 2) }}</td>
|
||||
</tr>
|
||||
<tr class="billingcharges">
|
||||
<td colspan="4"></td>
|
||||
<td class="right">Service Charges</td>
|
||||
<td class="right">{{ number_format($transaction->service_charge, 2) }}</td>
|
||||
</tr>
|
||||
|
||||
@if($voucher_redemption)
|
||||
<tr class="voucher">
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Voucher ({{ $voucher_redemption->voucher->code }})</td>
|
||||
<td class="right middle">-{{ number_format($voucherDiscount, 2) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if($transaction->tax > 0)
|
||||
<tr class="billingcharges">
|
||||
<td colspan="4"></td>
|
||||
<td class="right">Tax</td>
|
||||
<td class="right">{{ number_format($transaction->tax, 2) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
@php
|
||||
$displayedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5);
|
||||
$expectedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5);
|
||||
$discrepancy = bcsub($displayedTotal, $expectedTotal, 5);
|
||||
$total = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5);
|
||||
@endphp
|
||||
<tr>
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Adjustment</td>
|
||||
<td class="right middle">{{number_format($discrepancy, 5)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Total</td>
|
||||
<td class="total right middle">
|
||||
{{ number_format($total, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<br>
|
||||
<div class="note">
|
||||
<strong>Note:</strong> All items purchased are subject to our Terms & Conditions. Please refer to our official website for more information.
|
||||
@@ -158,6 +69,6 @@
|
||||
Please transfer the payment to:<br>
|
||||
Bank: Maybank Berhad<br>
|
||||
Account Name: CIEF Worldwide Sdn Bhd<br>
|
||||
Account No: 564892103405<br>
|
||||
Account No: 568603010762<br>
|
||||
</div>
|
||||
@endsection
|
||||
|
||||
@@ -76,109 +76,8 @@
|
||||
|
||||
<br>
|
||||
|
||||
<table class="line-table" style="overflow: wrap" autosize="1">
|
||||
<!-- Table Header -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%">No</th>
|
||||
<th class="stock-code" width="10%">Stock Code</th>
|
||||
<th class="description">Description</th>
|
||||
<th width="10%">Quantity</th>
|
||||
<th width="15%">Unit Price (RM)</th>
|
||||
<th width="10%">Total Amount<br>(RM)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@php
|
||||
$subtotal = "0";
|
||||
$voucherDiscount = $voucher_redemption ? bcmul((string)$voucher_redemption->value, "-1", 5) : "0";
|
||||
$displayedSubtotal = "0";
|
||||
$exactTotal = "0";
|
||||
@endphp
|
||||
@include('pages.pdfs.purchase_order_table')
|
||||
|
||||
@foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail)
|
||||
@php
|
||||
$exactUnitPrice = bcdiv($transaction_detail->price, $transaction->currency_rate, 5);
|
||||
$itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5);
|
||||
|
||||
// Round half to even for displayed item total
|
||||
$displayedItemTotal = round(bcmul($exactUnitPrice, $transaction_detail->quantity, 2), 2, PHP_ROUND_HALF_EVEN);
|
||||
|
||||
$displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2);
|
||||
$subtotal = bcadd($subtotal, $itemTotal, 5);
|
||||
$exactTotal = bcadd($exactTotal, $displayedItemTotal, 5);
|
||||
@endphp
|
||||
<tr>
|
||||
<td width="5%" class="center top">{{ $key + 1 }}</td>
|
||||
<td class="stock-code top" width="10%">{{ $transaction_detail->product_code }}</td>
|
||||
<td class="description">{{ $transaction_detail->product_name }}</td>
|
||||
<td width="10%" class="center top">{{ $transaction_detail->quantity }}</td>
|
||||
<td width="15%" class="center top">
|
||||
{{ number_format($exactUnitPrice, 2) }}
|
||||
</td>
|
||||
<td width="20%" class="right top">
|
||||
{{ number_format($itemTotal, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
<tfoot>
|
||||
@php
|
||||
$subtotalWithDiscount = bcsub($subtotal, $voucherDiscount, 5);
|
||||
@endphp
|
||||
<tr class="subtotal">
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Subtotal</td>
|
||||
<td class="right middle">{{ number_format($subtotal, 2) }}</td>
|
||||
</tr>
|
||||
<tr class="billingcharges">
|
||||
<td colspan="4"></td>
|
||||
<td class="right">Service Charges</td>
|
||||
<td class="right">{{ number_format($transaction->service_charge, 2) }}</td>
|
||||
</tr>
|
||||
|
||||
@if($voucher_redemption)
|
||||
<tr class="voucher">
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Voucher ({{ $voucher_redemption->voucher->code }})</td>
|
||||
<td class="right middle">-{{ number_format($voucherDiscount, 2) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if($transaction->tax > 0)
|
||||
<tr class="billingcharges">
|
||||
<td colspan="4"></td>
|
||||
<td class="right">Tax</td>
|
||||
<td class="right">{{ number_format($transaction->tax, 2) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
@php
|
||||
// Calculate the totals with 5 decimal places
|
||||
$expectedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5);
|
||||
|
||||
// Calculate the displayed totals with 2 decimal places
|
||||
$displayedTotal = bcadd(bcadd(bcadd($displayedSubtotal, $transaction->service_charge, 2), $transaction->tax, 2), $voucherDiscount, 2);
|
||||
|
||||
// Calculate the discrepancy
|
||||
$discrepancy = bcsub($expectedTotal, $displayedTotal, 5);
|
||||
|
||||
// Calculate the final total
|
||||
$total = bcadd($expectedTotal, $discrepancy, 5);
|
||||
@endphp
|
||||
<tr>
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Adjustment</td>
|
||||
<td class="right middle">{{number_format($discrepancy, 5)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Total</td>
|
||||
<td class="total right middle">
|
||||
{{ number_format($total, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
<htmlpagefooter name="page-footer">
|
||||
<table width="100%">
|
||||
<tr>
|
||||
|
||||
@@ -0,0 +1,92 @@
|
||||
<table class="line-table" style="overflow: wrap" autosize="1">
|
||||
<!-- Table Header -->
|
||||
<thead>
|
||||
<tr>
|
||||
<th width="5%">No</th>
|
||||
<th class="stock-code" width="10%">Stock Code</th>
|
||||
<th class="description">Description</th>
|
||||
<th width="10%">Quantity</th>
|
||||
<th width="15%">Unit Price (RM)</th>
|
||||
<th width="10%">Total Amount<br>(RM)</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
@php
|
||||
$subtotal = "0";
|
||||
$voucherDiscount = $voucher_redemption ? bcmul((string)$voucher_redemption->value, "-1", 2) : "0";
|
||||
$displayedSubtotal = 0;
|
||||
@endphp
|
||||
|
||||
@foreach ($po_order_transaction->transactionDetails as $key => $transaction_detail)
|
||||
@php
|
||||
$exactUnitPrice = bcdiv($transaction_detail->price, $transaction->currency_rate, 7);
|
||||
$displayUnitPrice = round($exactUnitPrice, 2);
|
||||
$itemTotal = bcmul($exactUnitPrice, $transaction_detail->quantity, 5);
|
||||
$displayedItemTotal = round(bcmul($displayUnitPrice, $transaction_detail->quantity, 7), 2);
|
||||
$displayedSubtotal = bcadd($displayedSubtotal, $displayedItemTotal, 2);
|
||||
$subtotal = bcadd($subtotal, $itemTotal, 5);
|
||||
@endphp
|
||||
<tr>
|
||||
<td width="5%" class="center top">{{ $key + 1 }}</td>
|
||||
<td class="stock-code top" width="10%">{{ $transaction_detail->product_code }}</td>
|
||||
<td class="description">{{ $transaction_detail->product_name }}</td>
|
||||
<td width="10%" class="center top">{{ $transaction_detail->quantity }}</td>
|
||||
<td width="15%" class="center top">
|
||||
{{ number_format($displayUnitPrice, 2) }}
|
||||
</td>
|
||||
<td width="20%" class="right top">
|
||||
{{ number_format($displayedItemTotal, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
@endforeach
|
||||
</tbody>
|
||||
<tfoot>
|
||||
@php
|
||||
$subtotalWithDiscount = bcsub($subtotal, $voucherDiscount, 5);
|
||||
@endphp
|
||||
<tr class="subtotal">
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Subtotal</td>
|
||||
<td class="right middle">{{ number_format($displayedSubtotal, 2) }}</td>
|
||||
</tr>
|
||||
<tr class="billingcharges">
|
||||
<td colspan="4"></td>
|
||||
<td class="right">Service Charges</td>
|
||||
<td class="right">{{ number_format($transaction->service_charge, 2) }}</td>
|
||||
</tr>
|
||||
|
||||
@if($voucher_redemption)
|
||||
<tr class="voucher">
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Voucher ({{ $voucher_redemption->voucher->code }})</td>
|
||||
<td class="right middle">-{{ number_format($voucherDiscount, 2) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
|
||||
@if($transaction->tax > 0)
|
||||
<tr class="billingcharges">
|
||||
<td colspan="4"></td>
|
||||
<td class="right">Tax</td>
|
||||
<td class="right">{{ number_format($transaction->tax, 2) }}</td>
|
||||
</tr>
|
||||
@endif
|
||||
@php
|
||||
$displayedTotal = bcadd(bcadd(bcadd($displayedSubtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5);
|
||||
$expectedTotal = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5);
|
||||
$discrepancy = bcsub($expectedTotal, $displayedTotal, 5);
|
||||
$total = bcadd(bcadd(bcadd($subtotal, $transaction->service_charge, 5), $transaction->tax, 5), $voucherDiscount, 5);
|
||||
@endphp
|
||||
<tr>
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Adjustment</td>
|
||||
<td class="right middle">{{number_format($discrepancy, 5)}}</td>
|
||||
</tr>
|
||||
<tr>
|
||||
<td colspan="4"></td>
|
||||
<td class="right middle">Total</td>
|
||||
<td class="total right middle">
|
||||
{{ number_format($total, 2) }}
|
||||
</td>
|
||||
</tr>
|
||||
</tfoot>
|
||||
</table>
|
||||
@@ -1,5 +1,5 @@
|
||||
<div class="row">
|
||||
<div class="col">
|
||||
<customer-transaction-section-component :id="{{$id}}"></customer-transaction-section-component>
|
||||
<customer-transaction-section-component :id="{{$id}}" :wallet_id="{{$wallet_id}}"></customer-transaction-section-component>
|
||||
</div>
|
||||
</div>
|
||||
@@ -10,7 +10,7 @@ Route::group(['prefix' => 'accounting', 'as' => 'accounting.', 'namespace' => 'A
|
||||
Route::put('/details/update', 'BankStatementController@update')->name('details.update');
|
||||
});
|
||||
|
||||
Route::post('bankStatement/{id}/details/{status}', 'ApproveDuplicateBankStatementDetailsStatusController@update')->where('status', 'approve|reject')->name('bankStatement.details.status.update');
|
||||
Route::post('bankStatement/{id}/details/{status}', 'ApproveDuplicateBankStatementDetailsStatusController@update')->where('status', 'approve|reject|pending_verification')->name('bankStatement.details.status.update');
|
||||
|
||||
Route::group(['prefix' => 'statement_transaction', 'as' => 'statement_transaction.'], function () {
|
||||
Route::post('/owner/group-approve', 'GroupApproveStatementTransactionController@approve')->name('owner.groupApprove');
|
||||
|
||||
@@ -32,6 +32,8 @@ Route::group(['middleware' => 'api', 'prefix' => 'v1', 'as' => 'api.'], function
|
||||
Route::post('/import/upload-honey-trap', 'Imports\ImportHoneyTrapController@import')->name('honey_trap.upload');
|
||||
Route::post('/import/upload-import-invoices', 'Imports\ImportStatementInvoiceController@import')->name('import_invoices.upload');
|
||||
Route::post('/import/upload-import-receipt', 'Imports\ImportStatementReceiptsController@import')->name('import_receipts.upload');
|
||||
Route::post('/customers/invoices', 'Companies\BulkDownloadCustomerInvoicesController@download')->name('customers.invoices');
|
||||
Route::post('/supplier/white-form/bulk-download', 'Companies\BulkDownloadSupplierWhiteFormsController@download')->name('suppliers.white_forms');
|
||||
|
||||
require __DIR__ . '/company.php';
|
||||
|
||||
|
||||
@@ -19,6 +19,7 @@ Route::group(['prefix' => 'booking', 'as' => 'booking.', 'namespace' => 'Booking
|
||||
Route::post('create', 'CreateBookingPaymentController@create')->name('create');
|
||||
Route::post('{payment_id}/verification/create', 'CreatePaymentVerificationController@create')->name('verification.create');
|
||||
Route::put('/{payment_id}/approval/{status}', 'ApprovePaymentVerificationController@approve')->where('status', 'approve|reject')->name('approval');
|
||||
Route::post('delete', 'ExpireBookingPaymentController@expire')->name('expire');
|
||||
});
|
||||
|
||||
Route::group(['prefix' => '{id}/refund', 'as' => 'refund.'], function () {
|
||||
|
||||
@@ -16,6 +16,7 @@ Route::group(['prefix' => 'transactions', 'namespace' => 'Transactions', 'as' =>
|
||||
route::delete('{id}/bill/delete', 'DeletePaymentProofDocumentController@delete')->name('bill.delete');
|
||||
|
||||
Route::post('booking/{id}/details/update', 'CreatePurchaseOrderTransactionController@create')->name('po.create');
|
||||
Route::post('booking/{id}/details/import', 'ImportPurchaseOrderTransactionController@import')->name('po.import');
|
||||
|
||||
Route::get('bulk/po/{issuer_id}/{start_date}/{end_date}', 'CreateBulkPurchaseOrderTransactionController@create')->name('po.bulk.create');
|
||||
|
||||
|
||||
+11
-6
@@ -141,6 +141,10 @@ Route::get('/purchase_orders', function () {
|
||||
return view('pages.purchase_orders');
|
||||
})->name('purchase_orders');
|
||||
|
||||
Route::get('/customers/invoices', function () {
|
||||
return view('pages.customer_invoices_bulk_download');
|
||||
})->name('customers.invoices');
|
||||
|
||||
Route::get('/support', function () {
|
||||
return view('pages.customer_support', [
|
||||
'marking' => null,
|
||||
@@ -227,14 +231,13 @@ Route::get('/fix_bills', function () {
|
||||
})->name('products.random');
|
||||
|
||||
Route::get('/wallet/{marking}/details', function ($marking) {
|
||||
$id = \App\Models\Company::where('reference', '=', $marking)->first()->id;
|
||||
return view('pages.wallet.index', ['id' => $id]);
|
||||
$company = \App\Models\Company::where('reference', '=', $marking)->first();
|
||||
$id = $company->id;
|
||||
$wallet_id = $company->wallets()->first()->id;
|
||||
return view('pages.wallet.index', ['id' => $id, 'wallet_id' => $wallet_id]);
|
||||
})->name('wallet.details');
|
||||
|
||||
Route::get('/wallet/{marking}/details-precise', function ($marking) {
|
||||
$id = \App\Models\Company::where('reference', '=', $marking)->first()->id;
|
||||
return view('pages.wallet.precise', ['id' => $id]);
|
||||
})->name('wallet.details-precise');
|
||||
Route::get('/wallet/{marking}/{is_precise}/export', 'Exports\ExportCustomersWalletTransactionToExcelController@export')->name('wallet.details-export');
|
||||
|
||||
Route::get('/wallets', function () {
|
||||
return view('pages.wallet.wallets');
|
||||
@@ -258,6 +261,8 @@ Route::get('/export/payment-transactions/f614e339d7058904a831aad742e24d55', 'Exp
|
||||
Route::get('/export/wallet-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@walletTransactions')->name('walletTransactions.export');
|
||||
Route::get('/export/booking-transactions', 'Exports\ExportCustomersToExcelController@bookingTransactions')->name('export.transactions.booking');
|
||||
Route::get('/export/invoice-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@invoiceTransactions')->name('invoiceTransactions.export');
|
||||
Route::get('/export/receipt-transactions/f614e339d7058904a831aad742e24d55', 'Exports\ExportCustomersToExcelController@receiptTransactions')->name('receiptTransactions.export');
|
||||
Route::get('/export/imported-invoice-mapped', 'Exports\ExportCustomersToExcelController@importedInvoiceMapped')->name('importedInvoiceMapped.export');
|
||||
|
||||
Route::get('/products', function (\App\Classes\Modules\Exports\Services\ExportsProducts $exportsProducts) {
|
||||
$bookings = Booking::where(function($query){
|
||||
|
||||
Reference in New Issue
Block a user