Compare commits

...

96 Commits

Author SHA1 Message Date
jiasheng224 12710f614b fix migration for local 2024-04-22 18:41:04 +08:00
Omair Saleh dcec8cb33b update payment export itemization 2024-04-18 02:27:35 +08:00
Omair Saleh 75037f6192 update payment export itemization 2024-04-18 02:22:30 +08:00
Omair Saleh 675324081b update payment export itemization 2024-04-18 02:21:30 +08:00
Omair Saleh a959e83f5b update payment export itemization 2024-04-18 02:19:05 +08:00
Omair Saleh 2802e3c366 update payment export itemization 2024-04-18 02:17:43 +08:00
Omair Saleh aac2a0666a update payment export itemization 2024-04-18 02:16:13 +08:00
Omair Saleh 19efba4b89 update payment export itemization 2024-04-18 02:13:43 +08:00
Omair Saleh 7d70c800db update payment export itemization 2024-04-18 02:12:55 +08:00
Omair Saleh 863dc94dad Revert "Revert "Merge branch 'dillon/58-shipping-portal-sst' into 'master'""
This reverts commit a49920973e.
2024-04-18 02:09:16 +08:00
Omair Saleh 98e45e27e3 update payment export itemization 2024-04-18 02:04:56 +08:00
Omair Saleh df2916594b remove invoice date adjuster 2024-04-18 01:14:39 +08:00
Omair Saleh a49920973e Revert "Merge branch 'dillon/58-shipping-portal-sst' into 'master'"
This reverts commit 7cd376a9b5, reversing
changes made to 6176135f85.
2024-04-16 13:21:07 +08:00
Omair Saleh d129f8f6bd clear wrong date invoice from april to march 2024-04-16 13:17:23 +08:00
Omair Saleh 55a82e52a4 Merge remote-tracking branch 'origin/master' 2024-04-16 13:02:53 +08:00
Omair Saleh 1d4ac80b8f change sst invoice format 2024-04-16 13:02:40 +08:00
omair saleh 7cd376a9b5 Merge branch 'dillon/58-shipping-portal-sst' into 'master'
Dillon/58 shipping portal sst

See merge request CIEFWorldwideSdnBhd/shipping-portal!213
2024-04-16 04:51:39 +00:00
Omair Saleh c7e3091f9b change sst invoice format 2024-04-16 12:49:46 +08:00
Omair Saleh 28feba2ae9 change sst invoice format 2024-04-16 12:39:44 +08:00
edmondlang 6176135f85 fix qr api issue 2024-04-10 23:17:05 +08:00
edmondlang 5f529965da Merge branch 'qr-api-issue' of https://gitlab.com/CIEFWorldwideSdnBhd/shipping-portal 2024-04-10 22:27:29 +08:00
edmondlang 924f4f2ace fix qr api issue 2024-04-10 22:27:09 +08:00
edmondlang 6369282b38 update qr code config 2024-04-10 18:22:11 +08:00
jiasheng224 1991cf2c57 fix qr api issue 2024-04-09 17:42:10 +08:00
jiasheng224 5f5bbe0c8c update wallet balance when credit or debit to wallet balance 2024-04-09 16:58:12 +08:00
Dillon Ngo a809aec9a7 SST Impelemtation 2024-04-07 10:22:12 +08:00
Dillon Ngo 68ce8373e9 SST Impelemtation 2024-04-07 09:27:09 +08:00
Omair Saleh e5347f56b7 change bank in details 2024-04-04 08:22:47 +08:00
Omair Saleh 6673a44137 fix invoice date for april 2024-04-03 12:22:32 +08:00
Omair Saleh 4d3345f613 Merge remote-tracking branch 'origin/master' 2024-04-03 12:17:54 +08:00
Omair Saleh 60b8657773 fix invoice date for april 2024-04-03 12:17:40 +08:00
edmondlang 9f7a8d0d4b hide deletePaidGroupTransaction 2024-03-31 23:12:38 +08:00
edmondlang a87ab6c27f logging delete paid group transaction 2024-03-31 21:41:42 +08:00
edmondlang 462a4776cd delete paid group transaction 2024-03-31 17:36:12 +08:00
edmondlang 7e029c5610 delete paid group transaction 2024-03-30 00:49:55 +08:00
edmondlang 0719285286 show all extra payments from customer 2024-03-29 00:59:30 +08:00
edmondlang 64400d1524 fix ExportsCustomersWalletTransactionHistory 2024-03-29 00:06:22 +08:00
edmondlang be0279f56b fix ExportsCustomersWalletTransactionHistory 2024-03-29 00:02:13 +08:00
Dillon Ngo e15170bc7f Merge branch 'dillon/46.9-warehouse-storage-charges-fixes' into 'master'
Multiple fixes related to storage invoices

See merge request CIEFWorldwideSdnBhd/shipping-portal!212
2024-03-26 00:44:33 +00:00
Dillon Ngo 59f527aee7 Enable back manual payment that was temporary disable at order page for invoices with storage fee 2024-03-26 08:10:34 +08:00
Dillon Ngo d7aa248972 Merge branch 'dillon/55-billplz-fix' into 'master'
Update info log location for vue polling related stuff + perfexcrm integration

See merge request CIEFWorldwideSdnBhd/shipping-portal!211
2024-03-18 12:17:11 +00:00
Dillon Ngo 8e4ff6093e Update info log location for VuePolling JobResourceNotFoundException and PerfexCRM 2024-03-18 14:06:30 +08:00
Dillon Ngo 584169e173 Update info log location for VuePolling JobResourceNotFoundException and PerfexCRM 2024-03-18 13:54:09 +08:00
Dillon Ngo 1679d1ecf4 Fix a problem of unsuccessful payment when shipping invoice is paid first before storage invoice appear 2024-03-16 15:49:02 +08:00
Dillon Ngo 7ca48e9638 Fix a problem in info display inaccurate in payment history for manual payment 2024-03-16 15:17:28 +08:00
Dillon Ngo 14278a888a Merge branch 'dillon/55-billplz-fix' into 'master'
Long term solution to prevent customer making payment to a shipping invoice...

See merge request CIEFWorldwideSdnBhd/shipping-portal!210
2024-03-16 05:52:58 +00:00
Dillon Ngo 5de2554d63 Fix a problem with storage invoice checking when a payment related transaction is deleted at order page 2024-03-15 03:33:58 +08:00
edmondlang 033a835fce update SendPermitsReminderEmails logging 2024-03-14 12:48:25 +08:00
edmondlang 66ddb5da23 update send permits reminder 2024-03-14 12:46:47 +08:00
Dillon Ngo 65782ebf8a Long term solution to prevent customer making payment to a shipping invoice when there is a ongoing dispute 2024-03-14 12:43:58 +08:00
Dillon Ngo 96a089df16 Long term solution to prevent customer making payment to a shipping invoice when there is a ongoing dispute 2024-03-14 12:32:03 +08:00
edmondlang f95545a985 update container remark in order page 2024-03-13 00:20:39 +08:00
edmondlang 9e8685bd02 update container remark in order page 2024-03-13 00:02:52 +08:00
edmondlang 1224735ba8 Merge branch 'master' of https://gitlab.com/CIEFWorldwideSdnBhd/shipping-portal 2024-03-12 23:52:22 +08:00
edmondlang 11e2390059 update container and container remarks 2024-03-12 23:52:07 +08:00
Dillon Ngo c280da36d7 Merge branch 'dillon/55-billplz-fix' into 'master'
Fix a problem reported by Yien where order shipping invoice pending payment despite payment made

See merge request CIEFWorldwideSdnBhd/shipping-portal!209
2024-03-12 06:32:13 +00:00
Dillon Ngo 27529e90ca Fix a problem reported by Yien where order shipping invoice pending payment despite payment made 2024-03-12 14:20:19 +08:00
Dillon Ngo 2e9b0f918c Merge branch 'dillon/46.8-warehouse-storage-charges-fixes' into 'master'
Change log location, 404 page

See merge request CIEFWorldwideSdnBhd/shipping-portal!208
2024-03-09 13:26:32 +00:00
Dillon Ngo 5565d0b39b Update log location JobResourceNotFoundException 2024-03-09 21:17:49 +08:00
Dillon Ngo f1b8c6a556 When a pending verification group payment is deleted, do not display the group with no payment transaction(group payment) 2024-03-09 02:20:34 +08:00
Dillon Ngo 6d210d3713 Fix a problem with deleting a pending verification group payment at order page 2024-03-09 02:16:32 +08:00
Dillon Ngo 5dd2df02fd Hide 'Make Payment' button when there is a group payment pending verification from Admin 2024-03-09 01:22:13 +08:00
Dillon Ngo b207b11336 Fix missing group payment info on order page 2024-03-08 23:53:54 +08:00
Dillon Ngo ffd95ee1cc Fix missing group payment info on order page 2024-03-08 23:31:37 +08:00
Dillon Ngo 73b3995367 Merge branch 'dillon/46.9-warehouse-storage-charges-fixes' into 'master'
Temporary disable manual payment at order page for invoices with storage fee

See merge request CIEFWorldwideSdnBhd/shipping-portal!207
2024-03-08 13:12:33 +00:00
Dillon Ngo 45a2544b9d Temporary disable manual payment at order page for invoices with storage fee 2024-03-08 20:43:38 +08:00
Dillon Ngo 252636a7df Fix 404 exception caught at production laravel logs 2024-03-08 08:46:05 +08:00
Dillon Ngo 3e679fef23 Merge branch 'dillon/46.8-warehouse-storage-charges-fixes' into 'master'
UI Update (Payment and Billing 2 page) on Admin view to see shipping invoices...

See merge request CIEFWorldwideSdnBhd/shipping-portal!206
2024-03-03 11:16:07 +00:00
Dillon Ngo 758498f486 Fix a duplication problem in Pending Payment listing as a result of storage invoices 2024-03-02 14:09:06 +08:00
Dillon Ngo b55e32aece Fix missing container info at admin payment and billing page 2024-03-02 13:26:46 +08:00
Dillon Ngo 00bf7c0cf4 Fix when customer isCreditTerm is updated, waive storage invoices instead of deleting it 2024-03-01 11:47:21 +08:00
edmondlang 24a4d269b3 add edmond in the permits reminder email 2024-03-01 11:27:46 +08:00
Dillon Ngo f191979a53 Hide 'Your Payment Proof' at the order page when does not need to appear 2024-02-29 22:28:18 +08:00
Dillon Ngo c9998029b0 Fix a non functioning group payment delete at order page meant for shipping invoice with storage invoice 2024-02-29 21:10:37 +08:00
Dillon Ngo a442c78156 Refresh page after a payment transaction is suspended/deleted 2024-02-29 17:19:17 +08:00
Dillon Ngo 03c5ced77b Remove code no longer necessary - isBackDoorCheck flag 2024-02-29 16:32:37 +08:00
Dillon Ngo 5c6418cb1f When customer isCreditTerm status is updated to true, all existing storage invoices that is not paid but approve will be deleted 2024-02-29 16:30:57 +08:00
edmondlang 5e636862bb check if the address district name is null 2024-02-27 21:31:14 +08:00
Dillon Ngo e97cbfa618 Fix a problem with missing paid storage invoice when customer credit term status is updated 2024-02-26 16:36:43 +08:00
Dillon Ngo a448172521 UI Update (Payment and Billing 2 page) on Admin view to see shipping invoices with storage invoices on Pending Payment tab and Paid Invoice tab 2024-02-26 16:35:17 +08:00
Dillon Ngo 72ac055ec5 Merge branch 'dillon/46.6-warehouse-storage-charges-fixes' into 'master'
UI Update (Payment and Billing page) on Admin view to see shipping invoices...

See merge request CIEFWorldwideSdnBhd/shipping-portal!205
2024-02-25 07:44:39 +00:00
Dillon Ngo 09383a45a6 UI Update (Payment and Billing page) on Admin view to see shipping invoices with storage invoices on Pending Payment tab and Paid Invoice tab 2024-02-25 15:44:03 +08:00
Dillon Ngo bb1540116c Merge branch 'dillon/46.6-warehouse-storage-charges-fixes' into 'master'
UI Update (Payment and Billing page) on Admin view to see shipping invoices...

See merge request CIEFWorldwideSdnBhd/shipping-portal!204
2024-02-25 07:28:15 +00:00
Dillon Ngo 141062a7bf Fix storage invoice not allow to be regenerated if not yet pay 2024-02-25 15:21:04 +08:00
Dillon Ngo 4179706e04 UI Update (Payment and Billing page) on Admin view to see shipping invoices with storage invoices on Pending Payment tab and Paid Invoice tab 2024-02-25 14:26:54 +08:00
Dillon Ngo eaa21beb83 UI Update (Payment and Billing page) on Admin view to see shipping invoices with storage invoices on Pending Payment tab and Paid Invoice tab 2024-02-25 14:04:19 +08:00
Dillon Ngo 1acc02eb93 UI Update (Payment and Billing page) on Admin view to see shipping invoices with storage invoices on Pending Payment tab and Paid Invoice tab 2024-02-25 13:52:22 +08:00
Dillon Ngo 1f2959a5d2 Merge branch 'dillon/46.7-warehouse-storage-charges-fixes' into dillon/46.6-warehouse-storage-charges-fixes 2024-02-25 13:15:49 +08:00
Dillon Ngo 9b7b7068e1 Merge branch 'dillon/46.5-warehouse-storage-charges-fixes' into dillon/46.6-warehouse-storage-charges-fixes 2024-02-25 13:15:35 +08:00
Dillon Ngo 41e1c346f6 Rename a component 2024-02-25 13:13:09 +08:00
Dillon Ngo 74e9b23f91 Merge branch 'dillon/46.7-warehouse-storage-charges-fixes' into 'master'
Create a regenerate storage invoice feature to debug problem in reading and...

See merge request CIEFWorldwideSdnBhd/shipping-portal!203
2024-02-24 03:49:50 +00:00
Dillon Ngo 1e876dd103 Merge branch 'dillon/46.7-warehouse-storage-charges-fixes' into 'master'
Create a regenerate storage invoice feature to debug problem in reading and...

See merge request CIEFWorldwideSdnBhd/shipping-portal!202
2024-02-24 03:20:17 +00:00
Dillon Ngo 3d79d0f5e5 Merge branch 'dillon/46.5-warehouse-storage-charges-fixes' into 'master'
User interface to allow admin to update company whether is a credit term...

See merge request CIEFWorldwideSdnBhd/shipping-portal!201
2024-02-24 03:17:12 +00:00
Dillon Ngo b66dfa8649 Implement authorization module for update customer credit term status 2024-02-24 10:08:24 +08:00
Dillon Ngo 2689296a2c Implement authorization module for update customer credit term status 2024-02-23 11:09:30 +08:00
Dillon Ngo 62191c2711 Undo a changes made on previous commit 2024-02-23 10:49:09 +08:00
114 changed files with 2614 additions and 300 deletions
+4
View File
@@ -59,3 +59,7 @@ YD_API_CODE=''
PERFEXCRM_BASE_URL=""
PERFEXCRM_API_KEY=""
PERFEXCRM_IS_ENABLED="false"
STORAGE_FEE_LAUNCH_DATE="2023-12-11 00:00:00"
SST_START_DATE="2024-04-01 00:00:00"
@@ -65,7 +65,7 @@ abstract class AbstractControllerLogic
} catch (ErrorException|GeneralExceptions|TypeError $exception){
if ($exception instanceof JobResourceNotFoundException) {
Log::error(sprintf(
Log::channel('vue_polling')->info(sprintf(
"Uncaught exception '%s' with message '%s' in %s:%d",
get_class($exception),
$exception->getMessage(),
@@ -0,0 +1,32 @@
<?php
namespace App\Classes\General\Eloquent\Filters;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\SegmentConstants;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\PackingList;
use Illuminate\Database\Eloquent\Builder;
use Illuminate\Support\Facades\DB;
class PackingListLimitOneByTypeOrderedByInvoiceDate implements Filter
{
/**
* @param Builder $builder
* @param $value
* @return Builder|mixed
*/
public static function apply(Builder $builder, $value)
{
return $builder->select('packing_lists.*')->join('transactions', function($join){
$join->on('transactions.owner_id', '=', 'packing_lists.id');
$join->where('transactions.owner_type', '=', PackingList::class);
$join->where('transactions.status', '=', ApprovalStatus::APPROVED);
$join->whereRaw('(transactions.type <> 16 OR transactions.id = (
SELECT id FROM transactions WHERE owner_id = packing_lists.id AND type = 16 LIMIT 1
))');
})->orderBy('transactions.updated_at', 'DESC');
}
}
+2 -2
View File
@@ -47,7 +47,7 @@ class UpdatePerfexCRMInvoice implements ShouldQueue
$invoiceId = 0;
$invoiceStatus = 0;
$invoice = (App()->make(FetchesPerfexCRMInvoice::class))->execute($customer->userid,"INV-", $transaction->owner->bill_no);
Log::error('UpdatePerfexCRMInvoice debug bill_no: ' . $transaction->owner->bill_no . ', Project Id: ' . $this->updatePerfexCRMInvoiceObject->getProjectId());
Log::channel('perfex_crm')->info('UpdatePerfexCRMInvoice debug bill_no: ' . $transaction->owner->bill_no . ', Project Id: ' . $this->updatePerfexCRMInvoiceObject->getProjectId());
if(is_null($invoice)){
$result = (App()->make(CreatePerfexCRMInvoiceProcessor::class))->execute($transaction->owner, $this->updatePerfexCRMInvoiceObject->getIsPaid());
@@ -55,7 +55,7 @@ class UpdatePerfexCRMInvoice implements ShouldQueue
$invoiceId = $result->payload['id'];
} else {
// Log::error(json_encode('UpdatePerfexCRMInvoice CreatePerfexCRMInvoiceProcessor failed'));
Helper::debugLogger('UpdatePerfexCRMInvoice CreatePerfexCRMInvoiceProcessor failed');
Log::channel('perfex_crm')->info('UpdatePerfexCRMInvoice CreatePerfexCRMInvoiceProcessor failed');
}
}
else{
@@ -145,7 +145,7 @@ class CallbackBillplzLogic
$pL = $invoice->owner;
$order = $pL->owner;
if($order){
$this->storageInvoiceTransactionProcessor->executeOrder($order, false); //original was set true here so that no group is soft deleted or billplz bill got deleted
$this->storageInvoiceTransactionProcessor->executeOrder($order);
}
}
}
@@ -80,12 +80,13 @@ class CallbackBillplzProcessor
if ($group) {
foreach ($group->groupTransactions as $groupTransaction) {
$invoice = $groupTransaction->transaction;
if($invoice->status !== ApprovalStatus::COMPLETED){
$paymentTransaction = $this->createPaymentTransactionProcessor->execute($invoice, PaymentMethodType::WALLET, null, false);
$paymentTransaction = $this->createPaymentTransactionProcessor->execute($invoice, PaymentMethodType::WALLET, null, false);
if($paymentTransaction && $paymentTransaction->status == ApprovalStatus::APPROVED){
$pL = $invoice->owner;
$this->releaseGoodsToCustomerProcessor->execute($pL, $invoice);
if($paymentTransaction && $paymentTransaction->status == ApprovalStatus::APPROVED){
$pL = $invoice->owner;
$this->releaseGoodsToCustomerProcessor->execute($pL, $invoice);
}
}
}
@@ -111,7 +112,9 @@ class CallbackBillplzProcessor
foreach ($group->groupTransactions as $groupTransaction) {
$invoice = $groupTransaction->transaction;
$totalAmountToBePaid += $invoice->amount;
if($invoice->status !== ApprovalStatus::COMPLETED){
$totalAmountToBePaid += $invoice->amount;
}
}
if(($totalAmountToBePaid - $actualAmountPaid) < 0.01){
@@ -6,6 +6,12 @@ namespace App\Classes\Modules\Companies\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Companies\Services\FetchesCompany;
use App\Classes\Modules\Companies\Services\UpdatesCompanyModuleIsCreditTerm;
use App\Classes\Modules\Companies\Standards\Rules\CanUpdateCompanyModule;
use App\Classes\Modules\Transactions\Services\ListsTransactions;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionIsWaived;
use App\Classes\Modules\Transactions\Processors\CheckStorageInvoiceTransactionProcessor;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Order;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
@@ -30,16 +36,37 @@ class UpdateCompanyCreditTermStatusLogic extends AbstractControllerLogic
/** @var UpdatesCompanyModuleIsCreditTerm */
private $updatesCompanyModuleIsCreditTerm;
/** @var CanUpdateCompanyModule */
private $canUpdateCompanyModule;
/** @var ListsTransactions */
private $listsTransactions;
/** @var UpdatesTransactionIsWaived */
private $updatesTransactionIsWaived;
/** @var CheckStorageInvoiceTransactionProcessor */
private $storageInvoiceTransactionProcessor;
/**
* UpdateCompanyCreditTermStatusLogic constructor.
* @param FetchesCompany $fetchesCompany
* @param UpdatesCompanyModuleIsCreditTerm $updatesCompanyModuleIsCreditTerm
* @param CanUpdateCompanyModule $canUpdateCompanyModule
* @param UpdatesTransactionIsWaived $updatesTransactionIsWaived
* @param ListsTransactions $listsTransactions
* @param CheckStorageInvoiceTransactionProcessor $storageInvoiceTransactionProcessor
*/
public function __construct(FetchesCompany $fetchesCompany, UpdatesCompanyModuleIsCreditTerm $updatesCompanyModuleIsCreditTerm)
public function __construct(FetchesCompany $fetchesCompany, UpdatesCompanyModuleIsCreditTerm $updatesCompanyModuleIsCreditTerm, CanUpdateCompanyModule $canUpdateCompanyModule, UpdatesTransactionIsWaived $updatesTransactionIsWaived, ListsTransactions $listsTransactions, CheckStorageInvoiceTransactionProcessor $storageInvoiceTransactionProcessor)
{
$this->fetchesCompany = $fetchesCompany;
$this->updatesCompanyModuleIsCreditTerm = $updatesCompanyModuleIsCreditTerm;
$this->canUpdateCompanyModule = $canUpdateCompanyModule;
$this->listsTransactions = $listsTransactions;
$this->updatesTransactionIsWaived = $updatesTransactionIsWaived;
$this->storageInvoiceTransactionProcessor = $storageInvoiceTransactionProcessor;
}
/**
@@ -51,10 +78,11 @@ class UpdateCompanyCreditTermStatusLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
$this->canUpdateCompanyModule->passes();
$company = $this->fetchesCompany->execute(['id' => $request->route('id')]);
$isCreditTerm = $company->companyModules()->first()->connections()->first()->is_credit_term;
$companyModule = $company->companyModules()->first();
$isCreditTerm = $companyModule->connections()->first()->is_credit_term;
if ($isCreditTerm == 1) {
$isCreditTerm = 0;
@@ -62,6 +90,28 @@ class UpdateCompanyCreditTermStatusLogic extends AbstractControllerLogic
$isCreditTerm = 1;
}
if($isCreditTerm === 1){
//{"per_page":10,"order_by":{"column":"id","DESC":true},"status_in":[2],"receiver":190,"type_in":[1],"does_not_have_payment_status_in":[0,1],"does_not_have_groups":1,"check_for_storage_invoice":1}
$filters = [
'status_in' => [2],
'receiver' => $companyModule->id,
'type_in' => [TransactionType::STORAGE_INVOICE]
];
$transactions = $this->listsTransactions->execute($filters);
foreach($transactions as $transaction){
$this->updatesTransactionIsWaived->execute($transaction);
$packingList = $transaction->owner()->first();
if($packingList){
$order = $packingList->owner()->first();
if($order instanceof Order){
$storages = $this->storageInvoiceTransactionProcessor->executeOrder($order);
}
}
}
}
$this->updatesCompanyModuleIsCreditTerm->execute($company->companyModules()->first()->connections()->first(), $isCreditTerm);
Log::info(Auth::user()->email." updated credit term status for customer with id: " .$request->route('id'). " to status " . $isCreditTerm);
@@ -0,0 +1,53 @@
<?php
namespace App\Classes\Modules\Companies\Standards\Rules;
use App\Classes\General\Abstracts\AbstractRule;
use App\Classes\Modules\Companies\DataTransferObjects\CompanyObject;
use App\Classes\ValueObjects\Constants\RoleTypes;
class CanUpdateCompanyModule extends AbstractRule
{
/**
* CanUpdateCompanyModule constructor.
*/
public function __construct()
{
}
/**
* @return bool
*/
protected function authorized($object): bool
{
$user = Auth()->user();
if($user){
$roleToCheck = Auth()->user()->type;
if (in_array($roleToCheck, RoleTypes::ADMIN_ROLES)) {
return true;
}
}
return false;
}
/**
* @param $object
* @return bool
* @throws \App\Classes\Exceptions\RequestValidationException
*/
protected function validators($object): bool
{
return true;
}
/**
* @param CompanyObject $object
* @return bool
*/
protected function criteria($object): bool
{
return true;
}
}
@@ -70,15 +70,31 @@ class ExportsCustomersWalletTransactionHistory implements FromQuery, WithHeading
$description = 'Credit Voucher for ' . $transaction->payment_reference;
break;
case TransactionType::PAYMENT:
$booking = Transaction::where('payment_reference', $transaction->bill_no)->first()->owner;
if (!$booking) {
$description = 'Payment for unknown booking, please contact tech support.';
$payment = Transaction::where('payment_reference', $transaction->bill_no)->first();
if (!$payment) {
$description = 'Payment not found, please contact tech support.';
break;
}
$marking = $booking->marking;
$description = 'Payment For booking refs' . $marking;
$invoice = $payment->owner;
if (!$invoice) {
$description = 'Invoice not found, please contact tech support.';
break;
}
$packingList = $invoice->owner;
if (!$packingList) {
$description = 'Packing List not found, please contact tech support.';
break;
}
$order = $packingList->owner;
if (!$order) {
$description = 'Order not found, please contact tech support.';
break;
}
$description = 'Payment For booking refs ' . $order->reference;
break;
case TransactionType::DEBIT_NOTE:
$description = 'Debit Voucher for ' . $transaction->payment_reference;
@@ -41,6 +41,9 @@ class ExportsPaymentTransactions implements FromQuery, WithHeadings, WithHeading
'DeptNo',
'Qty',
'UnitPrice',
'TaxType',
'TaxableAmt',
'TaxRate',
// 'marking',
// 'contact person',
// 'contact number',
@@ -130,6 +133,37 @@ class ExportsPaymentTransactions implements FromQuery, WithHeadings, WithHeading
$furtherDescription .= $item->name.' '.$item->quantity.' X '.$item->price."\n";
}
$transactionDetails = $transaction->transactionDetails;
$firstItem = true;
$rows = [];
foreach ($transactionDetails as $detail) {
// Prepare each row based on the transaction detail
$rows[] = [
$firstItem ? '<<New>>' : '',
$transaction->created_at->format('m/d/Y H:m'),
$company->debtor,
$order->reference,
$order->reference,
'500-0000',
str_replace('<br>', ' ', $detail->name),
'',
$container->reference,
'CIEF',
$detail->quantity,
$detail->price,
floatval($detail->tax_percentage) > 0 ? 'SV-6' : '',
floatval($detail->tax_percentage) > 0 ? $detail->amount : '0',
$detail->tax_percentage,
];
if($firstItem) {
$firstItem = false;
}
}
return $rows;
return [
'<<New>>',
$transaction->created_at->format('m/d/Y H:m'),
@@ -6,8 +6,8 @@ namespace App\Classes\Modules\PackingLists\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\PackingLists\Standards\Rules\CanListPackingLists;
use App\Http\Resources\PackingListNullOrderResource;
use App\Http\Resources\PackingListResource;
use App\Http\Resources\PackingListWithStorageResource;
use ErrorException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -54,7 +54,14 @@ class ListPackingListsLogic extends AbstractControllerLogic
$query = $this->listsPackingLists->execute($this->listsPackingLists->deserializeFilters($request->input('filters')));
return $this->collectionResponse(PackingListResource::collection($query));
if($request->input('storages')){
foreach ($query->items() as $item) {
$item['storages'] = $request->input('storages');
}
return $this->collectionResponse(PackingListWithStorageResource::collection($query));
}
else{
return $this->collectionResponse(PackingListResource::collection($query));
}
}
}
@@ -7,8 +7,11 @@ use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\Modules\Jobs\Processors\UpdateJobResultProcessor;
use App\Classes\General\Helper;
use App\Classes\Modules\Jobs\DataTransferObjects\ListGenericJobObject;
use App\Http\Middleware\CheckForStorageInvoiceByPackingLists;
use App\Http\Resources\ListPackingListJobResource;
use App\Http\Resources\ListPackingListDetailsJobResource;
use App\Http\Resources\ListPackingListJobWithStorageResource;
use Illuminate\Support\Facades\Log;
class ListPackingListsJobProcessor
{
@@ -19,15 +22,19 @@ class ListPackingListsJobProcessor
/** @var UpdateJobResultProcessor */
private $updateJobResultProcessor;
/** @var CheckForStorageInvoiceByPackingLists */
private $checkForStorageInvoiceByPackingLists;
/**
* ListPackingListsJobProcessor constructor.
* @param ListsPackingLists $listsPackingLists
* @param UpdateJobResultProcessor $updateJobResultProcessor
*/
public function __construct(ListsPackingLists $listsPackingLists, UpdateJobResultProcessor $updateJobResultProcessor)
public function __construct(ListsPackingLists $listsPackingLists, UpdateJobResultProcessor $updateJobResultProcessor, CheckForStorageInvoiceByPackingLists $checkForStorageInvoiceByPackingLists)
{
$this->listsPackingLists = $listsPackingLists;
$this->updateJobResultProcessor = $updateJobResultProcessor;
$this->checkForStorageInvoiceByPackingLists = $checkForStorageInvoiceByPackingLists;
}
/**
@@ -41,18 +48,40 @@ class ListPackingListsJobProcessor
$query = $this->listsPackingLists->execute($this->listsPackingLists->deserializeFilters($listGenericJobObject->getPayload()['filters']), ['page' => $listGenericJobObject->getPayload()['page']]);
// $query = $this->listsPackingLists->execute(array_merge($this->listsPackingLists->deserializeFilters($listGenericJobObject->getPayload()['filters']), ['page' => $listGenericJobObject->getPayload()['page'], 'with_containers_packages' => true]));
foreach ($query->items() as &$item) {
$item['userInfo'] = $listGenericJobObject->getUserInfo();
$filtersArray = json_decode($listGenericJobObject->getPayload()['filters'], true);
$storages = [];
if(isset($filtersArray['check_for_storage_invoice']))
{
$myRequest = new \Illuminate\Http\Request();
$myRequest->setMethod('POST');
$myRequest->request->add($listGenericJobObject->getPayload());
$next = function ($request) {
return $request;
};
$response = $this->checkForStorageInvoiceByPackingLists->handle($myRequest, $next);
$storages = $response->input('storages');
}
$filtersArray = json_decode($listGenericJobObject->getPayload()['filters'], true);
if(isset($filtersArray['does_not_have_transaction_type'])){ //For Pending Invoice query
foreach ($query->items() as &$item) {
$item['userInfo'] = $listGenericJobObject->getUserInfo();
$item['storages'] = $storages;
}
if(isset($filtersArray['does_not_have_transaction_type'])){ //For Payment and Billing page > Pending Invoice tab
$resultCurrent = Helper::collectionResponse(ListPackingListDetailsJobResource::collection($query));
$this->updateJobResultProcessor->execute($listGenericJobObject, $resultCurrent);
}
else{
$resultCurrent = Helper::collectionResponse(ListPackingListJobResource::collection($query));
$this->updateJobResultProcessor->execute($listGenericJobObject, $resultCurrent);
if($storages){ //For Payment and Billing page > Pending Payment tab, Paid Invoice tab
$resultCurrent = Helper::collectionResponse(ListPackingListJobWithStorageResource::collection($query));
$this->updateJobResultProcessor->execute($listGenericJobObject, $resultCurrent);
}
else{
$resultCurrent = Helper::collectionResponse(ListPackingListJobResource::collection($query));
$this->updateJobResultProcessor->execute($listGenericJobObject, $resultCurrent);
}
}
}
}
@@ -61,7 +61,7 @@ class FetchPerfexCRMInvoiceProcessor
$invoiceId = $result->payload['id'];
} else {
$log['message'] = 'FetchPerfexCRMInvoiceProcessor failed for transaction > bill_no: '.$number;
Helper::debugLogger($log);
Log::channel('perfex_crm')->info($log);
}
}
else{
@@ -25,7 +25,7 @@ class ConvertsPerfexCRMLeadToCustomer
return (object) $data;
}else{
Log::error('ConvertsPerfexCRMLeadToCustomer: '.$response);
Log::channel('perfex_crm')->info('ConvertsPerfexCRMLeadToCustomer: '.$response);
return null;
}
}
@@ -28,7 +28,7 @@ class CreatesPerfexCRMCustomer
$data = $response->json();
return (object) $data;
}else{
Log::error('CreatesPerfexCRMCustomer: '.$response);
Log::channel('perfex_crm')->info('CreatesPerfexCRMCustomer: '.$response);
return null;
}
}
@@ -35,7 +35,7 @@ class CreatesPerfexCRMCustomerContact
$data = $response->json();
return (object) $data;
}else{
Log::error('CreatesPerfexCRMCustomerContact: '.$response);
Log::channel('perfex_crm')->info('CreatesPerfexCRMCustomerContact: '.$response);
return null;
}
}
@@ -34,7 +34,7 @@ class CreatesPerfexCRMCustomerProject
$data = $response->json();
return (object) $data;
}else{
Log::error('CreatesPerfexCRMCustomerProject: '.$response);
Log::channel('perfex_crm')->info('CreatesPerfexCRMCustomerProject: '.$response);
return null;
}
}
@@ -54,7 +54,7 @@ class CreatesPerfexCRMInvoice
$data = $response->json();
return (object) $data;
}else{
Log::error('CreatesPerfexCRMInvoice: '.$response);
Log::channel('perfex_crm')->info('CreatesPerfexCRMInvoice: '.$response);
return null;
}
}
@@ -34,7 +34,7 @@ class CreatesPerfexCRMInvoicePayment
$data = $response->json();
return (object) $data;
}else{
Log::error('CreatesPerfexCRMInvoicePayment: '.$response);
Log::channel('perfex_crm')->info('CreatesPerfexCRMInvoicePayment: '.$response);
return null;
}
}
@@ -41,7 +41,7 @@ class CreatesPerfexCRMLead
$data = $response->json();
return (object) $data;
}else{
Log::error('CreatesPerfexCRMLead: '.$response);
Log::channel('perfex_crm')->info('CreatesPerfexCRMLead: '.$response);
return null;
}
}
@@ -37,7 +37,7 @@ class CreatesPerfexCRMMilestone
$data = $response->json();
return (object) $data;
}else{
Log::error('CreatesPerfexCRMMilestone: '.$response);
Log::channel('perfex_crm')->info('CreatesPerfexCRMMilestone: '.$response);
return null;
}
}
@@ -34,7 +34,7 @@ class CreatesPerfexCRMSupportTicket
$data = $response->json();
return (object) $data;
}else{
Log::error($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}
@@ -58,7 +58,7 @@ class CreatesPerfexCRMTask
$data = $response->json();
return (object) $data;
}else{
Log::error('CreatesPerfexCRMTask: '.$response);
Log::channel('perfex_crm')->info('CreatesPerfexCRMTask: '.$response);
return null;
}
}
@@ -25,7 +25,7 @@ class FetchesPerfexCRMCustomer
return (object) $data;
}else{
Log::error('FetchesPerfexCRMCustomer: '.$response);
Log::channel('perfex_crm')->info('FetchesPerfexCRMCustomer: '.$response);
return null;
}
}
@@ -27,7 +27,7 @@ class FetchesPerfexCRMInvoice
return (object) $data;
}else{
Log::error('FetchesPerfexCRMInvoice: '.$response);
Log::channel('perfex_crm')->info('FetchesPerfexCRMInvoice: '.$response);
return null;
}
}
@@ -25,7 +25,7 @@ class FetchesPerfexCRMLead
return (object) $data;
}else{
Log::error('FetchesPerfexCRMLead: '.$response);
Log::channel('perfex_crm')->info('FetchesPerfexCRMLead: '.$response);
return null;
}
}
@@ -31,7 +31,7 @@ class FetchesPerfexCRMMilestone
return (object) $data;
}else{
Log::error('FetchesPerfexCRMMilestone: '.$response);
Log::channel('perfex_crm')->info('FetchesPerfexCRMMilestone: '.$response);
return null;
}
}
@@ -31,7 +31,7 @@ class FetchesPerfexCRMProject
return (object) $data;
}else{
Log::error('FetchesPerfexCRMProject: '.$response);
Log::channel('perfex_crm')->info('FetchesPerfexCRMProject: '.$response);
return null;
}
}
@@ -45,7 +45,7 @@ class FetchesPerfexCRMTask
return (object) $data;
}else{
Helper::debugLogger($response);
Log::channel('perfex_crm')->info($response);
return null;
}
}
@@ -39,7 +39,7 @@ class UpdatesPerfexCRMCustomer
$data = $response->json();
return (object) $data;
}else{
// Helper::debugLogger($response);
// Log::channel('perfex_crm')->info($response);
return null;
}
}
@@ -61,7 +61,7 @@ class UpdatesPerfexCRMInvoice
$data = $response->json();
return (object) $data;
}else{
Log::error('UpdatesPerfexCRMInvoice: '.$response);
Log::channel('perfex_crm')->info('UpdatesPerfexCRMInvoice: '.$response);
return null;
}
}
@@ -42,7 +42,7 @@ class UpdatesPerfexCRMLead
$data = $response->json();
return (object) $data;
}else{
Log::error('UpdatesPerfexCRMLead: '.$response);
Log::channel('perfex_crm')->info('UpdatesPerfexCRMLead: '.$response);
return null;
}
}
@@ -34,7 +34,7 @@ class UpdatesPerfexCRMProject
$data = $response->json();
return (object) $data;
}else{
Log::error('UpdatesPerfexCRMProject: '.$response);
Log::channel('perfex_crm')->info('UpdatesPerfexCRMProject: '.$response);
return null;
}
}
@@ -39,7 +39,7 @@ class UpdatesPerfexCRMTask
$data = $response->json();
return (object) $data;
}else{
Log::error('UpdatesPerfexCRMTask: '.$response);
Log::channel('perfex_crm')->info('UpdatesPerfexCRMTask: '.$response);
return null;
}
}
@@ -82,16 +82,35 @@ class CreateGroupsLogic extends AbstractControllerLogic
public function logic(Request $request) : JsonResponse
{
$payment_method = PaymentMethodType::PAYMENT_METHODS[$request->input('payment_method')];
$groupPyamentStatus = ApprovalStatus::PENDING_VERIFICATION;
$invoice_ids = json_decode($request->route('transaction_ids'));
$billNumber = $this->generatesTransactionBillNumber->execute('PYMT-');
// todo-new: check why is this not working
// $invoices = $this->fetchesTransaction->execute(['id_in' => $invoice_ids]);
$invoices = Transaction::whereIn('id', $invoice_ids)->get();
$isInvoicesApprove = $this->checkIfInvoicesAreApprove($invoices);
if(!$isInvoicesApprove){
$response = ['message' => 'One of the transactions might be suspended; please check if there are any disputes in progress.'];
return $this->response(['data' => $response]);
}
else{
$paymentMethodStr = $request->input('payment_method');
$paymentMethod = PaymentMethodType::PAYMENT_METHODS[$paymentMethodStr];
$amount = $request->input('amount');
$bankCode = $request->input('bank_code');
$result = $this->processInvoices($invoices, $paymentMethodStr, $amount, $bankCode);
if ($paymentMethod === PaymentMethodType::PAYMENT_GATEWAY) {
return $this->resourceResponse(new WalletTransactionResource($result));
}
}
return $this->response([]);
}
private function processInvoices($invoices, $reqPaymentMethod, $reqAmount, $reqBankCode){
$result = [];
$payment_method = PaymentMethodType::PAYMENT_METHODS[$reqPaymentMethod];
$groupPyamentStatus = ApprovalStatus::PENDING_VERIFICATION;
$billNumber = $this->generatesTransactionBillNumber->execute('PYMT-');
foreach ($invoices as $invoice) {
$order = null;
if ($invoice->owner instanceof Transaction) {
@@ -118,7 +137,7 @@ class CreateGroupsLogic extends AbstractControllerLogic
$wallet = Wallet::where('owner_id', $companyModuleId)->first();
// todo-new: verify currently checking wallet amount based on 'amount' value passed by frontend
if((float) number_format(($wallet->amount - $request->input('amount')),2) < 0){
if((float) number_format(($wallet->amount - $reqAmount),2) < 0){
throw new MalformedRequestException('Insufficient wallet balance. Please Top up your wallet.');
}
@@ -154,7 +173,7 @@ class CreateGroupsLogic extends AbstractControllerLogic
foreach ($invoices as $invoice) {
if ($payment_method == PaymentMethodType::WALLET) {
$paymentTransaction = $this->createPaymentTransactionProcessor->execute($invoice, PaymentMethodType::WALLET, $request->input('bank_code'), false);
$paymentTransaction = $this->createPaymentTransactionProcessor->execute($invoice, PaymentMethodType::WALLET, $reqBankCode, false);
if($paymentTransaction && $paymentTransaction->status == ApprovalStatus::APPROVED){
$pL = $invoice->owner;
@@ -181,11 +200,12 @@ class CreateGroupsLogic extends AbstractControllerLogic
if (in_array($payment_method, [PaymentMethodType::PAYMENT_GATEWAY, PaymentMethodType::CASH])) {
// create only one billplz payment for wallet top up
$amount = floatval(str_replace(',', '', $request->input('amount')));
$amount = floatval(str_replace(',', '', $reqAmount));
$companyModuleId = $invoice->receiver;
$companyModule = $this->fetchesCompanyModule->execute(['id' => $companyModuleId]);
$topUpTransaction = $this->createWalletTopUpTransactionProcessor->execute($companyModule, $amount, $request->input('bank_code'), $payment_method, $billNumber, true);
$topUpTransaction = $this->createWalletTopUpTransactionProcessor->execute($companyModule, $amount, $reqBankCode, $payment_method, $billNumber, true);
$result = $topUpTransaction;
}
$group->issuer = $issuer;
@@ -201,11 +221,15 @@ class CreateGroupsLogic extends AbstractControllerLogic
$group->status = $groupPyamentStatus;
$group->save();
if ($payment_method === PaymentMethodType::PAYMENT_GATEWAY) {
return $this->resourceResponse(new WalletTransactionResource($topUpTransaction));
return $result;
}
} else {
return $this->response([]);
private function checkIfInvoicesAreApprove($invoices){
foreach ($invoices as $invoice) {
if($invoice->status !== ApprovalStatus::APPROVED && $invoice->status !== ApprovalStatus::COMPLETED){
return false;
}
}
return true;
}
}
@@ -52,28 +52,18 @@ class CreatePaymentTransactionLogic extends AbstractControllerLogic
$invoice_transaction = $this->fetchesTransaction->execute(['id' => $request->input('transaction_id')]);
$payment_transaction = $this->createPaymentTransactionProcessor->execute($invoice_transaction, $payment_method , $request->input('bank_code'), false);
if($invoice_transaction->status === ApprovalStatus::APPROVED){
$payment_transaction = $this->createPaymentTransactionProcessor->execute($invoice_transaction, $payment_method , $request->input('bank_code'), false);
if($payment_transaction && $payment_transaction->status == ApprovalStatus::APPROVED){
$pL = $invoice_transaction->owner;
$this->releaseGoodsToCustomerProcessor->execute($pL, $invoice_transaction);
if($payment_transaction && $payment_transaction->status === ApprovalStatus::APPROVED){
$pL = $invoice_transaction->owner;
$this->releaseGoodsToCustomerProcessor->execute($pL, $invoice_transaction);
}
return $this->resourceResponse(new TransactionResource($payment_transaction));
}
//cief todo: at exchange there is a transition step - starts
// if(PaymentMethodType::PAYMENT_METHODS[$request->input('payment_method')] == PaymentMethodType::PAYMENT_GATEWAY){
// $this->updatesTransactionStatus->execute($transaction, ApprovalStatus::PENDING_VERIFICATION);
// }
// if(config('perfexcrm.is_enabled') == 'true'){
// $this->transactionToPerfexCRMV2Processor->execute($transaction, $status);
// }
//To use
//ApprovalStatus::PENDING_VERIFICATION;
//use this to trigger $this->transactionToPerfexCRMV2Processor->execute > defineTasks > defineTasks_handlePendingVerificationStatus > definePaymentTasks
//cief todo: at exchange there is a transition step - ends
return $this->resourceResponse(new TransactionResource($payment_transaction));
$response = ['message' => 'A transaction might be suspended; please check if there is any dispute in progress.'];
return $this->response(['data' => $response]);
}
@@ -48,6 +48,8 @@ class DeleteGroupLogic extends AbstractControllerLogic
*/
public function logic(Request $request) : JsonResponse
{
ini_set('memory_limit', '-1');
$group = $this->fetchesGroup->execute(['id' => $request->route('id')]);
foreach ($group->groupTransactions as $groupTransaction) {
@@ -0,0 +1,90 @@
<?php
namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\General\Eloquent\Filters\PaymentMethod;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\Modules\Transactions\Services\FetchesGroup;
use App\Classes\Modules\Transactions\Services\DeletesTransaction;
use App\Classes\Modules\Transactions\Services\DeletesGroup;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\Transaction;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class DeletePaidGroupLogic extends AbstractControllerLogic
{
/**
* @return array
*/
protected function notification(): array
{
return [
'title' => 'Delete Paid Group Transaction',
'message' => 'You have successfully deleted this Group Transaction'
];
}
/** @var FetchesGroup */
private $fetchesGroup;
/** @var DeletesGroup */
private $deletesGroup;
/**
* DeleteGroupLogic constructor.
* @param updatesTransactionStatus $updatesTransactionStatus
* @param FetchesGroup $fetchesGroup
* @param DeletesTransaction $deletesTransaction
*/
public function __construct(FetchesGroup $fetchesGroup, DeletesGroup $deletesGroup)
{
$this->fetchesGroup = $fetchesGroup;
$this->deletesGroup = $deletesGroup;
}
/**
* @param Request $request
* @return JsonResponse
* @throws \App\Classes\Exceptions\MalformedRequestException
*/
public function logic(Request $request): JsonResponse
{
$group = $this->fetchesGroup->execute(['id' => $request->route('id')]);
foreach ($group->groupTransactions as $groupTransaction) {
$invoice = $groupTransaction->transaction;
$paymentTransaction = $invoice->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->first();
if ($paymentTransaction->payment_method == PaymentMethodType::WALLET) {
// Store the transaction ID before deleting
$transactionId = Transaction::where('bill_no', $paymentTransaction->payment_reference)->first()->id;
// Delete the transaction
Transaction::where('id', $transactionId)->first()->delete();
// Now you have the transaction ID available in $transactionId
Log::channel('deletePaidGroupOrder')->info("Deleted payment reference transaction ID: " . $transactionId);
} else {
Log::channel('deletePaidGroupOrder')->info("no transaction found. Invoice Id ->" . $invoice->id);
}
// Store the transaction ID before deleting
$transactionId = $paymentTransaction->id;
// Delete the payment transaction
$paymentTransaction->delete();
Log::channel('deletePaidGroupOrder')->info("Deleted payment transaction ID: " . $transactionId);
}
Log::channel('deletePaidGroupOrder')->info("Deleted Group -> " . $group->id);
$this->deletesGroup->execute($group);
return $this->response([]);
}
}
@@ -6,9 +6,13 @@ namespace App\Classes\Modules\Transactions\ControllersLogic;
use App\Classes\General\Abstracts\AbstractControllerLogic;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Transactions\Services\FetchesGroup;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\Transaction;
use App\Models\Wallet;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class DeletePaymentTransactionLogic extends AbstractControllerLogic
{
@@ -23,6 +27,9 @@ class DeletePaymentTransactionLogic extends AbstractControllerLogic
];
}
/** @var FetchesGroup */
private $fetchesGroup;
/** @var FetchesTransaction */
private $fetchesTransaction;
@@ -34,11 +41,13 @@ class DeletePaymentTransactionLogic extends AbstractControllerLogic
* SuspendTransactionLogic constructor.
* @param FetchesTransaction $fetchesTransaction
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param FetchesGroup $fetchesGroup
*/
public function __construct(FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus)
public function __construct(FetchesTransaction $fetchesTransaction, UpdatesTransactionStatus $updatesTransactionStatus, FetchesGroup $fetchesGroup)
{
$this->fetchesTransaction = $fetchesTransaction;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->fetchesGroup = $fetchesGroup;
}
@@ -46,11 +55,23 @@ class DeletePaymentTransactionLogic extends AbstractControllerLogic
{
$transaction = $this->fetchesTransaction->execute(['id' => $request->route('id')]);
if($transaction->owner instanceof Wallet){
try{
$group = $this->fetchesGroup->execute(['reference' => $transaction->payment_reference]);
$group->status = ApprovalStatus::SUSPENDED;
$group->save();
}
catch(\Exception $excaption){
Log::info('No group associated with transaction with payment_reference - '.$transaction->payment_reference);
}
}
$transaction->delete();
$invoice = $transaction->owner;
$this->updatesTransactionStatus->execute($invoice, ApprovalStatus::APPROVED);
if ($invoice instanceof Transaction) {
$this->updatesTransactionStatus->execute($invoice, ApprovalStatus::APPROVED);
}
return $this->response([]);
}
@@ -43,17 +43,18 @@ class ListTransactionsLogic extends AbstractControllerLogic
$query = $this->listsTransactions->execute($this->listsTransactions->deserializeFilters($request->input('filters')));
if($request->input('storages')){
foreach ($query->items() as &$item) {
foreach ($query->items() as $item) {
$transactionId = $item['id'];
$filteredStorages = array_filter($request->input('storages'), function ($storage) use ($transactionId) {
return isset($storage['parentInvoiceId']) && $storage['parentInvoiceId'] == $transactionId;
});
$item['storages'] = $filteredStorages;
}
return $this->collectionResponse(TransactionWithStorageResource::collection($query));
}
else{
return $this->collectionResponse(TransactionResource::collection($query));
//return $this->collectionResponse(TransactionWithStorageResource::collection($query));
}
// else{
// return $this->collectionResponse(TransactionResource::collection($query));
//
return $this->collectionResponse(TransactionWithStorageResource::collection($query));
}
}
@@ -15,6 +15,7 @@ use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Models\Document;
use Carbon\Carbon;
class RegenerateShippingInvoiceTransactionLogic extends AbstractControllerLogic
{
@@ -51,11 +52,18 @@ class RegenerateShippingInvoiceTransactionLogic extends AbstractControllerLogic
foreach ($orders as $order){
$invoices = $order->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->get();
foreach ($invoices as $invoice){
$invoice->documents()->delete();
$transaction_invoice_pdf = LaravelMpdf::loadView('pages.pdfs.shipping_invoice', ['invoice_transaction' => $invoice]);
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
@@ -63,11 +71,11 @@ class RegenerateShippingInvoiceTransactionLogic extends AbstractControllerLogic
ApprovalStatus::COMPLETED,
'shipping_invoice'
);
$document =$this->createsDocument->execute($invoice, $document_object);
$this->createsFiles->execute($document, $document_object);
// dump($document);
}
}
@@ -16,6 +16,7 @@ use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Models\Document;
use Carbon\Carbon;
class RegenerateSingleShippingInvoiceTransactionLogic extends AbstractControllerLogic
{
@@ -54,7 +55,14 @@ class RegenerateSingleShippingInvoiceTransactionLogic extends AbstractController
$invoice->documents()->delete();
$transaction_invoice_pdf = LaravelMpdf::loadView('pages.pdfs.shipping_invoice', ['invoice_transaction' => $invoice]);
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
@@ -25,6 +25,8 @@ use App\Classes\Modules\Transactions\Services\DeletesTransactionDetails;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionDetailObject;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\ValueObjects\Constants\TaxPercentage;
use Carbon\Carbon;
class UpdateShippingInvoiceTransactionLogic extends AbstractControllerLogic
{
@@ -60,9 +62,9 @@ class UpdateShippingInvoiceTransactionLogic extends AbstractControllerLogic
/** @var DeletesTransactionDetails */
private $deletesTransactionDetails;
public function __construct(
FetchesPackingList $fetchesPackingList,
FetchesPackingList $fetchesPackingList,
FetchesTransaction $fetchesTransaction,
UpdatesTransaction $updatesTransaction,
FetchesTransactionDetail $fetchesTransactionDetail,
@@ -105,11 +107,25 @@ class UpdateShippingInvoiceTransactionLogic extends AbstractControllerLogic
$transaction_detail = (object) $transaction_detail;
if(!in_array($transaction_detail->reference, ['SHIPPING_FEE', 'OVER_WEIGHT_CHARGES', 'MIN_CBM_CHARGES'])){
$reference = 'CUSTOM_CHARGES';
$taxPercentage = TaxPercentage::DEFAULT;
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice_transaction->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare)) {
$taxPercentage = TaxPercentage::SIX_PERCENT;
}
if($transaction_detail->reference === "PAY_ON_BEHALF"){
$reference = "PAY_ON_BEHALF";
$taxPercentage = TaxPercentage::NO_TAX;
}
$object_detail = new TransactionDetailObject(
'CUSTOM_CHARGES',
$reference,
isset($transaction_detail->name) ? $transaction_detail->name : TransactionDetailType::CUSTOM_CHARGES,
$transaction_detail->quantity,
$transaction_detail->price
$transaction_detail->price,
$taxPercentage
);
if(isset($transaction_detail->id)){
@@ -121,20 +137,20 @@ class UpdateShippingInvoiceTransactionLogic extends AbstractControllerLogic
}
$object = new TransactionObject(
$invoice_transaction->bill_no,
TransactionType::SHIPPING_INVOICE,
1,
$invoice_transaction->bill_no,
TransactionType::SHIPPING_INVOICE,
1,
$invoice_transaction->issuer,
1,
1,
PaymentMethodType::CASH,
$invoice_transaction->transactionDetails()->sum('amount'),
$invoice_transaction->transactionDetails()->sum('amount'),
1,
1,
0,
0,
1,
0,
null,
$invoice_transaction->transactionDetails()->sum('tax_amount'),
0,
null,
ApprovalStatus::PENDING_VERIFICATION
);
@@ -18,19 +18,25 @@ class TransactionDetailObject implements DataTransferObject
/** @var float|null */
private $price;
/** @var float|null */
private $taxPercentage;
/**
* TransactionDetailObject constructor.
* @param string $reference
* @param string $name
* @param float $quantity
* @param float $price
* @param float $taxPercentage
*/
public function __construct(?string $reference, ?string $name , ?float $quantity, ?float $price)
public function __construct(?string $reference, ?string $name , ?float $quantity, ?float $price, ?float $taxPercentage)
{
$this->reference = $reference;
$this->name = $name;
$this->quantity = $quantity;
$this->price = $price;
$this->taxPercentage = $taxPercentage;
}
/**
@@ -65,9 +71,28 @@ class TransactionDetailObject implements DataTransferObject
return $this->price;
}
/**
* @return float
*/
public function getAmount(): float
{
return $this->getQuantity() * $this->getPrice();
return ($this->getQuantity() * $this->getPrice()) + $this->getTaxAmount();
}
/**
* @return float
*/
public function getTaxPercentage(): ?float
{
return $this->taxPercentage;
}
/**
* @return float
*/
public function getTaxAmount(): float
{
return ($this->getQuantity() * $this->getPrice()) * $this->getTaxPercentage() / 100;
}
}
@@ -80,21 +80,21 @@ class TransactionObject implements DataTransferObject
* @param array|null $details
*/
public function __construct(
string $billNo,
string $transactionType,
int $issuer,
int $receiver,
int $recipientBankAccountId,
int $paymentMethod,
float $amount,
float $originalAmount,
string $billNo,
string $transactionType,
int $issuer,
int $receiver,
int $recipientBankAccountId,
int $paymentMethod,
float $amount,
float $originalAmount,
int $currencyId,
int $originalCurrencyId,
int $originalCurrencyId,
float $currencyRate,
float $tax,
float $serviceCharge,
?Carbon $expiresOn,
?int $status = ApprovalStatus::PENDING_SUBMISSION,
float $tax,
float $serviceCharge,
?Carbon $expiresOn,
?int $status = ApprovalStatus::PENDING_SUBMISSION,
?array $details = [],
?string $paymentReference = null
)
@@ -241,10 +241,10 @@ class TransactionObject implements DataTransferObject
/**
* @return array
*/
public function getDetails(): array
public function getDetails(): array //cief todo: not in used as of 20240407
{
return array_map(function($product){
return new TransactionDetailObject($product['stockCode'] ?? '', $product['description'] ?? '', $product['quantity'] ?? '', floatval(str_replace(',', '', $product['unit_price'])));
return new TransactionDetailObject($product['stockCode'] ?? '', $product['description'] ?? '', $product['quantity'] ?? '', floatval(str_replace(',', '', $product['unit_price'])), 0.0 );
}, $this->details);
}
@@ -255,4 +255,4 @@ class TransactionObject implements DataTransferObject
{
return $this->paymentReference;
}
}
}
@@ -19,6 +19,7 @@ use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Jobs\CreatePerfexCRMInvoice;
use App\Classes\Modules\Transactions\Processors\CheckStorageInvoiceTransactionProcessor;
use App\Models\Order;
use Carbon\Carbon;
class ApproveShippingInvoiceTransactionProcessor
{
@@ -59,9 +60,16 @@ class ApproveShippingInvoiceTransactionProcessor
/** @var Transaction $invoice_transaction */
$invoice_transaction = $packingList->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::PENDING_SUBMISSION])->first();
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice_transaction->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice_transaction->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$this->updatesTransactionStatus->execute($invoice_transaction, ApprovalStatus::APPROVED);
$transaction_invoice_pdf = LaravelMpdf::loadView('pages.pdfs.shipping_invoice', ['invoice_transaction' => $invoice_transaction]);
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice_transaction]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
@@ -23,6 +23,7 @@ use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PackageType;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Classes\ValueObjects\Constants\TaxPercentage;
use App\Classes\ValueObjects\Constants\TransactionDetailType;
use App\Http\Resources\TransactionWithStorageResource;
use App\Models\Order;
@@ -99,33 +100,38 @@ class CheckStorageInvoiceTransactionProcessor
return $this->executeOrder($order);
}
public function executeOrder(Order $order, bool $isBackDoorCheck = false){
public function executeOrder(Order $order){
$results = [];
$marking = $order->companyModule->inviters()->withPivot('invitee_reference')->first()->pivot->invitee_reference;
$is_credit_term = $order->companyModule->inviters()->withPivot('is_credit_term')->first()->pivot->is_credit_term;
if(!$is_credit_term){
Log::channel('storage_invoices')->info('orderId: '.$order->id.', orderReference: '.$order->reference.', marking: '.$marking.', is_credit_term: '.$is_credit_term);
$packingLists = $order->destinationWarehousePackages;
Log::channel('storage_invoices')->info('orderId: '.$order->id.', orderReference: '.$order->reference.', marking: '.$marking.', is_credit_term: '.$is_credit_term);
$packingLists = $order->destinationWarehousePackages;
foreach ($packingLists as $packingList){
$arrivalDateAtChinaWarehouse = $this->getArrivalDateAtChinaWarehoue($packingList);
Log::channel('storage_invoices')->info('arrivalDateAtChinaWarehouse: '.json_encode($arrivalDateAtChinaWarehouse));
Log::channel('storage_invoices')->info('destinationWarehousePackage: '.json_encode($packingList));
$eta = $this->getEtaFromPackingList($packingList);
if($arrivalDateAtChinaWarehouse && $eta){
$transactions = $packingList->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->get();
// $transactions = $destinationWarehousePackage->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->where('transactions.status', ApprovalStatus::APPROVED)->get();
foreach ($packingLists as $packingList){
$arrivalDateAtChinaWarehouse = $this->getArrivalDateAtChinaWarehoue($packingList);
Log::channel('storage_invoices')->info('arrivalDateAtChinaWarehouse: '.json_encode($arrivalDateAtChinaWarehouse));
Log::channel('storage_invoices')->info('destinationWarehousePackage: '.json_encode($packingList));
$eta = $this->getEtaFromPackingList($packingList);
if($arrivalDateAtChinaWarehouse && $eta){
$transactions = $packingList->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->whereIn('transactions.status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->get();
// $transactions = $destinationWarehousePackage->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->where('transactions.status', ApprovalStatus::APPROVED)->get();
/** @var Transaction $invoice_transaction */
foreach ($transactions as $invoice_transaction){
$result = $this->processSingleTransactionOfTypeShippingInvoice($invoice_transaction, $packingList, $order->company_module_id, $eta, $isBackDoorCheck);
if($result){
$results[] = $result;
}
/** @var Transaction $invoice_transaction */
foreach ($transactions as $invoice_transaction){
$result = null;
if(!$is_credit_term){
$result = $this->processSingleTransactionOfTypeShippingInvoice($invoice_transaction, $packingList, $order->company_module_id, $eta);
}
else{
$result = $this->isPaidOrWaivedStorageInvoiceExist($invoice_transaction, $packingList, $eta);
}
if($result){
$results[] = $result;
}
}
}
}
return $results;
}
@@ -167,7 +173,7 @@ class CheckStorageInvoiceTransactionProcessor
return null;
}
private function processSingleTransactionOfTypeShippingInvoice($transaction, $destinationWarehousePackage, $company_module_id, $eta, $isBackDoorCheck){
private function processSingleTransactionOfTypeShippingInvoice($transaction, $destinationWarehousePackage, $company_module_id, $eta){
$pricePerCBM = 3;
$resultNumberOfDaysFree = 10;
$dt1 = $eta->copy()->addDay()->startOfDay();
@@ -190,14 +196,26 @@ class CheckStorageInvoiceTransactionProcessor
$cbm = $cbm + $quantity;
}
$total_tax = 0;
$taxPercentage = TaxPercentage::DEFAULT;
$price_cbm = $pricePerCBM * $cbm * $resultNumberOfDaysExceeded;
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::now();
Log::channel('storage_invoices')->info('storageInvoice: '.json_encode($storageInvoice).', $transaction->status: '.$transaction->status);
if(!$storageInvoice && $resultNumberOfDaysExceeded > 0 && $transaction->status != ApprovalStatus::COMPLETED){
Log::channel('storage_invoices')->info('Created $transaction->id: '.$transaction->id);
$billNumber = $this->generatesTransactionBillNumber->execute('STOR-');
$storageInvoice = $this->createStorageInvoiceTransaction($destinationWarehousePackage, $billNumber, $company_module_id, $price_cbm);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare)) {
$taxPercentage = TaxPercentage::SIX_PERCENT;
$total_tax = $price_cbm * $taxPercentage / 100;
$price_cbm = $price_cbm + $total_tax;
}
$storageInvoice = $this->createStorageInvoiceTransaction($destinationWarehousePackage, $billNumber, $company_module_id, $price_cbm, $total_tax);
$storageInvoiceId = $storageInvoice->id;
$this->createStorageInvoiceTransactionDetails($storageInvoice, $destinationWarehousePackage, $cbm, $pricePerCBM, $resultNumberOfDaysExceeded);
$this->createStorageInvoiceTransactionDetails($storageInvoice, $destinationWarehousePackage, $cbm, $pricePerCBM, $resultNumberOfDaysExceeded, $taxPercentage);
}
else if($storageInvoice){
//Additional handling for giving selected storage invoice a waiver
@@ -216,6 +234,12 @@ class CheckStorageInvoiceTransactionProcessor
$price_cbm = $pricePerCBM * $cbm * $resultNumberOfDaysExceeded;
}
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare)) {
$taxPercentage = TaxPercentage::SIX_PERCENT;
$total_tax = $price_cbm * $taxPercentage / 100;
$price_cbm = $price_cbm + $total_tax;
}
$amount = $storageInvoice->amount;
$epsilon = 0.0001; // Tolerance for the comparison
Log::channel('storage_invoices')->info('Update $transaction->id: '.$transaction->id);
@@ -227,23 +251,24 @@ class CheckStorageInvoiceTransactionProcessor
if(abs($price_cbm - $amount) > $epsilon && $storageInvoice->status !== ApprovalStatus::COMPLETED){
$paymentTransactions = $storageInvoice->transactions()->where('transactions.type', TransactionType::PAYMENT)->where('transactions.status', ApprovalStatus::PENDING_SUBMISSION)->get();
if(!$isBackDoorCheck){
if(count($paymentTransactions) > 0){
$this->updatePaymentTransactionViaNonGroupPayment($paymentTransactions);
}
else{
$this->updatePaymentTransactionViaGroupPayment($storageInvoice);
}
// if(!$isBackDoorCheck){
if(count($paymentTransactions) > 0){
$this->updatePaymentTransactionViaNonGroupPayment($paymentTransactions);
}
else{
$this->updatePaymentTransactionViaGroupPayment($storageInvoice);
}
//}
$proceedToUpdate = true;
}
if($proceedToUpdate || ($pricePerCBM == 0 && $amount != 0)){
Log::channel('storage_invoices')->info('proceedToUpdate');
$storageInvoice = $this->updateStorageInvoiceTransaction($storageInvoice, $price_cbm);
$storageInvoice = $this->updateStorageInvoiceTransaction($storageInvoice, $price_cbm, $total_tax);
$invoiceTransactionDetails = $storageInvoice->transactionDetails()->first();
$this->updateStorageInvoiceTransactionDetails($invoiceTransactionDetails, $destinationWarehousePackage, $cbm, $pricePerCBM, $resultNumberOfDaysExceeded);
$this->updateStorageInvoiceTransactionDetails($invoiceTransactionDetails, $destinationWarehousePackage, $cbm, $pricePerCBM, $resultNumberOfDaysExceeded, $taxPercentage);
}
$storageInvoiceId = $storageInvoice->id;
@@ -266,9 +291,64 @@ class CheckStorageInvoiceTransactionProcessor
}
private function isPaidOrWaivedStorageInvoiceExist($transaction, $packingList, $eta){
$pricePerCBM = 3;
$resultNumberOfDaysFree = 10;
$dt1 = $eta->copy()->addDay()->startOfDay();
$resultStartDate = $dt1->format('Y-m-d');
$currentDatetime = Carbon::now();
$dt2 = $currentDatetime->copy()->addDay()->startOfDay();
$resultCurrentDate = $dt2->format('Y-m-d H:i:s');
$interval = Carbon::parse($dt2)->diff($dt1);
$resultNumberOfDaysExceeded = $interval->days - $resultNumberOfDaysFree;
$paidStorageInvoice = $packingList->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->whereIn('transactions.status', [ApprovalStatus::COMPLETED])->first();
if($paidStorageInvoice){
$storageInvoice = $paidStorageInvoice;
}
else{
$waivedStorageInvoice = $packingList->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->where('transactions.is_waived', 1)->whereIn('transactions.status', [ApprovalStatus::APPROVED])->first();
$storageInvoice = $waivedStorageInvoice;
}
if($storageInvoice){
$storageInvoiceId = $storageInvoice->id;
if(isset($storageInvoice->is_waived) && $storageInvoice->is_waived){
$pricePerCBM = 0;
}
$transactionDetailsItems = $transaction->transactionDetails()->get();
$cbm = 0.00;
foreach ($transactionDetailsItems as $tdItem){
$quantity = $tdItem->quantity;
if($tdItem->price < 0.00){
$quantity = $quantity * -1;
}
$cbm = $cbm + $quantity;
}
if($storageInvoiceId !== 0){
$result = [
'parentInvoiceId' => $transaction->id,
'storageInvoiceId' => $storageInvoiceId,
'numberOfDaysExceeded' => $resultNumberOfDaysExceeded,
'numberOfDaysFree' => $resultNumberOfDaysFree,
'startDate' => $resultStartDate,
'currentDate' => $resultCurrentDate,
'cbm' => $cbm,
'pricePerCBM' => $pricePerCBM,
'storageInvoice' => new TransactionWithStorageResource($storageInvoice)
];
return $result;
}
}
return [];
}
private function updatePaymentTransactionViaGroupPayment($storageInvoice){
Log::channel('storage_invoices')->info('updatePaymentTransactionViaGroupPayment');
$groups = $storageInvoice->groups()->get();
$groups = $storageInvoice->groups()->whereNotIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::SUSPENDED])->get();
foreach ($groups as $grp){
$groupReference = $grp->reference;
$walletTransaction = $this->fetchesTransaction->execute(['payment_reference' => $groupReference]);
@@ -296,7 +376,7 @@ class CheckStorageInvoiceTransactionProcessor
}
}
private function updateStorageInvoiceTransaction(Transaction $transaction, float $totalAmount){
private function updateStorageInvoiceTransaction(Transaction $transaction, float $totalAmount, float $totalTax){
$object = new TransactionObject(
$transaction->bill_no,
@@ -310,7 +390,7 @@ class CheckStorageInvoiceTransactionProcessor
1,
1,
0,
0,
$totalTax,
0,
null,
ApprovalStatus::APPROVED
@@ -322,18 +402,19 @@ class CheckStorageInvoiceTransactionProcessor
return $invoice_transaction;
}
private function updateStorageInvoiceTransactionDetails($invoice_transaction_details, PackingList $packing_list, $cbm, $pricePerCBM, $numberOfDays){
private function updateStorageInvoiceTransactionDetails($invoice_transaction_details, PackingList $packing_list, $cbm, $pricePerCBM, $numberOfDays, $taxPercentage){
$object_detail = new TransactionDetailObject(
'STORAGE_FEE',
TransactionDetailType::STORAGE_FEE.' for '.$numberOfDays. ' days * RM'.$pricePerCBM.'<br>'.round($packing_list->packages->where('type', '!=', PackageType::OVER_WEIGHT)->sum('quantity'), 3).' CTNS - '.round($cbm, 3).' CBM',
$cbm,
$pricePerCBM * $numberOfDays
$pricePerCBM * $numberOfDays,
$taxPercentage
);
$this->updatesTransactionDetail->execute($invoice_transaction_details, $object_detail);
}
private function createStorageInvoiceTransaction(PackingList $packing_list, string $billNumber, int $companyModuleId, float $totalAmount){
private function createStorageInvoiceTransaction(PackingList $packing_list, string $billNumber, int $companyModuleId, float $totalAmount, float $totalTax){
$object = new TransactionObject(
$billNumber,
@@ -347,7 +428,7 @@ class CheckStorageInvoiceTransactionProcessor
1,
1,
0,
0,
$totalTax,
0,
null,
ApprovalStatus::APPROVED
@@ -359,12 +440,13 @@ class CheckStorageInvoiceTransactionProcessor
return $invoice_transaction;
}
private function createStorageInvoiceTransactionDetails($invoice_transaction, PackingList $packing_list, $cbm, $pricePerCBM, $numberOfDays){
private function createStorageInvoiceTransactionDetails($invoice_transaction, PackingList $packing_list, $cbm, $pricePerCBM, $numberOfDays, $taxPercentage){
$object_detail = new TransactionDetailObject(
'STORAGE_FEE',
TransactionDetailType::STORAGE_FEE.' for '.$numberOfDays. ' days * RM'.$pricePerCBM.'<br>'.round($packing_list->packages->where('type', '!=', PackageType::OVER_WEIGHT)->sum('quantity'), 3).' CTNS - '.round($cbm, 3).' CBM',
$cbm,
$pricePerCBM * $numberOfDays
$pricePerCBM * $numberOfDays,
$taxPercentage
);
$this->createsTransactionDetail->execute($invoice_transaction, $object_detail);
@@ -22,14 +22,17 @@ use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PackageType;
use App\Classes\ValueObjects\Constants\SegmentConstants;
use App\Classes\ValueObjects\Constants\TaxPercentage;
use App\Classes\ValueObjects\Constants\TransactionDetailType;
use App\Models\CompanyModule;
use App\Models\Document;
use App\Models\PackingList;
use App\Models\Transaction;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
class CreateInvoiceTransactionProcessor
@@ -171,6 +174,16 @@ class CreateInvoiceTransactionProcessor
$billNumber = $this->generatesTransactionBillNumber->execute('SHIP-');
$total_tax = 0;
$taxPercentage = TaxPercentage::DEFAULT;
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::now();
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare)) {
$taxPercentage = TaxPercentage::SIX_PERCENT;
$total_tax = $total_cbm * $taxPercentage / 100;
$total_cbm = $total_cbm + $total_tax;
}
$object = new TransactionObject(
$billNumber,
TransactionType::SHIPPING_INVOICE,
@@ -183,7 +196,7 @@ class CreateInvoiceTransactionProcessor
1,
1,
0,
0,
$total_tax,
0,
null,
ApprovalStatus::PENDING_SUBMISSION
@@ -196,7 +209,8 @@ class CreateInvoiceTransactionProcessor
'SHIPPING_FEE',
TransactionDetailType::SHIPPING_FEE.'<br>'.round($packing_list->packages->where('type', '!=', PackageType::OVER_WEIGHT)->sum('quantity'), 3).' CTNS - '.round($cbm, 3).' CBM',
$cbm,
$price_cbm
$price_cbm,
$taxPercentage
);
$this->createsTransactionDetail->execute($invoice_transaction, $object_detail);
@@ -206,7 +220,8 @@ class CreateInvoiceTransactionProcessor
'OVER_WEIGHT_CHARGES',
TransactionDetailType::OVER_WEIGHT_CHARGES,
$over_weight_cbm,
$price_cbm
$price_cbm,
$taxPercentage
);
$this->createsTransactionDetail->execute($invoice_transaction, $object_detail);
@@ -217,7 +232,8 @@ class CreateInvoiceTransactionProcessor
'MIN_CBM_CHARGES',
TransactionDetailType::MIN_CBM_CHARGES,
$minimum_charge,
$price_cbm
$price_cbm,
$taxPercentage
);
$this->createsTransactionDetail->execute($invoice_transaction, $object_detail);
@@ -9,6 +9,7 @@ use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\SegmentConstants;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\TaxPercentage;
use App\Models\Order;
class CreateShippingCostTransactionProcessor
@@ -57,7 +58,8 @@ class CreateShippingCostTransactionProcessor
TransactionType::SHIPPING_COST,
'Shipping Cost',
$quantity,
$totalShippingCost/$totalCBM
$totalShippingCost/$totalCBM,
TaxPercentage::SIX_PERCENT
);
$shippingCostTransaction = $this->createsShippingCostTransaction->execute($order, $transactionObject, $transactionDetailObject);
@@ -16,6 +16,8 @@ use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class CreateStorageInvoiceDocTransactionFixProcessor
{
@@ -51,9 +53,17 @@ class CreateStorageInvoiceDocTransactionFixProcessor
/** @var Transaction $invoice_transaction */
$invoice_transaction = $packingList->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->whereIn('status', [ApprovalStatus::COMPLETED])->first();
// $this->updatesTransactionStatus->execute($invoice_transaction, ApprovalStatus::APPROVED);
// $this->updatesTransactionStatus->execute($invoice_transaction, ApprovalStatus::APPROVED);
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
Log::info('$dateToCompare 2: '.$dateToCompare);
$storageInvoiceTransactionCreatedDate = Carbon::parse($invoice_transaction->created_at);
Log::info('$storageInvoiceTransactionCreatedDate 2: '.$storageInvoiceTransactionCreatedDate);
if ($storageInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice_transaction->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$transaction_invoice_pdf = LaravelMpdf::loadView('pages.pdfs.shipping_invoice', ['invoice_transaction' => $invoice_transaction]);
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice_transaction]);
$document_object = new DocumentObject(
DocumentType::STORAGE_INVOICE,
@@ -16,6 +16,8 @@ use App\Classes\Modules\Documents\Services\CreatesFiles;
use App\Classes\Modules\Documents\Services\CreatesDocument;
use App\Classes\Modules\Documents\DataTransferObjects\DocumentObject;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class CreateStorageInvoiceDocTransactionProcessor
{
@@ -53,7 +55,16 @@ class CreateStorageInvoiceDocTransactionProcessor
// $this->updatesTransactionStatus->execute($invoice_transaction, ApprovalStatus::APPROVED);
$transaction_invoice_pdf = LaravelMpdf::loadView('pages.pdfs.shipping_invoice', ['invoice_transaction' => $invoice_transaction]);
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
Log::info('$dateToCompare: '.$dateToCompare);
$storageInvoiceTransactionCreatedDate = Carbon::parse($invoice_transaction->created_at);
Log::info('$storageInvoiceTransactionCreatedDate: '.$storageInvoiceTransactionCreatedDate);
if ($storageInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice_transaction->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice_transaction]);
$document_object = new DocumentObject(
DocumentType::STORAGE_INVOICE,
@@ -44,6 +44,8 @@ class CreatesShippingCostTransaction extends AbstractUpdateRelationshipRecord
$model->quantity = $transactionDetailObject->getQuantity();
$model->price = $transactionDetailObject->getPrice();
$model->amount = $transactionDetailObject->getAmount();
$model->tax_amount = $transactionDetailObject->getTaxAmount();
$model->tax_percentage = $transactionDetailObject->getTaxPercentage();
return $this->handler($transaction->transactionDetails(), $model);
@@ -5,8 +5,10 @@ namespace App\Classes\Modules\Transactions\Services;
use App\Classes\General\Eloquent\AbstractUpdateRecord;
use App\Classes\General\Eloquent\AbstractUpdateRelationshipRecord;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\PackingList;
use App\Models\Transaction;
use Carbon\Carbon;
class CreatesTransaction extends AbstractUpdateRelationshipRecord
{
@@ -35,4 +37,4 @@ class CreatesTransaction extends AbstractUpdateRelationshipRecord
return $this->handler($packing_list->transactions(), $model);
}
}
}
@@ -23,8 +23,10 @@ class CreatesTransactionDetail extends AbstractUpdateRelationshipRecord
$model->quantity = $object->getQuantity();
$model->price = $object->getPrice();
$model->amount = $object->getAmount();
$model->tax_amount = $object->getTaxAmount();
$model->tax_percentage = $object->getTaxPercentage();
return $this->handler($transaction->transactionDetails(), $model);
}
}
}
@@ -20,8 +20,10 @@ class UpdatesTransactionDetail extends AbstractUpdateRecord
$transactionDetail->quantity = $object->getQuantity();
$transactionDetail->price = $object->getPrice();
$transactionDetail->amount = $object->getAmount();
$transactionDetail->tax_amount = $object->getTaxAmount();
$transactionDetail->tax_percentage = $object->getTaxPercentage();
return $this->handler($transactionDetail);
}
}
}
@@ -5,6 +5,8 @@ namespace App\Classes\Modules\Transactions\Standards\Validators;
use App\Classes\General\Abstracts\AbstractValidation;
use App\Classes\Modules\Transactions\DataTransferObjects\WaiveTransactionObject;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
class WaiveTransactionValidation extends AbstractValidation
{
@@ -28,8 +30,8 @@ class WaiveTransactionValidation extends AbstractValidation
protected function rules(): array {
return [
'id' => 'required',
'type' => ['required', 'numeric', 'in:16'], //Only storage invoice (type 16) can be waived
'status' => ['required', 'numeric', 'in:2'], //Approve storage invoice only, paid invoice stricly forbidden
'type' => ['required', 'numeric', 'in:'.TransactionType::STORAGE_INVOICE], //Only storage invoice (type 16) can be waived
'status' => ['required', 'numeric', 'in:'.ApprovalStatus::APPROVED], //Approve storage invoice only, paid invoice stricly forbidden
// 'billNo' => 'required',
];
}
@@ -15,6 +15,7 @@ use App\Classes\Modules\Transactions\Services\CreatesTransactionableTransaction;
use App\Classes\Modules\Wallets\DataTransferObjects\WalletObject;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Wallets\Services\UpdatesWalletBalance;
use App\Models\CompanyModule;
class CreditWalletProcessor
@@ -36,6 +37,9 @@ class CreditWalletProcessor
/** @var UpdatesWallet */
private $updatesWallet;
/** @var UpdatesWalletBalance */
private $updatesWalletBalance;
/**
* CreateWalletLogic constructor.
@@ -45,6 +49,7 @@ class CreditWalletProcessor
* @param CreatesTransaction $createsTransaction
* @param CreatesTransactionableTransaction $createsTransactionableTransaction
* @param UpdatesWallet $updatesWallet
* @param UpdatesWalletBalance $updatesWalletBalance
*/
public function __construct(
GeneratesWalletCode $generatesWalletCode,
@@ -52,7 +57,8 @@ class CreditWalletProcessor
GeneratesTransactionBillNumber $generatesTransactionBillNumber,
CreatesTransaction $createsTransaction,
CreatesTransactionableTransaction $createsTransactionableTransaction,
UpdatesWallet $updatesWallet
UpdatesWallet $updatesWallet,
UpdatesWalletBalance $updatesWalletBalance
)
{
$this->generatesWalletCode = $generatesWalletCode;
@@ -61,6 +67,7 @@ class CreditWalletProcessor
$this->createsTransaction = $createsTransaction;
$this->createsTransactionableTransaction = $createsTransactionableTransaction;
$this->updatesWallet = $updatesWallet;
$this->updatesWalletBalance = $updatesWalletBalance;
}
@@ -87,11 +94,13 @@ class CreditWalletProcessor
$transaction_object = new TransactionObject($billNumber, $transactionType === 2 ? TransactionType::DEBIT_NOTE : TransactionType::CREDIT_NOTE, 1, $wallet->owner->id, 1, PaymentMethodType::CASH, $amount, $amount, 1, 1, 1, 0, 0, null, ApprovalStatus::APPROVED, [], $reference);
$transaction = $this->createsTransactionableTransaction->execute($wallet, $transaction_object);
$updateWalletAmount = $transactionType === 2 ? ($wallet->amount - $transaction->amount) : ($wallet->amount + $transaction->amount);
$this->updatesWalletBalance->execute($wallet, $transaction->amount);
$walletObject = new WalletObject($wallet->owner->id, $wallet->currency_id, $wallet->code, $updateWalletAmount);
// $updateWalletAmount = $transactionType === 2 ? ($wallet->amount - $transaction->amount) : ($wallet->amount + $transaction->amount);
$wallet = $this->updatesWallet->execute($wallet, $walletObject);
// $walletObject = new WalletObject($wallet->owner->id, $wallet->currency_id, $wallet->code, $updateWalletAmount);
// $wallet = $this->updatesWallet->execute($wallet, $walletObject);
return $wallet;
}
@@ -0,0 +1,12 @@
<?php
namespace App\Classes\ValueObjects\Constants;
final class TaxPercentage {
public const DEFAULT = 0;
public const NO_TAX = 0;
public const SIX_PERCENT = 6;
}
@@ -13,4 +13,6 @@ final class TransactionDetailType {
public const CUSTOM_CHARGES = 'Custom charges';
public const STORAGE_FEE = 'Malaysia Warehouse Storage Fee';
public const PAY_ON_BEHALF = 'Pay on behalf';
}
+14 -7
View File
@@ -58,13 +58,20 @@ class FixInvoice extends Command
foreach ($orders as $order){
$invoices = $order->transactions()->where('transactions.type', TransactionType::SHIPPING_INVOICE)->get();
foreach ($invoices as $invoice){
dump($invoice->id);
$invoice->documents()->delete();
$transaction_invoice_pdf = LaravelMpdf::loadView('pages.pdfs.shipping_invoice', ['invoice_transaction' => $invoice]);
$view = 'pages.pdfs.shipping_invoice';
$dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00'));
$shippingInvoiceTransactionCreatedDate = Carbon::parse($invoice->created_at);
if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare) && $invoice->tax > 0) {
$view = 'pages.pdfs.shipping_invoice_sst';
}
$transaction_invoice_pdf = LaravelMpdf::loadView($view, ['invoice_transaction' => $invoice]);
$document_object = new DocumentObject(
DocumentType::SHIPPING_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
@@ -72,10 +79,10 @@ class FixInvoice extends Command
ApprovalStatus::COMPLETED,
'shipping_invoice'
);
/** @var Document $document */
$document = (App()->make(CreatesDocument::class))->execute($invoice, $document_object);
(App()->make(CreatesFiles::class))->execute($document, $document_object);
}
}
@@ -0,0 +1,73 @@
<?php
namespace App\Console\Commands;
use App\Classes\Modules\Billplzs\Processors\CallbackBillplzProcessor;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Models\Transaction;
use Carbon\Carbon;
use Illuminate\Console\Command;
class OneTimeTransactionFixBillplzFailedCallback extends Command
{
/**
* The name and signature of the console command.
*
* @var string
*/
protected $signature = 'one-time-transaction-fix-billplz-failed-callback';
/**
* The console command description.
*
* @var string
*/
protected $description = 'This is a one time fix billplz failed callback for transaction with id 15205';
protected $output = null;
protected $outputArray = [];
/** @var CallbackBillplzProcessor */
private $callbackBillplzProcessor;
/**
* Create a new command instance.
*
* @return void
*/
public function __construct(CallbackBillplzProcessor $callbackBillplzProcessor)
{
parent::__construct();
$this->callbackBillplzProcessor = $callbackBillplzProcessor;
}
/**
* Execute the console command.
*
* @return int
*/
public function handle()
{
ini_set('memory_limit', '-1');
$this->outputArray = [];
$start = new Carbon();
//This transaction, 15205 has approve payment but not its owner, shipping invoice
$transaction = Transaction::whereIn('id', [15205])->first();
$this->info(Carbon::now() . ' : One time fix failled callback from billplz for transaction with id 15205 cron started.');
if($transaction && $transaction->id == 15205){
$status = ApprovalStatus::APPROVED;
$this->callbackBillplzProcessor->execute($transaction, $status);
}
$end = new Carbon();
$elapsedTime = $start->diff($end)->format('%H:%I:%S');
$this->info(Carbon::now() . ' : One time fix failled callback from billplz for transaction with id 15205 cron ended. ElapsedTime: ' . $elapsedTime);
}
}
@@ -7,6 +7,7 @@ use App\Models\PermitsReminder;
use App\Models\User;
use Carbon\Carbon;
use Illuminate\Console\Command;
use Illuminate\Support\Facades\Log;
class SendPermitsReminderEmails extends Command
{
@@ -41,23 +42,23 @@ class SendPermitsReminderEmails extends Command
*/
public function handle()
{
$now = now();
$startRange = $now->subDays(3)->startOfDay();
$endRange = $now->copy()->addDays(6)->endOfDay();
$currentDateTime = now();
$startRange = $currentDateTime->subDays(3)->startOfDay();
$endRange = $currentDateTime->copy()->addDays(6)->endOfDay();
$reminders = PermitsReminder::whereDate('reminder_date', '>=', $startRange)
->whereDate('reminder_date', '<=', $endRange)
->orWhere('reminder_date', '<', now())
->pluck('model');
$this->info($this->getTimeStamp() . json_encode($reminders));
if ($reminders->isEmpty()) {
$this->info('No reminders expiring within the specified range.');
return;
}
$users = User::whereIn(
'email',
[
// 'edmond.wuiming2021@gmail.com',
'anithagurl96@gmail.com'
]
)->get();
$this->info($this->getTimeStamp() . 'Reminders: ' . $reminders->toJson());
$users = User::whereIn('email', $this->getEmailList())->get();
foreach ($users as $user) {
$this->info($this->getTimeStamp() . 'Reminder email sent to ' . $user->email);
@@ -71,4 +72,12 @@ class SendPermitsReminderEmails extends Command
{
return '[' . Carbon::now()->format('Y-m-d H:i:s') . '] - ';
}
protected function getEmailList(): array
{
return [
'edmond.wuiming2021@gmail.com',
'anithagurl96@gmail.com'
];
}
}
@@ -3,6 +3,7 @@
namespace App\Http\Controllers\PermitsReminder;
use App\Models\PermitsReminder;
use Carbon\Carbon;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
@@ -15,14 +16,25 @@ class ListPermitsReminderController
public function list(Request $request): JsonResponse
{
$perPage = 10; // Number of items per page
$page = request('page', 1); // Get the current page from the request
$page = $request->query('page', 1); // Get the current page from the request
// Paginate the PermitsReminder model
$query = PermitsReminder::orderBy('id', 'desc');
$paginator = $query->paginate($perPage, ['*'], 'page', $page);
$paginator = PermitsReminder::orderBy('reminder_date')->paginate($perPage, ['*'], 'page', $page);
// Convert paginated data to an array
// Get current date and time
$currentDateTime = now();
// Define date range
$startRange = $currentDateTime->subDays(3)->startOfDay();
$endRange = $currentDateTime->copy()->addDays(6)->endOfDay();
// Process paginated items
$data = $paginator->items();
foreach ($data as &$item) {
// Check if the reminder_date is within the date range or after the current date
$reminderDate = Carbon::parse($item->reminder_date);
$item->show_remind = $reminderDate->between($startRange, $endRange) || $reminderDate->isBefore($currentDateTime);
}
// Create pagination links
$links = [
@@ -32,6 +44,7 @@ class ListPermitsReminderController
"next" => $paginator->nextPageUrl(),
];
// Prepare response
$response = [
"title" => "List Permits Reminder",
"message" => "You have successfully retrieved a list of Permits Reminder",
@@ -0,0 +1,20 @@
<?php
namespace App\Http\Controllers\Transactions;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use App\Classes\Modules\Transactions\ControllersLogic\DeletePaidGroupLogic;
class DeletePaidGroupController
{
/**
* @param Request $request
* @param DeleteGroupTransactionLogic $logic
* @return JsonResponse
*/
public function delete(Request $request, DeletePaidGroupLogic $logic) : JsonResponse {
return $logic->execute($request);
}
}
+1
View File
@@ -73,5 +73,6 @@ class Kernel extends HttpKernel
'storage.invoice.check.byorder' => \App\Http\Middleware\CheckForStorageInvoiceByOrderId::class,
'storage.invoice.check.bytransactions' => \App\Http\Middleware\CheckForStorageInvoiceByTransactions::class,
'storage.invoice.check.bygroup' => \App\Http\Middleware\CheckForStorageInvoiceByGroup::class,
'storage.invoice.check.bypackinglists' => \App\Http\Middleware\CheckForStorageInvoiceByPackingLists::class,
];
}
@@ -29,7 +29,12 @@ class CheckForStorageInvoiceByOrderId
public function handle(Request $request, Closure $next)
{
$orderId = $request->route('id');
$storages = $this->storageInvoiceTransactionProcessor->execute($orderId);
$storages = [];
try{
$storages = $this->storageInvoiceTransactionProcessor->execute($orderId);
} catch (\Exception $exception) {
$storages = [];
}
$request->merge(['storages' => $storages]);
return $next($request);
}
@@ -0,0 +1,69 @@
<?php
namespace App\Http\Middleware;
use Closure;
use App\Classes\Modules\Transactions\Processors\CheckStorageInvoiceTransactionProcessor;
use App\Classes\Modules\PackingLists\Services\ListsPackingLists;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Models\CompanyConnection;
use App\Models\Order;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
class CheckForStorageInvoiceByPackingLists
{
/** @var CheckStorageInvoiceTransactionProcessor */
private $storageInvoiceTransactionProcessor;
/** @var ListsPackingLists */
private $listsPackingLists;
public function __construct(CheckStorageInvoiceTransactionProcessor $storageInvoiceTransactionProcessor, ListsPackingLists $listsPackingLists)
{
$this->storageInvoiceTransactionProcessor = $storageInvoiceTransactionProcessor;
$this->listsPackingLists = $listsPackingLists;
}
/**
* Handle an incoming request.
*
* @param Request $request
* @param \Closure(\Illuminate\Http\Request): (\Illuminate\Http\Response|\Illuminate\Http\RedirectResponse) $next
* @return \Illuminate\Http\Response|\Illuminate\Http\RedirectResponse
*/
public function handle(Request $request, Closure $next)
{
$results = [];
$packinglists = null;
$filters = json_decode($request->input('filters'), true);
// $filters['type_in'] = [TransactionType::SHIPPING_INVOICE];
// if(json_encode($filters['order_by']) == '{"column":"id","DESC":true}'){
// $filters['order_by_id_desc'] = true;
// }
if(isset($filters['check_for_storage_invoice'])){
unset($filters['order_by']);
$packinglists = $this->listsPackingLists->execute($filters);
foreach($packinglists as $packingList){
if($packingList){
$order = $packingList->owner()->first();
if($order instanceof Order){
$storages = $this->storageInvoiceTransactionProcessor->executeOrder($order);
if($storages){
$results = array_merge($results, $storages);
}
}
}
}
}
$request->merge(['storages' => $results]);
return $next($request);
}
}
+14 -6
View File
@@ -23,17 +23,25 @@ class ContainerResource extends JsonResource
'container_specification' => ContainerTypes::CONTAINER_SPECIFICATION[$this->container_type],
'container_number' => $this->container_number,
'seal_reference' => $this->seal_reference,
'loading_date' => $this->loading_date ? $this->loading_date->format('d-m-Y') : $this->loading_date,
'loading_date' => optional($this->loading_date)->format('d-m-Y'),
'transport' => new TransportResource($this->transports()->first()),
'packages_count' => $this->packages()->where('packages.type', '!=', 2)->sum('quantity'),
'total_cbm' => $this->packages()->sum(DB::raw('(width/100) * (height/100) * (length/100) * quantity')),
'remarks' => RemarkResource::collection($this->remarks),
'status' => $this->status,
'packing_lists' => $this->whenLoaded('packingLists', PackingListResource::collection($this->whenLoaded('packingLists', function(){
return $this->packingLists()->get()->sortBy(function ($packingList) {
return $packingList->owner->company_module_id;
});
})))
'packing_lists' => $this->shouldIncludePackingListData($request) ? $this->getSortedPackingLists() : null,
];
}
protected function shouldIncludePackingListData($request)
{
return (isset($request->all()['with_packing_list_data']) && ($request->all()['with_packing_list_data'] == false)) ? false : true;
}
protected function getSortedPackingLists()
{
return $this->whenLoaded('packingLists', PackingListResource::collection(
$this->packingLists()->get()->sortBy(fn ($packingList) => $packingList->owner->company_module_id)
));
}
}
@@ -26,7 +26,7 @@ class GroupForOrderV2Resource extends JsonResource
'original_currency' => new CurrencyResource($this->original_currency),
'issuer_name' => $this->issuerCompany->name,
'issuer_id' => $this->issuerCompany->id,
'amount' => (float) $this->amount,
'amount' => (float) $this->amount, //cief todo: 58
'service_charge' => (float) $this->amount,
'currency' => new CurrencyResource($this->currency),
'created_at' => Carbon::parse($this->created_at)->format('d-m-Y h:i:s A'),
@@ -40,8 +40,10 @@ class GroupForOrderV2Resource extends JsonResource
'payment_transaction' => $payment_transaction ? [
'id' => $payment_transaction->id,
'status' => $payment_transaction->status,
'status_name' => ApprovalStatus::APPROVAL_STATUS_ID[$payment_transaction->status]
] : []
'status_name' => ApprovalStatus::APPROVAL_STATUS_ID[$payment_transaction->status],
'bill_no' => $payment_transaction->bill_no,
'updated_at' => Carbon::parse($payment_transaction->updated_at)->format('d-m-Y h:i:s A'),
] : null
];
}
}
@@ -0,0 +1,57 @@
<?php
namespace App\Http\Resources;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\RoleTypes;
use App\Models\Order;
use Illuminate\Http\Resources\Json\JsonResource;
class ListPackingListJobWithStorageResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$exceptionUsers = in_array($this->userInfo ? $this->userInfo->type : Auth()->user()->type, [RoleTypes::SHADOW_ADMIN, RoleTypes::SUPER_ADMIN]);
$packages = !$this->packingLists()->exists() || $exceptionUsers ? $this->packages : $this->packingLists->first()->packages;
$shippingTransaction = $this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereNotIn('status', [ApprovalStatus::SUSPENDED, ApprovalStatus::EXPIRED])->first();
$transactions = $this->transactions()->whereNotIn('transactions.status', [0, 1])->whereIn('transactions.type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])->get();
$storages = [];
if($this->storages){
$transactionId = $shippingTransaction->id;
$filteredStorages = array_filter($this->storages, function ($storage) use ($transactionId) {
return isset($storage['parentInvoiceId']) && $storage['parentInvoiceId'] == $transactionId;
});
$storages = $filteredStorages;
}
return [
'id' => $this->id,
'claimant_id' => $this->claimant_id,
'reference' => $this->reference,
'status' => $this->status,
'transport' => new TransportResource($this->transports()->first()),
'type' => $this->type,
// 'receive_packing_list' => $this->when($this->type === PackingListType::SHIPPING_PACKING_LIST, new PackingListV2Resource(PackingList::where('reference', $this->reference)->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST)->first(), $this->userInfo)),
// 'packages' => PackageResource::collection($packages),
// $this->mergeWhen($this->owner instanceof Order, [
// 'order' => New OrderResource($this->owner)
// ]),
'container' => new ContainerResource($this->containers->first()),
'packages' => PackageWithoutOrderResource::collection($packages),
$this->mergeWhen($this->owner instanceof Order, [ 'order' => New OrderResource($this->owner) ]),
'shipping_transaction' => count($storages) == 0 ? new TransactionWithStorageResource($shippingTransaction): null,
'storages' => $storages,
'invoices' => TransactionWithStorageResource::collection($transactions),
'suspended_invoice' => new TransactionResource($this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereIn('status', [ApprovalStatus::SUSPENDED])->first()),
// 'suspended_invoices' => TransactionResource::collection($this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereIn('status', [ApprovalStatus::SUSPENDED])->get()),
];
}
}
@@ -0,0 +1,56 @@
<?php
namespace App\Http\Resources;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PackingListType;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\RoleTypes;
use App\Models\Order;
use App\Models\PackingList;
use Illuminate\Http\Resources\Json\JsonResource;
use Illuminate\Support\Facades\Log;
class PackingListWithStorageResource extends JsonResource
{
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
* @return array
*/
public function toArray($request)
{
$exceptionUsers = in_array(Auth()->user()->type, [RoleTypes::SHADOW_ADMIN, RoleTypes::SUPER_ADMIN]);
$packages = !$this->packingLists()->exists() || $exceptionUsers ? $this->packages : $this->packingLists->first()->packages;
$shippingTransaction = $this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereNotIn('status', [ApprovalStatus::SUSPENDED, ApprovalStatus::EXPIRED])->first();
$transactions = $this->transactions()->whereNotIn('transactions.status', [0, 1])->whereIn('transactions.type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])->get();
$storages = [];
if($this->storages){
$transactionId = $shippingTransaction->id;
$filteredStorages = array_filter($this->storages, function ($storage) use ($transactionId) {
return isset($storage['parentInvoiceId']) && $storage['parentInvoiceId'] == $transactionId;
});
$storages = $filteredStorages;
}
return [
'id' => $this->id,
'claimant_id' => $this->claimant_id,
'reference' => $this->reference,
'status' => $this->status,
'transport' => new TransportResource($this->transports()->first()),
'type' => $this->type,
'receive_packing_list' => $this->when($this->type === PackingListType::SHIPPING_PACKING_LIST, new PackingListResource(PackingList::where('reference', $this->reference)->where('type', PackingListType::WAREHOUSE_RECEIVE_LIST)->first())),
'packages' => PackageResource::collection($packages),
$this->mergeWhen($this->owner instanceof Order, [
'order' => New OrderResource($this->owner)
]),
'shipping_transaction' => count($storages) == 0 ? new TransactionWithStorageResource($shippingTransaction): null,
'storages' => $storages,
'invoices' => TransactionWithStorageResource::collection($transactions),
'suspended_invoice' => new TransactionResource($this->transactions()->where('type', TransactionType::SHIPPING_INVOICE)->whereIn('status', [ApprovalStatus::SUSPENDED])->first()),
];
}
}
+2 -2
View File
@@ -52,7 +52,7 @@ class TransactionResource extends JsonResource
'documents' => $groupTransactions ? DocumentResource::collection($this->documents->where('status', ApprovalStatus::PENDING_VERIFICATION)) : DocumentResource::collection($this->documents),
'type' => (int) $this->type,
'bill_no' => $this->bill_no,
'amount' => (double) $this->amount,
'amount' => (double) $this->amount, //cief todo: 58
'payment_method' => (int) $this->payment_method,
'payment_reference' => $this->payment_reference,
'outstanding' => (double) $this->amount - ($this->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount')),
@@ -78,7 +78,7 @@ class TransactionResource extends JsonResource
->get()
),
'remarks' => RemarkResource::collection($this->remarks),
'expires_on' => Carbon::parse($this->expires_on)->format('d-m-Y h:s:i'),
'expires_on' => Carbon::parse($this->expires_on)->format('d-m-Y h:i:s A'),
'updated_at' => Carbon::parse($this->updated_at)->format('d-m-Y'),
'created_at' => Carbon::parse($this->created_at)->format('d-m-Y')
];
@@ -59,7 +59,7 @@ class TransactionWithStorageResource extends JsonResource
if ($ts) {
$paymentTransaction = Transaction::where('payment_reference', $ts->reference)->whereIn('status', [ApprovalStatus::PENDING_SUBMISSION])->first();
if($paymentTransaction){
$groupTotalAmount = (double) $this->amount;
$groupTotalAmount = (double) $this->amount; //cief todo: 58
foreach ($group_payment_history as $key => $value) {
if ($value->id === $ts->id && $value->reference === $ts->reference) {
@@ -88,10 +88,10 @@ class TransactionWithStorageResource extends JsonResource
'documents' => $groupTransactions ? DocumentResource::collection($this->documents->where('status', ApprovalStatus::PENDING_VERIFICATION)) : DocumentResource::collection($this->documents),
'type' => (int) $this->type,
'bill_no' => $this->bill_no,
'amount' => (double) $this->amount,
'amount' => (double) $this->amount, //cief todo: 58
'payment_method' => (int) $this->payment_method,
'payment_reference' => $this->payment_reference,
'outstanding' => (double) $this->amount - ($this->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount')),
'outstanding' => (double) $this->amount - ($this->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount')), //cief todo: 58
'floating' => $group_payment_attempts ? $groupTotalAmount : (double) $this->transactions()->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::PENDING_SUBMISSION, ApprovalStatus::PENDING_VERIFICATION])->sum('amount'),
'service_charge' => (double) $this->service_charge,
'tax' => (double) $this->tax,
@@ -121,7 +121,7 @@ class TransactionWithStorageResource extends JsonResource
'remarks' => RemarkResource::collection($this->remarks),
'storages' => $this->storages ? $this->storages : null, //from middleware
'is_waived' => (int) $this->is_waived,
'expires_on' => Carbon::parse($this->expires_on)->format('d-m-Y h:s:i'),
'expires_on' => Carbon::parse($this->expires_on)->format('d-m-Y h:i:s A'),
'updated_at' => Carbon::parse($this->updated_at)->format('d-m-Y'),
'created_at' => Carbon::parse($this->created_at)->format('d-m-Y')
];
+18
View File
@@ -112,6 +112,24 @@ return [
'path' => storage_path('logs/paymentUnknownOrderLog.log'),
'level' => 'info',
],
'deletePaidGroupOrder' => [
'driver' => 'single',
'path' => storage_path('logs/deletePaidGroupOrder.log'),
'level' => 'info',
],
'vue_polling' => [
'driver' => 'single',
'path' => storage_path('logs/laravel_vue_plling.log'),
'level' => 'info',
],
'perfex_crm' => [
'driver' => 'single',
'path' => storage_path('logs/laravel_perfex_crm.log'),
'level' => 'info',
],
],
];
+8
View File
@@ -0,0 +1,8 @@
<?php
return [
// please update resources/assets/vue/app.js if value is changed
// 'qr_code_img_url' => 'https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl=', // not working
'qr_code_img_url' => 'https://qrcode.tec-it.com/API/QRCode?data=',
];
@@ -0,0 +1,65 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
class CreateTransactionLogsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::create('transaction_logs', function (Blueprint $table) {
$table->id();
$table->foreignId('transaction_id');
$table->morphs('owner');
$table->string('type')->default(TransactionType::PAYMENT);
$table->foreignId('issuer')->unsigned();
$table->foreignId('receiver')->unsigned();
$table->foreignId('recipient_bank_account_id')->unsigned();
$table->string('payment_method')->nullable();
$table->string('payment_reference')->nullable();
$table->string('bill_no')->unique();
$table->decimal('amount', 25, 5)->default(0.00);
$table->decimal('original_amount', 25, 5)->default(0.00);
$table->foreignId('currency_id')->unsigned();
$table->foreignId('original_currency_id')->unsigned();
$table->decimal('currency_rate', 14, 5)->default(0.00);
$table->decimal('tax', 14, 5)->default(0.00);
$table->decimal('service_charge', 14, 5)->default(0.00);
$table->timestamp('expires_on')->nullable();
$table->integer('status')->default(ApprovalStatus::PENDING_SUBMISSION);
$table->softDeletes();
$table->timestamps();
$table->foreign('transaction_id')->references('id')->on('transactions');
$table->foreign('currency_id')->references('id')->on('currencies');
$table->foreign('issuer')->references('id')->on('company_modules');
$table->foreign('receiver')->references('id')->on('company_modules');
$table->foreign('original_currency_id')->references('id')->on('currencies');
});
//In-case the model name lengthy
Schema::table('transaction_logs', function (Blueprint $table) {
$table->string('owner_type', 250)->change();
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::dropIfExists('transaction_logs');
}
}
@@ -0,0 +1,36 @@
<?php
use Illuminate\Database\Migrations\Migration;
use Illuminate\Database\Schema\Blueprint;
use Illuminate\Support\Facades\Schema;
class AddColumnsToTransactionDetailsTable extends Migration
{
/**
* Run the migrations.
*
* @return void
*/
public function up()
{
Schema::table('transaction_details', function (Blueprint $table) {
$table->decimal('tax_amount', 14, 5)->after('amount')->default(0.00);
$table->decimal('tax_percentage', 6, 2)->after('tax_amount')->default(0.00);
$table->decimal('discount', 14, 5)->after('tax_percentage')->default(0.00);
});
}
/**
* Reverse the migrations.
*
* @return void
*/
public function down()
{
Schema::table('transaction_details', function (Blueprint $table) {
$table->dropColumn('tax_amount');
$table->dropColumn('tax_percentage');
$table->dropColumn('discount');
});
}
}
+3
View File
@@ -24,6 +24,9 @@ import closable from './general/directives/closable';
import Avatar from 'vue-avatar';
// define global variable
Vue.prototype.$qr_code_img_url = 'https://qrcode.tec-it.com/API/QRCode?data=';
/** Application Injections */
Vue.use(vuelidate);
Vue.use(VueTheMask);
@@ -8,7 +8,7 @@
<div class="col">
<h5 class="all-caps">Update Credit Term Customer</h5>
<div class="fs-11">Are you sure you want to update the credit term status for this company to <b>{{ data.is_credit_term === 1 ? 'NO' : 'YES' }}</b>?</div>
<p class="fs-11 text-danger" v-if="data.is_credit_term === 0">All existing invoices for storage that have not yet been paid will be waived</p>
</div>
</div>
<div class="row">
@@ -1,5 +1,5 @@
<template>
<div class="row m-t-5">
<div class="row m-t-5" @keyup.enter="submitForm">
<div class="col">
<validation-wrapper-component :validator="$v.parameters.content">
<input type="text" class="form-control fs-12" placeholder="Write your comments..." v-model.trim="parameters.content">
@@ -42,7 +42,7 @@
submitForm() {
this.submit(this.data ? this.route('api.remark.update', this.data.id) : this.route('api.packing_list.container.remark.create', this.id), this.data ? 'put' : 'post', this.section, true, true);
this.$emit('submit')
}
},
},
mixins: [modalFormHandler]
}
@@ -0,0 +1,229 @@
<template>
<div class="row">
<div class="col">
<div class="row" v-if="container">
<div class="col">
<div class="row align-items-center m-t-10">
<div class="col bg-master-lightest rounded padding-20 m-l-10 m-r-10">
<div class="row d-flex justify-content-between align-items-center">
<div class="col b-r">
<div class="row">
<div class="col">
<p class="m-b-0 large-text normal m-b-10">Container Number</p>
</div>
</div>
<div class="row">
<div class="col">
<p class="m-t-0 m-b-0 fs-20 bold">{{ container.container_reference }}</p>
<p class="m-t-0 m-b-0 small-text">{{ container.container_number }}</p>
<p class="m-t-0 m-b-0 small-text">seal number</p>
</div>
</div>
</div>
<div class="col">
<div class="row">
<div class="col">
<p class="fs-10 bold m-b-0">ETD</p>
<p class="small-text m-t-0">{{ container.transport.current_schedule.etd }} <a class="b-rad-none all-caps requestModal" data-type="rescheduleDate"><i class="fa fa-edit pointer fa-fw fs-15 m-l-5"></i></a>
</p>
</div>
</div>
<div class="row">
<div class="col">
<p class="fs-10 bold m-b-0">ETA</p>
<p class="small-text m-t-0">{{ container.transport.current_schedule.eta }} <a class="b-rad-none all-caps requestModal" data-type="rescheduleDate"><i class="fa fa-edit pointer fa-fw fs-15 m-l-5"></i></a>
</p>
</div>
</div>
</div>
<div class="col">
<div class="row">
<div class="col">
<p class="fs-10 bold m-b-0">Location</p>
<p class="small-text m-t-0">-tbc-</p>
</div>
</div>
<div class="row">
<div class="col">
<p class="fs-10 bold m-b-0">Destination</p>
<p class="small-text m-t-0">-tbc-</p>
</div>
</div>
</div>
<div class="col">
<div class="row">
<div class="col">
<p class="fs-10 bold m-b-0">Container Type</p>
<p class="small-text m-t-0">{{ container.container_specification.name }}</p>
</div>
</div>
<div class="row">
<div class="col">
<p class="fs-10 bold m-b-0">Owner</p>
<p class="small-text m-t-0">-tbc-</p>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row m-t-10 m-b-50">
<div class="col">
<div class="row">
<div class="col">
<div class="row h-100">
<div class="col">
<h5 class="m-b-5 large-text bold l-20">Tracking:</h5>
<div class="row padding-10">
<div class="col rounded bg-master-lighter padding-15">
<li class="m-t-10">
<a class="btn btn-sm btn-primary b-rad-none all-caps requestModal"
data-type="containerDepature">Container Departure</a>
</li>
<li class="m-t-10">
<a class="btn btn-sm btn-primary b-rad-none all-caps requestModal"
data-type="containerArrival">Arrival Date</a>
</li>
<li class="m-t-10">
<a class="btn btn-sm btn-primary b-rad-none all-caps requestModal"
data-type="containerUnpacking">Date of Unpacking</a>
</li>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in"
type="rescheduleDate">
<reschedule-date-form-component :section="section"
:data="container"></reschedule-date-form-component>
</modal-component>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in"
type="containerDepature">
<container-depature-form-component :section="section"
:data="container"></container-depature-form-component>
</modal-component>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in"
type="containerArrival">
<container-arrival-form-component :section="section"
:data="container"></container-arrival-form-component>
</modal-component>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in"
type="containerUnpacking">
<container-unpacking-form-container :section="section"
:data="container"></container-unpacking-form-container>
</modal-component>
<div class="row m-t-10">
<div class="col">
<div class="row">
<div class="col-auto padding-5 m-l-15 m-r-15 pointer" :class="[{ 'text-primary': tabShowing === 'Comments' }, { 'b-b': tabShowing === 'Comments' }]" @click="tabShowing = 'Comments'">
<h5 class="large-text bold l-20" :class="[{ 'text-primary': tabShowing === 'Comments' }]"> Comments</h5>
</div>
<!-- <div class="col-auto padding-5 m-l-15 m-r-15 pointer" :class="[{ 'text-primary': tabShowing === 'Timeline' }, { 'b-b': tabShowing === 'Timeline' }]" @click="tabShowing = 'Timeline'">
<h5 class="large-text bold l-20" :class="[{ 'text-primary': tabShowing === 'Timeline' }]"> Activity Timeline</h5>
</div> -->
</div>
<div class="row p-l-10 p-r-10">
<div class="col rounded padding-15">
<div class="row" v-if="tabShowing === 'Comments'">
<div class="col">
<div class="row" v-for="remarks in container.remarks">
<div class="col">
<container-comment-component :section="section" :data="remarks"></container-comment-component>
</div>
</div>
<container-comment-form-component :section="section" :id="container.id"></container-comment-form-component>
</div>
</div>
<div class="row" v-if="tabShowing === 'Timeline'">
<div class="col">
<div class="row align-items-center justify-content-center p-t-50 p-b-50">
<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 hide">
<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>
</div>
</div>
</div>
</div>
</template>
<script>
export default {
props: {
id: {
type: Number,
required: true,
}
},
data() {
return {
section: 'containerPofileSection',
isLoading: true,
container: null,
expanded: false,
CBMcapacity: 30,
// tabShowing: 'Timeline',
tabShowing: 'Comments',
selectAllPackingList: false,
selectedPackageList: [],
deleteCommentId: '',
}
},
computed: {
pendingQueue() {
return this.$store.getters.isInCompleteQueue(this.section);
},
loadedCBM() {
return (Math.ceil((this.container.packing_lists.reduce((total, obj) => total + obj.packages.reduce((total, obj) => obj.cbm + total, 0), 0)) * 1000) / 1000).toFixed(3)
},
},
watch: {
pendingQueue(inComplete) {
if (inComplete) {
this.fetchCompany();
}
}
},
created() {
this.$store.dispatch('updateListQueue', { 'name': this.section });
},
methods: {
fetchCompany() {
this.isLoading = true;
this.submit(route('api.packing_list.container.show', this.id) + '?with_packing_list_data=0', 'get', this.section, false, false)
},
successHandler(response) {
this.$store.dispatch('completeList', { 'name': this.section, 'data': [] });
this.isLoading = false;
this.container = response.payload.data;
},
}
}
</script>
@@ -5,9 +5,10 @@
<div class="col-6 no-padding">
<div class="row">
<div class="col">
<a :href="route('order.qr.download', item.id)" target="_blank">
<a :href="route('order.qr.download', item.id)" target="_blank" class="d-flex justify-content-center allign-items-center">
<div class="peelable-corner overflow-hidden relative">
<img :src="'https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl={id:'+item.id+'}'" class="w-100">
<!-- <img :src="'https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl={id:'+item.id+'}'" class="w-100"> -->
<img :src="this.$qr_code_img_url + item.id + '}'" class="w-100" style="max-width: 150px; max-height: 150px;">
</div>
</a>
</div>
@@ -47,7 +47,7 @@
</div>
</div>
</div>
<div class="row b-b b-grey p-b-20 align-items-center">
<div class="row b-b b-grey p-b-20 align-items-center parentContainer">
<div class="col">
<div class="row m-b-5">
<div class="col-auto">
@@ -58,9 +58,48 @@
<small class="fs-10 all-caps muted">Status</small>
<p class="no-margin bold">{{item.container ? item.container.transport.schedule_complete && status === 'Shipping' ? 'Custom Clearance' : status : status}}</p>
</div>
<div class="col-auto" v-if="$store.getters.isAdmin">
<small class="fs-10 all-caps muted">Container</small>
<p class="no-margin bold">{{item.container ? item.container.container_reference : '-'}}</p>
<div class="col" v-if="$store.getters.isAdmin">
<div class="row h-100 justify-content-center align-items-center">
<div class="col">
<small class="fs-10 all-caps muted">Container</small>
<p class="no-margin bold">{{ item.container ? item.container.container_reference : '-' }}</p>
</div>
<div class="col-auto" v-if="$store.getters.isAdmin && item.container">
<i class="fa fa-comment fs-15 pointer requestModal" data-type="commentsModal"></i>
<modal-component type="commentsModal" styleType="fill-in">
<div class="row">
<div class="col bg-white b-rad-lg p-t-10 p-t-10 p-l-40 p-r-40">
<h4 class="m-b-20">Remarks</h4>
<div class="row" v-if="item.container.remarks.length">
<div class="col">
<div class="row" v-for="remarks in item.container.remarks">
<div class="col">
<container-comment-component :section="section" :data="remarks"></container-comment-component>
</div>
</div>
</div>
</div>
<div class="row align-items-center justify-content-center p-t-50 p-b-50" v-else>
<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 Yet!</p>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
</modal-component>
</div>
</div>
</div>
</div>
<div class="row">
@@ -12,7 +12,8 @@
<div class="col-10">
<a :href="route('order.qr.download', order.id)" target="_blank">
<div class="peelable-corner overflow-hidden relative">
<img :src="'https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl={id:'+order.id+'}'" class="w-100">
<!-- <img :src="'https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl={id:'+order.id+'}'" class="w-100"> -->
<img :src="this.$qr_code_img_url + order.id + '}'" class="w-100">
</div>
</a>
</div>
@@ -12,7 +12,8 @@
<div class="col-10">
<a :href="route('order.qr.download', order.id)" target="_blank">
<div class="peelable-corner overflow-hidden relative">
<img :src="'https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl={id:'+order.id+'}'" class="w-100">
<!-- <img :src="'https://chart.googleapis.com/chart?chs=150x150&cht=qr&chl={id:'+order.id+'}'" class="w-100"> -->
<img :src="this.$qr_code_img_url + order.id + '}'" class="w-100">
</div>
</a>
</div>
@@ -79,7 +80,7 @@
<h6 class="no-margin">
<div class="row">
<div class="col-12 col-sm-auto pr-sm-0"><b>Delivery Address:</b>&nbsp;</div>
<div class="col-12 col-sm-auto pl-sm-0">{{order.address.reference}} <i class="fa fa-info-circle m-l-10" v-tooltip:right="order.address.street_one+' '+(order.address.street_two ? order.address.street_two : '')+', '+ order.address.district.name+', '+order.address.post_code+' '+order.address.state.name+', '+order.address.country.name" ></i></div>
<div class="col-12 col-sm-auto pl-sm-0">{{order.address.reference}} <i class="fa fa-info-circle m-l-10" v-tooltip:right="order.address.street_one + ' ' + (order.address.street_two ? order.address.street_two : '') + ', ' + (order.address.district ? order.address.district.name : '') + ', ' + order.address.post_code + ' ' + (order.address.state ? order.address.state.name : '') + ', ' + (order.address.country ? order.address.country.name : '')"></i></div>
</div>
</h6>
</div>
@@ -149,7 +150,7 @@
</div>
<div class="row bg-master-lightest p-t-15" v-for="invoice in order.invoices" v-if="invoice.type === 1">
<div class="col" v-if="getMergedInvoices(invoice).length > 1">
<customer-payments-billing-variant-2-component :data="getMergedInvoices(invoice)" :storage="getStorageInfo(invoice)" invoice_status="Pending Payment" :section="section"></customer-payments-billing-variant-2-component>
<customer-payments-billing-with-storage-component :data="getMergedInvoices(invoice)" :storage="getStorageInfo(invoice)" invoice_status="Pending Payment" :section="section"></customer-payments-billing-with-storage-component>
</div>
<div class="col" v-else>
<customer-payments-billing-component :data="invoice" invoice_status="Pending Payment" :section="section"></customer-payments-billing-component>
@@ -215,6 +216,11 @@
this.isLoading = false;
this.order = response.payload.data;
},
errorHandler(error, status){
if(status == 404){
window.location.href = this.route('error.404');
}
},
getStorageInfo(invoice) {
const storageObject = this.findStorageInfoObject(invoice.id);
return storageObject;
@@ -34,17 +34,13 @@
</div>
</div>
</div>
<!-- CIEF TODO: For easy revert to old code -->
<list-component :key="currentKey" :section="section" :endpoint="route('api.packing_list.list')" :options="options">
<template slot="list" slot-scope="{data}">
<admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></admin-payments-billing-component>
<single-parent-admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></single-parent-admin-payments-billing-component>
<!-- <admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></admin-payments-billing-component> -->
<!-- AdminPaymentsBillingComponent.vue deleted to avoid confusion -->
</template>
</list-component>
<!-- <list-polling-component :key="currentKey" :section="section" :endpoint="route('api.packing_list.list.job')" :options="options">
<template slot="list" slot-scope="{data}">
<admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></admin-payments-billing-component>
</template>
</list-polling-component> -->
</div>
</div>
</template>
@@ -34,15 +34,10 @@
</div>
</div>
</div>
<!-- CIEF TODO: For easy revert to old code -->
<!-- <list-component :key="currentKey" :section="section" :endpoint="route('api.packing_list.list')" :options="options">
<template slot="list" slot-scope="{data}">
<admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></admin-payments-billing-component>
</template>
</list-component> -->
<list-polling-component :key="currentKey" :section="section" :endpoint="route('api.packing_list.list.job')" :options="options">
<template slot="list" slot-scope="{data}">
<single-admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></single-admin-payments-billing-component>
<!-- <single-admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></single-admin-payments-billing-component> -->
<single-parent-admin-payments-billing-component :data="data" :invoice_status="invoice_status" :section="section" ></single-parent-admin-payments-billing-component>
</template>
</list-polling-component>
</div>
@@ -84,10 +84,13 @@
</div>
<div class="col-auto p-l-0 p-r-0 d-flex justify-content-center align-items-center" v-if="$store.getters.isSuperAdmin">
<span class="d-inline-block m-r-15 text-primary bold text-underline pointer requestModal" style="min-width:15px;" :data-type="'regenerateStorageInvoice-' + item.id" v-if="item.type === 16">
<span class="d-inline-block m-r-15 text-primary bold text-underline pointer requestModal" style="min-width:15px;" :data-type="'regenerateStorageInvoice-' + item.id" v-if="item.type === 16 && item.status === 3">
<i class="fa fa-repeat"></i>
</span>
<span class="d-inline-block m-r-15 text-primary bold text-underline pointer requestModal" style="min-width:15px;" :data-type="'regenerateShippingInvoice-' + item.id" v-else>
<span class="d-inline-block m-r-15 text-primary bold text-underline pointer requestModal" style="min-width:15px;" v-if="item.type === 16 && item.status !== 3">
<i class="fa fa-ban"></i>
</span>
<span class="d-inline-block m-r-15 text-primary bold text-underline pointer requestModal" style="min-width:15px;" :data-type="'regenerateShippingInvoice-' + item.id" v-if="item.type === 1">
<i class="fa fa-repeat"></i>
</span>
@@ -274,7 +277,7 @@
<div class="font-heading fs-12">MYR {{(Math.round((totalOutstanding + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row m-t-20" v-if="totalOutstanding - totalFloating > 0.009">
<div class="row m-t-20" v-if="totalOutstanding - totalFloating > 0.009 && !groupPaymentPending">
<div class="col">
<div class="btn btn-sm all-caps b-rad-none btn-success btn-block requestModal" data-type="makePayment">Make Payment</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="makePayment">
@@ -342,6 +345,20 @@
});
return ids;
},
groupPaymentPending(){
if (Array.isArray(this.items)) {
for (let i = 0; i < this.items.length; i++) {
for (let j = 0; j < this.items[i].groups_payment_history.length; j++) {
const item = this.items[i].groups_payment_history[j];
// console.log('item', JSON.stringify(item));
if (item.payment_transaction && item.payment_transaction.status === 1) {
return true;
}
}
}
}
return false;
}
},
methods: {
getLatestComment(item) {
@@ -353,6 +370,7 @@
},
groupTransactionsExist(items, groups) {
return groups.some(group =>
group.payment_transaction &&
group.transactions_ids.length === items.length &&
group.transactions_ids.every(transaction =>
items.some(item => item.id === transaction.transaction_id)
@@ -25,12 +25,12 @@
<i class="fa fa-repeat fs-20 text-white"></i>
</div>
</div>
<div class="col-auto requestModal" v-if="item.status != 2 && item.status != 6" data-type="deleteGroupTransaction">
<div class="col-auto requestModal" v-if="item.status != 2 && item.status != 6" data-type="deleteGroupTransactionInProgress">
<div class="btn bg-grey no-border">
<i class="fa fa-times"></i>
</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="deleteGroupTransaction">
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="deleteGroupTransactionInProgress">
<general-confirmation-form-component
contentText="Are you sure you want to delete this Group Payment?"
modalType="delete"
@@ -75,6 +75,23 @@
<i class="fa fa-repeat fs-20 text-white"></i>
</div>
</div>
<!-- <div class="col-auto requestModal" v-if="item.status == 2 && $store.getters.isSuperAdmin && false" data-type="deletePaidGroupTransaction">
<div class="btn bg-grey no-border">
<i class="fa fa-times"></i>
</div>
</div> -->
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="deletePaidGroupTransaction">
<general-confirmation-form-component
contentText="Are you sure you want to delete this Paid Group Payment?"
modalType="delete"
buttonText="Delete"
class="text-center"
:apiRoute="route('api.transaction.group.paidGroup.delete', item.id)"
apiMethod="delete"
:section="section"
>
</general-confirmation-form-component>
</modal-component>
<div class="col-auto" v-if="!['customerGroupPaymentExpiredInvoiceComponent'].includes(section)">
<div class="btn bg-grey no-border" @click="expanded = !expanded">
<i class="fa" :class="{'fa-angle-down': !expanded, 'fa-angle-up': expanded}" ></i>
@@ -85,7 +102,7 @@
</div>
<div class="row b-t b-grey p-t-10 m-l-5 m-r-5" v-show="expanded" v-if="item.invoices && !['customerGroupPaymentExpiredInvoiceComponent'].includes(section)">
<div class="col">
<payments-billing-components :section="section" v-for="invoice in data.invoices" v-bind:key="invoice.id" :data="invoice" :selectedInvoice="selectedInvoice" v-on:input="updateList($event)"></payments-billing-components>
<payments-billing-components :section="section" v-if="invoice" v-for="invoice in data.invoices" v-bind:key="invoice.id" :data="invoice" :selectedInvoice="selectedInvoice" v-on:input="updateList($event)"></payments-billing-components>
</div>
</div>
</div>
@@ -18,12 +18,18 @@
{{item.currency.short_code}} {{(Math.round((item.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
<div class="col-auto p-l-0">
<div class="col-auto p-l-0" v-if="item.bill_no">
<div class="font-heading fs-8 muted all-caps">Bill Number</div>
<div class="font-heading fs-10 bold">
{{ item.bill_no }}
</div>
</div>
<div class="col-auto p-l-0" v-else-if="item.payment_transaction && $store.getters.isAdmin">
<div class="font-heading fs-8 muted all-caps">Bill Number</div>
<div class="font-heading fs-10 bold">
{{ item.payment_transaction.bill_no }}
</div>
</div>
</div>
</div>
</div>
@@ -50,10 +50,10 @@
</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="deleteInvoiceFunction">
<general-confirmation-form-component
contentText="Are you sure you want to delete this Payment?"
modalType="delete"
buttonText="Delete"
<general-confirmation-form-component
contentText="Are you sure you want to delete this Payment?"
modalType="delete"
buttonText="Delete"
class="text-center"
:apiRoute="route('api.transaction.payment.delete', item.id)"
apiMethod="delete"
@@ -80,7 +80,7 @@
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps fs-10 bold">Maybank: <span class="text-complete">562237009234</span></div>
<div class="font-heading all-caps fs-10 bold">Maybank: <span class="text-complete">568603010762</span></div>
</div>
</div>
<div class="row">
@@ -181,7 +181,11 @@
},
methods: {
clickExpand(){
this.expandPaymentDetails = !this.expandPaymentDetails;
if(this.item
&& ((this.item.payment_method !== 5 && this. item.documents.length)
|| (this.item.payment_method === 5 && (this.item.status === 2 || this.item.status === 3)))){
this.expandPaymentDetails = !this.expandPaymentDetails;
}
},
},
mixins: [componentHandler]
@@ -0,0 +1,294 @@
<template>
<div class="row m-b-15 m-l-5 m-r-10 parentContainer">
<div class="col bg-white rounded">
<div v-for="singleInvoice in invoices" class="row">
<div class="col padding-20">
<div class="row align-items-center">
<div class="col">
<p class="no-margin fs-10 all-caps">Marking</p>
<div class="no-margin">
<div v-if="item.order">
<a :href="route('customer.profile', item.order.company_module.marking)">{{item.order.company_module.marking}}</a>/<a :href="route('order.show', item.order.reference)">{{item.order.reference}}</a>
<p>{{item.loading_days_ago}}</p>
</div>
<div v-else class="text-danger">Unclaimed Packing List</div>
</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Container</p>
<div v-if="item.packages[0].container"> {{item.packages[0].container.container_reference}}</div>
<div v-else-if="item.container"> {{item.container.container_reference}}</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Invoice Date</p>
<div v-if="singleInvoice">({{ singleInvoice.bill_no }})</div>
<div v-if="!singleInvoice">n/a</div>
<div v-if="singleInvoice"> {{ singleInvoice.updated_at }}</div>
</div>
<div class="col">
<div v-if="item.order">
<p class="no-margin fs-10 all-caps">Address</p>
<div>{{ item.order.address.post_code_area}}</div>
<div>{{ item.order.address.district.name +' '+item.order.address.postcode+' '+item.order.address.state.name }}</div>
</div>
<div v-else class="text-danger">Unclaimed</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Status</p>
<div class="all-caps">{{ invoice_status }}</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Amount</p>
<div v-if="!singleInvoice">n/a</div>
<div v-if="singleInvoice">MYR {{ singleInvoice.amount.toFixed(2) }}</div>
</div>
<div class="col-auto p-l-0 p-r-0" v-if="['Pending Payment', 'Paid Invoice', 'Suspended Invoice'].includes(invoice_status)">
<div v-if="singleInvoice">
<div v-if="singleInvoice.documents.length">
<div v-for="file in singleInvoice.documents[0].files" v-bind:key="file.id" class="col-auto no-padding">
<document-file-viewer-component :file="file">
<template slot="button">
<div class="btn bg-grey no-border muted">
<i class="fa fa-file-pdf-o"></i>
</div>
</template>
</document-file-viewer-component>
</div>
</div>
<div v-else>
<div class="btn bg-grey no-border muted invisible">
<i class="fa fa-file-pdf-o"></i>
</div>
</div>
</div>
</div>
<div class="col-auto">
<div class="row text-center parentContainer m-b-10" v-if="['Pending Invoice'].includes(invoice_status) && !item.receive_packing_list" >
<div class="col">
<div class="requestModal pointer btn btn-primary btn-xs" data-type="addWarehouseTransport">
Add Warehouse Transport
</div>
<modal-component class="animate_animated animatefast animate_fadeIn" styleType="fill-in" type="addWarehouseTransport">
<create-warehouse-transport-form-component :packinglistId="item.id" :section="section"></create-warehouse-transport-form-component>
</modal-component>
</div>
</div>
<div class="row">
<div class="col">
<div class="btn bg-grey no-border" @click="expanded = !expanded" v-if="['Pending Approval', 'Pending Payment'].includes(invoice_status)">
<i class="fa" :class="{'fa-angle-down': !expanded, 'fa-angle-up': expanded}" ></i>
</div>
<div class="btn bg-grey no-border muted requestModal" v-if="singleInvoice && invoice_status == 'Pending Approval'" data-type="confirmInvoice">
<i class="fa fa-check fs-12"></i>
</div>
<div class="btn bg-grey no-border muted requestModal" v-if="singleInvoice && invoice_status == 'Pending Approval'" data-type="deleteInoive">
<i class="fa fa-close fs-12"></i>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="confirmInvoice">
<approve-shipping-invoice-form-component :section="section" :data="data"></approve-shipping-invoice-form-component>
</modal-component>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="deleteInoive">
<delete-shipping-invoice-form-component :section="section" :data="data"></delete-shipping-invoice-form-component>
</modal-component>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row b-t b-grey p-t-10 m-l-5 m-r-5" v-show="expanded" v-if="invoice_status == 'Pending Payment'">
<div class="col-12 col-md-7 padding-20">
<div class="row bg-master-lightest h-100">
<div class="col">
<div v-for="(groupItem, index) in invoices" class="row bg-master-lightest" v-if="groupItem.groups_payment_attempts.length && groupItem.type == 1 && groupTransactionsExist(invoices, groupItem.groups_payment_attempts)">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
<div v-if="index === 0" class="font-head fs-10 all-caps">Payment Attempt</div>
</div>
</div>
<div class="row">
<div class="col">
<single-group-payment-transaction-details-component v-for="group in groupItem.groups_payment_attempts" v-bind:key="group.id" :data="group" :section="section"></single-group-payment-transaction-details-component>
</div>
</div>
</div>
</div>
<div v-for="(groupItem, index) in invoices" class="row bg-master-lightest" v-if="groupItem.groups_payment_expired.length && groupItem.type == 1 && groupTransactionsExist(invoices, groupItem.groups_payment_expired)">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
<div v-if="index === 0" class="font-head fs-10 all-caps">Payment Expired</div>
</div>
</div>
<div class="row">
<div class="col">
<payment-expired-component v-for="group in groupItem.groups_payment_expired" v-bind:key="group.id" :data="group" :section="section"></payment-expired-component>
</div>
</div>
</div>
</div>
<div v-for="(groupItem, index) in invoices" class="row bg-master-lightest" v-if="groupItem.groups_payment_history.length && groupItem.type == 1 && groupTransactionsExist(invoices, groupItem.groups_payment_history)">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
<div v-if="index === 0" class="font-head fs-10 all-caps">Payment History</div>
</div>
</div>
<div class="row">
<div class="col">
<single-group-payment-history-transaction-details-component v-for="group in groupItem.groups_payment_history" v-bind:key="group.id" :data="group" :section="section"></single-group-payment-history-transaction-details-component>
</div>
</div>
</div>
</div>
<div v-for="(paymentAttemptItem, index) in invoices" class="row bg-master-lightest" v-if="invoices.some(x => x.payment_attempts && x.payment_attempts.length > 0)">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
<div v-if="index === 0" class="font-head fs-10 all-caps">Payment Attempt</div>
</div>
</div>
<div class="row">
<div class="col">
<shipping-transaction-component v-for="i in paymentAttemptItem.payment_attempts" v-bind:key="i.id" :data="i" :section="section"></shipping-transaction-component>
</div>
</div>
</div>
</div>
<div v-for="(paymentExpiredItem, index) in invoices" class="row bg-master-lightest" v-if="invoices.some(x => x.payments_expired && x.payments_expired.length > 0)">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
<div v-if="index === 0" class="font-head fs-10 all-caps">Payment Expired</div>
</div>
</div>
<div class="row">
<div class="col">
<payment-expired-component v-for="i in paymentExpiredItem.payments_expired" v-bind:key="i.id" :data="i" ></payment-expired-component>
</div>
</div>
</div>
</div>
<div v-for="(paymentHistoryItem, index) in invoices" class="row bg-master-lightest" v-if="invoices.some(x => x.payment_history && x.payment_history.length > 0)">
<div class="col">
<div class="row m-t-10 m-b-10">
<div class="col">
<div v-if="index === 0" class="font-head fs-10 all-caps">Payment History</div>
</div>
</div>
<div class="row">
<div class="col">
<payment-history-component v-for="i in paymentHistoryItem.payment_history" v-bind:key="i.id" :data="i" ></payment-history-component>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="col-12 col-md-5 padding-20 parentContainer">
<div class="row bg-master-lightest h-100">
<div class="col">
<div class="row padding-10">
<div class="col">
<div class="row align-items-end m-b-10 text-complete">
<div class="col">
<div class="font-heading all-caps fs-12">Total Amount:</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-12">MYR {{(Math.round((totalAmount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row align-items-end bold text-danger">
<div class="col">
<div class="font-heading all-caps fs-12">OutStanding Total:</div>
</div>
<div class="col-auto text-right">
<div class="font-heading fs-12">MYR {{(Math.round((totalOutstanding + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}</div>
</div>
</div>
<div class="row m-t-20" v-if="totalOutstanding - totalFloating > 0.009">
<div class="col">
<div class="btn btn-sm all-caps b-rad-none btn-success btn-block requestModal" data-type="makePayment">Make Payment</div>
</div>
</div>
</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="makePayment">
<group-payment-form-component :section="section" :selectedIds="selectedIds" :sumAmount="totalOutstanding.toFixed(2)" :showManualPayment="true"></group-payment-form-component>
</modal-component>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
export default {
props: {
invoices: {
type: Array,
},
invoice_status: {
type: String,
required: true
},
section:{
type: String,
required: true
},
storage:{
type: Object
},
},
data(){
return {
parameters: {
packing_list_id: null,
transaction_details: [],
},
expanded: false,
}
},
computed: {
totalAmount() {
return this.invoices.reduce((sum, item) => sum + item.amount, 0);
},
totalOutstanding() {
return this.invoices.reduce((sum, item) => sum + item.outstanding, 0);
},
totalFloating() {
return this.invoices.reduce((sum, item) => sum + item.floating, 0);
},
selectedIds() {
const ids = [];
this.invoices.forEach(item => {
ids.push(item.id);
});
return ids;
},
},
created(){
this.parameters.packing_list_id = this.data.id;
},
methods: {
successHandler(response){
this.item = response.payload.data;
this.updateList();
},
groupTransactionsExist(items, groups) {
return groups.some(group =>
group.transactions_ids.length === items.length &&
group.transactions_ids.every(transaction =>
items.some(item => item.id === transaction.transaction_id)
)
);
}
},
mixins: [componentHandler]
}
</script>
@@ -17,11 +17,13 @@
<div class="col">
<p class="no-margin fs-10 all-caps">Container</p>
<div v-if="item.packages[0].container"> {{item.packages[0].container.container_reference}}</div>
<div v-else-if="item.container"> {{item.container.container_reference}}</div>
</div>
<div class="col">
<p class="no-margin fs-10 all-caps">Invoice Date</p>
<div v-if="item.shipping_transaction">({{ item.shipping_transaction.bill_no }})</div>
<div v-if="!item.shipping_transaction">n/a</div>
<div v-if="item.shipping_transaction"> {{ item.shipping_transaction.updated_at }}</div>
<div v-if="item.shipping_transaction">{{ item.shipping_transaction.updated_at }}</div>
</div>
<div class="col">
<div v-if="item.order">
@@ -219,6 +221,7 @@
</div>
</div>
</div>
<div class="col-12 col-md-5 padding-20 parentContainer">
<div class="row bg-master-lightest h-100">
<div class="col">
@@ -19,16 +19,16 @@
{{item.currency.short_code}} {{(Math.round((item.amount + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}}
</div>
</div>
<div class="col-auto p-l-0">
<div class="col-auto p-l-0" v-if="$store.getters.isAdmin">
<div class="font-heading fs-8 muted all-caps">Bill Number</div>
<div class="font-heading fs-10 bold">
{{ item.bill_no }}
{{ item.payment_transaction.bill_no }}
</div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading fs-8 all-caps" :class="[{'text-danger': item.payment_transaction.status === 4}, {'text-primary': item.payment_transaction.status !== 4}]">{{ item.payment_transaction.status === 2 ? 'Received' : item.payment_transaction.status === 4 ? 'Rejected' : 'Submitted'}} On: {{item.updated_at}}</div>
<div class="font-heading fs-8 all-caps" :class="[{'text-danger': item.payment_transaction.status === 4}, {'text-primary': item.payment_transaction.status !== 4}]">{{ item.payment_transaction.status === 2 ? 'Received' : item.payment_transaction.status === 4 ? 'Rejected' : 'Submitted'}} On: {{item.payment_transaction.updated_at}}</div>
</div>
</div>
</div>
@@ -81,19 +81,19 @@
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps fs-10 bold">Maybank: <span class="text-complete">562237009234</span></div>
<div class="font-heading all-caps fs-10 bold">Maybank: <span class="text-complete">568603010762</span></div>
</div>
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps fs-10 bold">Bank In Amount: <span class="text-success">{{(Math.round((parseFloat(amount) + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}} MYR</span></div>
<div class="font-heading all-caps fs-10 bold">Bank In Amount: <span class="text-success">{{(Math.round((parseFloat(item.amount) + Number.EPSILON) * 100) / 100).toFixed(2).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",")}} MYR</span></div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="row b-t b-grey" v-if="expandPaymentDetails">
<!-- <div class="row b-t b-grey" v-if="expandPaymentDetails">
<div class="col bg-white padding-15">
<div class="row">
<div class="col">
@@ -121,7 +121,7 @@
</div>
</div>
</div>
</div>
</div> -->
</div>
</div>
</template>
@@ -34,7 +34,7 @@
</div>
</div>
<modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="deleteAttempt">
<delete-payment-attempt-form-component :data="item" :section="section" class="text-center"></delete-payment-attempt-form-component>
<delete-group-payment-attempt-form-component :data="{ groupId: groupId }" :section="section" class="text-center"></delete-group-payment-attempt-form-component>
</modal-component>
<modal-component type="paymentProofModal">
<payment-verification-form-component v-if="selected_id === item.payment_transaction.id" :section="section" :data="item"></payment-verification-form-component>
@@ -55,10 +55,12 @@
bank_id: 1
},
section: 'bookingDetailSection',
groupId: 0,
}
},
mounted() {
this.item.id = this.item.payment_transaction.id;
this.groupId = this.item && this.item.transactions_ids && this.item.transactions_ids.length > 0 ? this.item.transactions_ids[0].group_id : 0;
},
methods: {
clickExpand(){
@@ -71,3 +73,4 @@
mixins: [componentHandler]
}
</script>
@@ -0,0 +1,77 @@
<template>
<div class="row m-b-15 m-l-5 m-r-10 parentContainer">
<div class="col bg-white rounded" v-if="item.storages && item.storages.length > 0">
<div class="row" v-for="invoice in item.invoices" v-if="invoice.type === 1">
<div class="col" v-if="getMergedInvoices(invoice).length > 1">
<single-admin-payments-billing-with-storage-component :data="item" :invoices="getMergedInvoices(invoice)" :storage="getStorageInfo(invoice)" :invoice_status="invoice_status" :section="section" ></single-admin-payments-billing-with-storage-component>
</div>
</div>
</div>
<div class="col bg-white rounded" v-else>
<div class="row">
<div class="col">
<single-admin-payments-billing-without-storage-component :data="item" :invoice_status="invoice_status" :section="section" ></single-admin-payments-billing-without-storage-component>
</div>
</div>
</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
export default {
props: {
invoice_status: {
type: String,
required: true
},
section:{
type: String,
required: true
}
},
computed: {
orderStorageMap() {
// Create a map to link parent invoice IDs to storageInvoiceIds
const storageMap = {};
if(this.item.storages){
for (const storage of this.item.storages) {
storageMap[storage.parentInvoiceId] = storage.storageInvoiceId;
}
}
return storageMap;
}
},
methods: {
getStorageInfo(invoice) {
const storageObject = this.findStorageInfoObject(invoice.id);
return storageObject;
},
findStorageInfoObject(shippingInvoiceId) {
if(this.item.storages){
return this.item.storages.find(storage => storage.parentInvoiceId === shippingInvoiceId);
}
return null;
},
getMergedInvoices(invoice){
const storageInvoice = this.getStorageInvoice(invoice);
const mergedArray = [
...(invoice ? [invoice] : []),
...(storageInvoice ? [storageInvoice] : []),
];
return mergedArray;
},
getStorageInvoice(invoice) {
// Retrieve the storageInvoiceId for the current shipping invoice from storage info (order.storages)
const storageInvoiceId = this.orderStorageMap[invoice.id];
// Find and return the storage invoice (type 16) from order.invoices
const storageInvoice = this.item.invoices.find((invoice) => {
return invoice.type === 16 && invoice.id === storageInvoiceId;
});
return storageInvoice;
},
},
mixins: [componentHandler]
}
</script>
@@ -0,0 +1,40 @@
<template>
<div class="row">
<div class="col">
<loading-component style="height: 300px; top: 0;" key="1" color="success" v-show="isLoading" ></loading-component>
<div class="row justify-content-center" v-show="!isLoading">
<div class="col">
<div class="row m-b-20">
<div class="col">
<h3 class="all-caps">Are you Sure?</h3>
<div class="fs-11">Are you sure you want to delete this payment? </div>
</div>
</div>
<div class="row">
<div class="col p-r-5">
<div class="btn btn-sm btn-success btn-block b-rad-none" data-dismiss="modal">Cancel</div>
</div>
<div class="col p-l-5">
<div class="btn btn-sm btn-danger btn-block b-rad-none" @click="submit(route('api.transaction.group.delete', item.groupId), 'delete', section, true, true)">Delete</div>
</div>
</div>
</div>
</div>
</div>
</div>
</template>
<script>
import componentHandler from '../../../general/mixins/componentHandler';
import ModalFormHandler from '../../../general/mixins/modalFormHandler';
export default {
methods:{
successHandler(response){
this.closeModal();
this.formHandler();
window.location.reload();
},
},
mixins: [componentHandler, ModalFormHandler]
}
</script>
@@ -27,6 +27,15 @@
import componentHandler from '../../../general/mixins/componentHandler';
import ModalFormHandler from '../../../general/mixins/modalFormHandler';
export default {
methods:{
successHandler(response){
this.closeModal();
this.formHandler();
if(response.payload.data.id){
window.location.reload();
}
},
},
mixins: [componentHandler, ModalFormHandler]
}
@@ -55,7 +55,7 @@
</div>
</div>
</div>
<div v-if="$store.getters.isSuperAdmin | showManualPayment">
<div v-if="$store.getters.isSuperAdmin ||showManualPayment">
<div class="row m-t-10 m-b-10">
<div class="col text-center"><div id="expend-method" class="padding-10 bg-master-lightest pointer" @click="$store.dispatch('toggleSection', {name: 'otherPaymentMethods', status: !$store.getters.isShowing('otherPaymentMethods')})"><i class="fa m-r-10" :class="[{'fa-angle-up': $store.getters.isShowing('otherPaymentMethods')}, {'fa-angle-down': !$store.getters.isShowing('otherPaymentMethods')}]"></i>{{$store.getters.isShowing('otherPaymentMethods') ? 'Hide' : 'Show'}} Alternative Methods <i class="fa m-l-10" :class="[{'fa-angle-up': $store.getters.isShowing('otherPaymentMethods')}, {'fa-angle-down': !$store.getters.isShowing('otherPaymentMethods')}]"></i></div></div>
</div>
@@ -115,7 +115,7 @@
</div>
<div class="row">
<div class="col">
<div class="font-heading all-caps fs-10 bold">Maybank: <span class="text-complete">562237009234</span></div>
<div class="font-heading all-caps fs-10 bold">Maybank: <span class="text-complete">568603010762</span></div>
</div>
</div>
<div class="row">
@@ -138,7 +138,7 @@
<div class="btn btn-sm all-caps b-rad-none btn-default bg-master-lighter btn-block" @click="expandPayment = false" data-dismiss="modal">Cancel</div>
</div>
<div class="col-8 p-l-0">
<div class="btn btn-sm all-caps b-rad-none btn-default bg-success btn-block text-white" @click="submitForm()" :class="[{'hide': paymentMethod.name === ''}]" data-dismiss="modal">Proceed</div>
<div class="btn btn-sm all-caps b-rad-none btn-default bg-success btn-block text-white" @click="submitForm()" :class="[{'hide': paymentMethod.name === ''}]">Proceed</div>
</div>
</div>
</div>
@@ -202,8 +202,9 @@
},
methods:{
submitForm(){
this.error = '';
this.parameters.payment_method = this.paymentMethod.id;
this.submit(this.route('api.transaction.group.create', JSON.stringify(this.selectedIds)), 'post', this.section, true, true);
this.submit(this.route('api.transaction.group.create', JSON.stringify(this.selectedIds)), 'post', this.section, false, true);
},
updatePaymentType(payment){
this.paymentMethod = {
@@ -224,11 +225,17 @@
// }
// }
if (response.payload.length == 0) {
let isClearToUpdateList = true;
if(response.payload.data && response.payload.data.message){
this.error = response.payload.data.message;
isClearToUpdateList = false;
}
else if (response.payload.length == 0) {
setTimeout(function() {
location.reload();
}, 2000);
} else if (response.payload) {
}
else if (response.payload) {
if (response.payload.data.payment_method === 5) {
window.location.href = this.route('billplz.bill', response.payload.data.reference) + '?auto_submit=true';
} else {
@@ -236,7 +243,9 @@
}
}
this.updateList();
if(isClearToUpdateList){
this.updateList();
}
}
},
mixins: [formHandler]
@@ -37,7 +37,11 @@
<div class="row" v-if="isEdit">
<div class="col padding-25 bg-master-lightest">
<div class="row">
<div class="col">
<div class="col" v-if="name">
<p class="m-b-0 small muted">Name</p>
<p class="m-b-0 bold">{{product.name}}</p>
</div>
<div class="col" v-else>
<validation-wrapper-component :validator="$v.product.name">
<label>Name</label>
<input class="form-control" v-model="product.name">
@@ -93,6 +97,10 @@
// required: true
default: 0
},
name:{
type: String,
default: ""
},
},
data(){
return {
@@ -102,6 +110,7 @@
quantity: 0,
price: 0,
amount: 0,
reference: 'CUSTOM_CHARGES',
},
products: []
}
@@ -113,6 +122,12 @@
price: { required },
}
},
mounted() {
if(this.name){
this.product.name = this.name;
this.product.reference = 'PAY_ON_BEHALF';
}
},
created() {
if (this.data) {
this.product = this.data;
@@ -136,7 +151,7 @@
this.$emit('add', {
name: this.product.name,
quantity: this.product.quantity,
reference: 'CUSTOM_CHARGES',
reference: this.product.reference,
price: parseFloat((this.product.price).toString().replace(',', '')),
amount: this.productTotal
});

Some files were not shown because too many files have changed in this diff Show More