New Warehouse Storage Fee

This commit is contained in:
Dillon Ngo
2023-11-04 14:58:50 +08:00
parent b5bcd5c553
commit 06751fdc78
24 changed files with 704 additions and 53 deletions
@@ -9,10 +9,12 @@ use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\Modules\Transactions\Processors\CreatePaymentTransactionProcessor;
use App\Classes\Modules\Transactions\Processors\CreateStorageInvoiceDocTransactionProcessor;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Wallets\Services\UpdatesWalletBalance;
use App\Classes\Modules\Orders\Processors\UpdateDoFromVTPortalProcessor;
use App\Classes\Modules\Orders\Processors\UpdateDoFromYDPortalProcessor;
use Illuminate\Support\Facades\Log;
class CallbackBillplzProcessor
{
@@ -31,6 +33,9 @@ class CallbackBillplzProcessor
/** @var CreatePaymentTransactionProcessor */
private $createPaymentTransactionProcessor;
/** @var CreateStorageInvoiceDocTransactionProcessor */
private $ceateStorageInvoiceDocTransactionProcessor;
/**
* CreateUserProcessor constructor.
* @param UpdatesTransactionStatus $updatesTransactionStatus
@@ -38,14 +43,16 @@ class CallbackBillplzProcessor
* @param UpdateDoFromYDPortalProcessor $updateDoFromYDPortalProcessor
* @param UpdatesWalletBalance $updatesWalletBalance
* @param CreatePaymentTransactionProcessor $createPaymentTransactionProcessor
* @param CreateStorageInvoiceDocTransactionProcessor $ceateStorageInvoiceDocTransactionProcessor
*/
public function __construct(UpdatesTransactionStatus $updatesTransactionStatus, UpdateDoFromVTPortalProcessor $updateDoFromVTPortalProcessor, UpdateDoFromYDPortalProcessor $updateDoFromYDPortalProcessor, UpdatesWalletBalance $updatesWalletBalance, CreatePaymentTransactionProcessor $createPaymentTransactionProcessor)
public function __construct(UpdatesTransactionStatus $updatesTransactionStatus, UpdateDoFromVTPortalProcessor $updateDoFromVTPortalProcessor, UpdateDoFromYDPortalProcessor $updateDoFromYDPortalProcessor, UpdatesWalletBalance $updatesWalletBalance, CreatePaymentTransactionProcessor $createPaymentTransactionProcessor, CreateStorageInvoiceDocTransactionProcessor $ceateStorageInvoiceDocTransactionProcessor)
{
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->updateDoFromVTPortalProcessor = $updateDoFromVTPortalProcessor;
$this->updateDoFromYDPortalProcessor = $updateDoFromYDPortalProcessor;
$this->updatesWalletBalance = $updatesWalletBalance;
$this->createPaymentTransactionProcessor = $createPaymentTransactionProcessor;
$this->ceateStorageInvoiceDocTransactionProcessor = $ceateStorageInvoiceDocTransactionProcessor;
}
@@ -66,32 +73,65 @@ class CallbackBillplzProcessor
$this->updatesWalletBalance->execute($transaction->owner, $transaction->amount);
$group = Group::where('reference', $transaction->payment_reference)->first();
// check if is group payment
if ($group) {
foreach ($group->groupTransactions as $groupTransaction) {
$invoice = $groupTransaction->transaction;
$this->createPaymentTransactionProcessor->execute($invoice, PaymentMethodType::WALLET, null);
$paymentTransaction = $this->createPaymentTransactionProcessor->execute($invoice, PaymentMethodType::WALLET, null);
if($paymentTransaction && $paymentTransaction->status == ApprovalStatus::APPROVED){
$pL = $invoice->owner;
$this->processPackingListAndInvoice($pL);
if($invoice->type == TransactionType::STORAGE_INVOICE){
$this->ceateStorageInvoiceDocTransactionProcessor->execute($pL);
}
}
}
$group->status = $status;
$group->save();
}
}
if (!$transaction->owner instanceof Wallet) {
$totalPaidAmount = $invoice->transactions->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount');
$this->processPackingListAndInvoice($packingList, $invoice);
if (($invoice->amount - $totalPaidAmount) < 0.01) {
if($invoice->type == TransactionType::STORAGE_INVOICE){
$this->ceateStorageInvoiceDocTransactionProcessor->execute($packingList);
}
}
}
private function processPackingListAndInvoice($packingList, $invoice = null){
$totalInvoiceAmmuntPaid = 0.00;
$totalInvoiceAmmunt = 0.00;
$invoiceTransactions = $packingList->transactions()->whereIn('type', [TransactionType::SHIPPING_INVOICE, TransactionType::STORAGE_INVOICE])->get();
foreach($invoiceTransactions as $invoiceTransaction){
$totalInvoiceAmmunt = $totalInvoiceAmmunt + $invoiceTransaction->amount;
$totalInvoiceAmmuntPaid = $totalInvoiceAmmuntPaid + $invoiceTransaction->transactions->where('type', TransactionType::PAYMENT)->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])->sum('amount');
}
Log::info('Total invoice amount paid 1: '.$totalInvoiceAmmunt); //cief todo: to be removed
Log::info('Total invoice amount paid 2: '.$totalInvoiceAmmuntPaid); //cief todo: to be removed
// if (($invoice->amount - $totalPaidAmount) < 0.01) {
if (($totalInvoiceAmmunt - $totalInvoiceAmmuntPaid) < 0.01) {
// dd(json_encode($totalInvoiceAmmunt));
if($invoice){
$this->updatesTransactionStatus->execute($invoice, ApprovalStatus::COMPLETED);
}
$packingList->status = ApprovalStatus::APPROVED;
$packingList->save();
Log::info('Total invoice amount paid 3: '.$totalInvoiceAmmuntPaid); //cief todo: to be removed
if (app()->environment('production')) {
$this->updateDoFromVTPortalProcessor->execute($packingList);
$this->updateDoFromYDPortalProcessor->execute($packingList);
}
$packingList->status = ApprovalStatus::APPROVED;
$packingList->save();
if (app()->environment('production')) {
$this->updateDoFromVTPortalProcessor->execute($packingList);
$this->updateDoFromYDPortalProcessor->execute($packingList);
}
}
}
@@ -52,9 +52,11 @@ class FetchOrderV2Logic extends AbstractControllerLogic
$this->canFetchOrder->passes();
$query = $this->fetchesOrder->execute(['reference' => $request->route('id'), 'with_packing_lists' => true]);
$query->storages = $request->input('storages'); //from middleware
return $this->resourceResponse(new OrderV2Resource($query));
}
}
}
@@ -0,0 +1,286 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Modules\Orders\Services\FetchesOrder;
use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber;
use App\Classes\Modules\Transactions\Services\CreatesTransaction;
use App\Classes\Modules\Transactions\Services\CreatesTransactionDetail;
use App\Classes\Modules\Transactions\Services\UpdatesTransaction;
use App\Classes\Modules\Transactions\Services\FetchesTransaction;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionDetail;
use App\Classes\Modules\Transactions\Services\UpdatesTransactionStatus;
use App\Classes\Modules\Transactions\Services\DeletesGroup;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionObject;
use App\Classes\Modules\Transactions\DataTransferObjects\TransactionDetailObject;
use App\Classes\ValueObjects\Constants\TransactionType;
use App\Classes\ValueObjects\Constants\PaymentMethodType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\PackageType;
use App\Classes\ValueObjects\Constants\TransactionDetailType;
use App\Models\PackingList;
use App\Models\Transaction;
use Carbon\Carbon;
use Illuminate\Support\Facades\Log;
class CheckAndCreateStorageInvoiceTransactionProcessor
{
/** @var FetchesOrder */
private $fetchesOrder;
/** @var GeneratesTransactionBillNumber */
private $generatesTransactionBillNumber;
/** @var FetchesTransaction */
private $fetchesTransaction;
/** @var CreatesTransaction */
private $createsTransaction;
/** @var CreatesTransactionDetail */
private $createsTransactionDetail;
/** @var UpdatesTransaction */
private $updatesTransaction;
/** @var UpdatesTransactionDetail */
private $updatesTransactionDetail;
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var DeletesGroup */
private $deletesGroup;
/**
* @param FetchesOrder $fetchesOrder
* @param GeneratesTransactionBillNumber $generatesTransactionBillNumber
* @param FetchesTransaction $fetchesTransaction
* @param CreatesTransaction $createsTransaction
* @param CreatesTransactionDetail $createsTransactionDetail
* @param UpdatesTransaction $updatesTransaction
* @param UpdatesTransactionDetail $updatesTransactionDetail
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param DeletesGroup $deletesGroup
*/
public function __construct(FetchesOrder $fetchesOrder, GeneratesTransactionBillNumber $generatesTransactionBillNumber, FetchesTransaction $fetchesTransaction, CreatesTransaction $createsTransaction, CreatesTransactionDetail $createsTransactionDetail, UpdatesTransaction $updatesTransaction, UpdatesTransactionDetail $updatesTransactionDetail, UpdatesTransactionStatus $updatesTransactionStatus, DeletesGroup $deletesGroup)
{
$this->fetchesOrder = $fetchesOrder;
$this->generatesTransactionBillNumber = $generatesTransactionBillNumber;
$this->fetchesTransaction = $fetchesTransaction;
$this->createsTransaction = $createsTransaction;
$this->createsTransactionDetail = $createsTransactionDetail;
$this->updatesTransaction = $updatesTransaction;
$this->updatesTransactionDetail = $updatesTransactionDetail;
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->deletesGroup = $deletesGroup;
}
/**
* @throws MalformedRequestException
*/
public function execute(int $orderId)
{
$multipleResults = array();
$order = $this->fetchesOrder->execute(['reference' => $orderId, 'with_packing_lists' => true]);
$eta = "";
$destinationWarehousePackages = $order->destinationWarehousePackages;
foreach ($destinationWarehousePackages as $destinationWarehousePackage){
if ($destinationWarehousePackage) {
$package = $destinationWarehousePackage->packages->first();
if ($package) {
$container = $package->container()->first();
if ($container) {
$transport = $container->transports->first();
if ($transport) {
$schedule = $transport->schedules->last();
if ($schedule) {
$eta = $schedule->eta;
if($eta){
$transactions = $destinationWarehousePackage->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){
$multipleResults[] = $this->processSingleTransactionOfTypeShippingInvoice($invoice_transaction, $destinationWarehousePackage, $order, $eta);
}
}
}
}
}
}
}
}
return $multipleResults;
}
function processSingleTransactionOfTypeShippingInvoice($transaction, $destinationWarehousePackage, $order, $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;
$storageInvoice = $destinationWarehousePackage->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->first();
$storageInvoiceId = 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;
}
$price_cbm = $pricePerCBM * $cbm * $resultNumberOfDaysExceeded;
if(!$storageInvoice && $resultNumberOfDaysExceeded > 0 && $transaction->status != ApprovalStatus::COMPLETED){
$billNumber = $this->generatesTransactionBillNumber->execute('STOR-');
$invoiceTransaction = $this->createTransaction($destinationWarehousePackage, $billNumber, $order->company_module_id, $price_cbm);
$storageInvoiceId = $invoiceTransaction->id;
$this->createTransactionDetails($invoiceTransaction, $destinationWarehousePackage, $cbm, 3 * $resultNumberOfDaysExceeded, $resultNumberOfDaysExceeded);
}
else if($storageInvoice){
$amount = $storageInvoice->amount;
$epsilon = 0.0001; // Tolerance for the comparison
//cief todo: to be removed - starts
Log::info('price_cbm: '.$price_cbm."-".gettype($price_cbm));
Log::info('amount: '.$amount."-".gettype($amount));
if (abs($price_cbm - $amount) > $epsilon) {
Log::info("The values are not equal.");
} else {
Log::info("The values are approximately equal.");
}
//cief todo: to be removed - ends
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(count($paymentTransactions) > 0){ //PAYMENT type
foreach ($paymentTransactions as $paymentTransaction){
$this->updatesTransactionStatus->execute($paymentTransaction, ApprovalStatus::EXPIRED);
}
}
else{ //TOP UP type
$groups = $storageInvoice->groups()->get();
foreach ($groups as $grp){
$groupReference = $grp->reference;
$walletTransaction = $this->fetchesTransaction->execute(['payment_reference' => $groupReference]);
if($walletTransaction->status === ApprovalStatus::PENDING_SUBMISSION || $walletTransaction->status === ApprovalStatus::PENDING_VERIFICATION){
$grp->status = ApprovalStatus::EXPIRED;
$grp->save();
$this->deletesGroup->execute($grp);
$this->updatesTransactionStatus->execute($walletTransaction, ApprovalStatus::EXPIRED);
}
}
}
$invoiceTransaction = $this->updateTransaction($storageInvoice, $price_cbm);
$invoiceTransactionDetails = $storageInvoice->transactionDetails()->first();
$this->updateTransactionDetails($invoiceTransactionDetails, $cbm, 3 * $resultNumberOfDaysExceeded);
}
$storageInvoiceId = $storageInvoice->id;
}
$result = [
'parentInvoiceId' => $transaction->id,
'storageInvoiceId' => $storageInvoiceId,
'numberOfDaysExceeded' => $resultNumberOfDaysExceeded,
'numberOfDaysFree' => $resultNumberOfDaysFree,
'startDate' => $resultStartDate,
'currentDate' => $resultCurrentDate,
'cbm' => $cbm,
'pricePerCBM' => $pricePerCBM,
];
return $result;
}
function updateTransaction(Transaction $transaction, float $totalAmount){
$object = new TransactionObject(
$transaction->bill_no,
TransactionType::STORAGE_INVOICE,
1,
$transaction->receiver,
1,
PaymentMethodType::CASH,
$totalAmount,
$totalAmount,
1,
1,
0,
0,
0,
null,
ApprovalStatus::APPROVED
);
/** @var Transaction $invoice_transaction */
$invoice_transaction = $this->updatesTransaction->execute($transaction, $object);
return $invoice_transaction;
}
function updateTransactionDetails($invoice_transaction_details, $cbm, $price_cbm){
$object_detail = new TransactionDetailObject(
'STORAGE_FEE',
$invoice_transaction_details->name,
$cbm,
$price_cbm
);
$this->updatesTransactionDetail->execute($invoice_transaction_details, $object_detail);
}
function createTransaction(PackingList $packing_list, string $billNumber, int $companyModuleId, float $totalAmount){
$object = new TransactionObject(
$billNumber,
TransactionType::STORAGE_INVOICE,
1,
$companyModuleId,
1,
PaymentMethodType::CASH,
$totalAmount,
$totalAmount,
1,
1,
0,
0,
0,
null,
ApprovalStatus::APPROVED
);
/** @var Transaction $invoice_transaction */
$invoice_transaction = $this->createsTransaction->execute($packing_list, $object);
return $invoice_transaction;
}
function createTransactionDetails($invoice_transaction, PackingList $packing_list, $cbm, $price_cbm, $numberOfDays){
$object_detail = new TransactionDetailObject(
'SHIPPING_FEE',
TransactionDetailType::STORAGE_FEE.' for '.$numberOfDays. ' days<br>'.round($packing_list->packages->where('type', '!=', PackageType::OVER_WEIGHT)->sum('quantity'), 3).' CTNS - '.round($cbm, 3).' CBM',
$cbm,
$price_cbm
);
$this->createsTransactionDetail->execute($invoice_transaction, $object_detail);
}
}
@@ -127,15 +127,15 @@ class CreatePaymentTransactionProcessor
$this->updatesWalletBalance->execute($wallet, ($amount * -1));
$packingList = $invoice->owner;
$order = $packingList->owner;
$packingList->status = ApprovalStatus::APPROVED;
$packingList->save();
// $packingList = $invoice->owner;
// $order = $packingList->owner;
// $packingList->status = ApprovalStatus::APPROVED;
// $packingList->save();
if(app()->environment('production')){
$this->updateDoFromVTPortalProcessor->execute($packingList);
$this->updateDoFromYDPortalProcessor->execute($packingList);
}
// if(app()->environment('production')){
// $this->updateDoFromVTPortalProcessor->execute($packingList);
// $this->updateDoFromYDPortalProcessor->execute($packingList);
// }
// later use this variabke to create a approved payment transaction
$approvalStatus = ApprovalStatus::APPROVED;
@@ -0,0 +1,79 @@
<?php
namespace App\Classes\Modules\Transactions\Processors;
use App\Classes\Exceptions\MalformedRequestException;
use App\Classes\Notifications\InvoiceIssuedEmail;
use App\Models\Document;
use App\Models\PackingList;
use App\Models\Transaction;
use Mccarlosen\LaravelMpdf\Facades\LaravelMpdf;
use App\Classes\ValueObjects\Constants\DocumentType;
use App\Classes\ValueObjects\Constants\ApprovalStatus;
use App\Classes\ValueObjects\Constants\TransactionType;
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;
class CreateStorageInvoiceDocTransactionProcessor
{
/** @var UpdatesTransactionStatus */
private $updatesTransactionStatus;
/** @var CreatesDocument */
private $createsDocument;
/** @var CreatesFiles */
private $createsFiles;
/**
* @param UpdatesTransactionStatus $updatesTransactionStatus
* @param CreatesDocument $createsDocument
* @param CreatesFiles $createsFiles
*/
public function __construct(UpdatesTransactionStatus $updatesTransactionStatus, CreatesDocument $createsDocument, CreatesFiles $createsFiles)
{
$this->updatesTransactionStatus = $updatesTransactionStatus;
$this->createsDocument = $createsDocument;
$this->createsFiles = $createsFiles;
}
/**
* @throws MalformedRequestException
*/
public function execute(PackingList $packingList)
{
/** @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);
$transaction_invoice_pdf = LaravelMpdf::loadView('pages.pdfs.shipping_invoice', ['invoice_transaction' => $invoice_transaction]);
$document_object = new DocumentObject(
DocumentType::STORAGE_INVOICE,
[chunk_split('data:application/pdf;base64,'.base64_encode($transaction_invoice_pdf->output()))],
'',
ApprovalStatus::COMPLETED,
'storage_invoice'
);
$invouce_transaction_document = $invoice_transaction->documents()->where('document_type', DocumentType::STORAGE_INVOICE)->first();
if(!$invouce_transaction_document){
/** @var Document $document */
$document = $this->createsDocument->execute($invoice_transaction, $document_object);
$this->createsFiles->execute($document, $document_object);
$user = $packingList->owner->companyModule->employees()->first();
if(app()->environment(['production'])) {
$user->notify(new InvoiceIssuedEmail($user, $packingList));
}
}
}
}