diff --git a/app/Classes/General/Eloquent/Filters/CompanySegmentsIn.php b/app/Classes/General/Eloquent/Filters/CompanySegmentsIn.php new file mode 100644 index 00000000..dd86d514 --- /dev/null +++ b/app/Classes/General/Eloquent/Filters/CompanySegmentsIn.php @@ -0,0 +1,24 @@ +whereHas('companyModules', function ($module) use ($value) { + $module->whereHas('connections', function ($connection) use ($value) { + $connection->whereHas('connectionSegments', function ($segment) use ($value) { + $segment->whereIn('segment_id', $value); + }); + }); + }); + } +} diff --git a/app/Classes/General/Interfaces/KeyValueInterface.php b/app/Classes/General/Interfaces/KeyValueInterface.php new file mode 100644 index 00000000..fbee5265 --- /dev/null +++ b/app/Classes/General/Interfaces/KeyValueInterface.php @@ -0,0 +1,12 @@ +key = $key; + $this->value = $value; + } + + /** + * @return string + */ + public function getKey(): string + { + return $this->key; + } + + /** + * @return string + */ + public function getValue(): string + { + return $this->value; + } + +} diff --git a/app/Classes/Modules/Accounts/Services/CreatesKeyValuePair.php b/app/Classes/Modules/Accounts/Services/CreatesKeyValuePair.php new file mode 100644 index 00000000..c963ec4e --- /dev/null +++ b/app/Classes/Modules/Accounts/Services/CreatesKeyValuePair.php @@ -0,0 +1,28 @@ +key = $object->getKey(); + $model->value = $object->getValue(); + + return $this->handler($kv->attributes(), $model); + + } +} diff --git a/app/Classes/Modules/Addresses/ControllersLogic/CreateAddressLogic.php b/app/Classes/Modules/Addresses/ControllersLogic/CreateAddressLogic.php index df552b6a..6b964475 100644 --- a/app/Classes/Modules/Addresses/ControllersLogic/CreateAddressLogic.php +++ b/app/Classes/Modules/Addresses/ControllersLogic/CreateAddressLogic.php @@ -18,6 +18,7 @@ use App\Classes\Modules\Contacts\Processors\CreateContactProcessor; use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject; use App\Classes\Modules\Remarks\Processors\CreateRemarkProcessor; use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\ValueObjects\Constants\RemarkTypes; use App\Http\Resources\AddressResource; use App\Models\Address; use App\Transformers\AddressTransformer; @@ -110,6 +111,15 @@ class CreateAddressLogic extends AbstractControllerLogic ->parseIncludes('remark') ->respond(200, [], JSON_PRETTY_PRINT);*/ + $addressExtraFields = [ + 'property_type' => $request->input('property_type'), + 'tools_required_unload' => $request->input('tools_required_unload'), + 'pickup_time_from' => $request->input('pickup_time_from'), + 'pickup_time_to' => $request->input('pickup_time_to'), + ]; + + $addressExtraFieldsObject = new RemarkObject(json_encode($addressExtraFields), Auth()->user()->id, RemarkTypes::ADDRESS_EXTRA_COLUMNS); + $this->createRemarkProcessor->execute($address, $addressExtraFieldsObject); return $this->resourceResponse(new AddressResource($address)); diff --git a/app/Classes/Modules/Addresses/ControllersLogic/UpdateAddressLogic.php b/app/Classes/Modules/Addresses/ControllersLogic/UpdateAddressLogic.php index 4216a0e8..46eae08d 100644 --- a/app/Classes/Modules/Addresses/ControllersLogic/UpdateAddressLogic.php +++ b/app/Classes/Modules/Addresses/ControllersLogic/UpdateAddressLogic.php @@ -15,6 +15,7 @@ use App\Classes\Modules\Remarks\DataTransferObjects\RemarkObject; use App\Classes\Modules\Remarks\Processors\CreateRemarkProcessor; use App\Classes\ValueObjects\Constants\AddressType; use App\Classes\ValueObjects\Constants\ApprovalStatus; +use App\Classes\ValueObjects\Constants\RemarkTypes; use App\Http\Resources\AddressResource; use App\Models\Address; use App\Transformers\AddressTransformer; @@ -110,6 +111,15 @@ class UpdateAddressLogic extends AbstractControllerLogic ->item($address, new AddressTransformer()) ->parseIncludes('remark') ->respond(200, [], JSON_PRETTY_PRINT);*/ + $addressExtraFields = [ + 'property_type' => $request->input('property_type'), + 'tools_required_unload' => $request->input('tools_required_unload'), + 'pickup_time_from' => $request->input('pickup_time_from'), + 'pickup_time_to' => $request->input('pickup_time_to'), + ]; + + $addressExtraFieldsObject = new RemarkObject(json_encode($addressExtraFields), Auth()->user()->id, RemarkTypes::ADDRESS_EXTRA_COLUMNS); + $this->createRemarkProcessor->execute($address, $addressExtraFieldsObject); return $this->resourceResponse(new AddressResource($address)); diff --git a/app/Classes/Modules/Companies/ControllersLogic/AssignCompanyConnectionToConnectionSegmentLogic.php b/app/Classes/Modules/Companies/ControllersLogic/AssignCompanyConnectionToConnectionSegmentLogic.php index cee72e84..8069663c 100644 --- a/app/Classes/Modules/Companies/ControllersLogic/AssignCompanyConnectionToConnectionSegmentLogic.php +++ b/app/Classes/Modules/Companies/ControllersLogic/AssignCompanyConnectionToConnectionSegmentLogic.php @@ -7,6 +7,8 @@ use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Modules\Companies\Processors\AssignConnectionSegmentProcessor; use App\Classes\Modules\Companies\Services\FetchesCompany; use App\Classes\Modules\Companies\Services\FetchesCompanyConnection; +use App\Classes\Modules\Contacts\DataTransferObjects\ContactObject; +use App\Classes\Modules\Contacts\Processors\CreateContactProcessor; use App\Http\Resources\CompanyResource; use Illuminate\Http\JsonResponse; use Illuminate\Http\Request; @@ -33,17 +35,22 @@ class AssignCompanyConnectionToConnectionSegmentLogic extends AbstractController /** @var AssignConnectionSegmentProcessor */ private $assignCompanyConnectionToConnectionSegmentProcessor; + /** @var CreateContactProcessor */ + private $createContactProcessor; + /** * AssignCompanyToSegmentLogic constructor. * @param FetchesCompany $fetchesCompany * @param FetchesCompanyConnection $fetchesCompanyConnection * @param AssignConnectionSegmentProcessor $assignCompanyConnectionToConnectionSegmentProcessor + * @param CreateContactProcessor $createContactProcessor */ - public function __construct(FetchesCompany $fetchesCompany, FetchesCompanyConnection $fetchesCompanyConnection, AssignConnectionSegmentProcessor $assignCompanyConnectionToConnectionSegmentProcessor) + public function __construct(FetchesCompany $fetchesCompany, FetchesCompanyConnection $fetchesCompanyConnection, AssignConnectionSegmentProcessor $assignCompanyConnectionToConnectionSegmentProcessor, CreateContactProcessor $createContactProcessor) { $this->fetchesCompany = $fetchesCompany; $this->fetchesCompanyConnection = $fetchesCompanyConnection; $this->assignCompanyConnectionToConnectionSegmentProcessor = $assignCompanyConnectionToConnectionSegmentProcessor; + $this->createContactProcessor = $createContactProcessor; } /** @@ -62,6 +69,11 @@ class AssignCompanyConnectionToConnectionSegmentLogic extends AbstractController $this->assignCompanyConnectionToConnectionSegmentProcessor->execute($companyConnection, $request->input('segment_id')); + if ($request->input('segment_id') == 10 || $request->input('segment_id') == 11) { + $contactObject = new ContactObject('Whatsapp: ' . $request->input('name'), $request->input('phone'), null, null); + $this->createContactProcessor->execute($contactObject, $company); + } + return $this->resourceResponse(new CompanyResource($company)); } } \ No newline at end of file diff --git a/app/Classes/Modules/Orders/ControllersLogic/CreateOrderLogic.php b/app/Classes/Modules/Orders/ControllersLogic/CreateOrderLogic.php index 8ef031cd..f8ddc857 100644 --- a/app/Classes/Modules/Orders/ControllersLogic/CreateOrderLogic.php +++ b/app/Classes/Modules/Orders/ControllersLogic/CreateOrderLogic.php @@ -6,6 +6,7 @@ use App\Classes\Exceptions\RequestValidationException; use App\Classes\General\Abstracts\AbstractControllerLogic; use App\Classes\Modules\Addresses\DataTransferObjects\AddressObject; use App\Classes\Modules\Addresses\Services\CreatesAddress; +use App\Classes\Modules\Accounts\DataTransferObjects\KeyValuePairObject; use App\Classes\Modules\Addresses\Services\FetchesAddress; use App\Classes\Modules\Companies\Services\FetchesCompany; use App\Classes\Modules\Companies\Services\FetchesCompanyModule; @@ -16,10 +17,12 @@ use App\Classes\Modules\Orders\Services\ConnectOrderToExchangeBooking; use App\Classes\Modules\Orders\Services\GeneratesOrderNumber; use App\Classes\ValueObjects\Constants\AddressType; use App\Classes\ValueObjects\Constants\ApprovalStatus; -use App\Classes\ValueObjects\Constants\WarehouseReferences; -use App\Http\Resources\OrderResource; use App\Classes\Modules\Addresses\Standards\Rules\CanCreateAddress; use App\Models\Address; +use App\Classes\Modules\Accounts\Services\CreatesKeyValuePair; +use App\Classes\ValueObjects\Constants\WarehouseReferences; +use App\Http\Resources\OrderResource; +use App\Models\Order; use Illuminate\Http\Request; use Illuminate\Http\JsonResponse; @@ -64,6 +67,10 @@ class CreateOrderLogic extends AbstractControllerLogic /** @var ConnectOrderToExchangeBookingOnExchangeProcessor */ private $connectOrderToExchangeBookingOnExchangeProcessor; + /** @var CreatesKeyValuePair */ + private $createsKeyValuePair; + + /** * CreateOrderLogic constructor. * @param FetchesCompany $fetchesCompany @@ -75,7 +82,7 @@ class CreateOrderLogic extends AbstractControllerLogic * @param ConnectOrderToExchangeBooking $connectOrderToExchangeBooking * @param ConnectOrderToExchangeBookingOnExchangeProcessor $connectOrderToExchangeBookingOnExchangeProcessor */ - public function __construct(FetchesCompany $fetchesCompany, FetchesAddress $fetchesAddress, CreateOrderProcessor $createOrderProcessor, FetchesCompanyModule $fetchesCompanyModule, GeneratesOrderNumber $generatesOrderNumber, NewLeadTaskToPerfexCRMProcessor $newLeadTaskToPerfexCRMProcessor, ConnectOrderToExchangeBooking $connectOrderToExchangeBooking, ConnectOrderToExchangeBookingOnExchangeProcessor $connectOrderToExchangeBookingOnExchangeProcessor) + public function __construct(FetchesCompany $fetchesCompany, FetchesAddress $fetchesAddress, CreateOrderProcessor $createOrderProcessor, FetchesCompanyModule $fetchesCompanyModule, GeneratesOrderNumber $generatesOrderNumber, NewLeadTaskToPerfexCRMProcessor $newLeadTaskToPerfexCRMProcessor, ConnectOrderToExchangeBooking $connectOrderToExchangeBooking, ConnectOrderToExchangeBookingOnExchangeProcessor $connectOrderToExchangeBookingOnExchangeProcessor, CreatesKeyValuePair $createsKeyValuePair) { $this->fetchesCompany = $fetchesCompany; $this->fetchesAddress = $fetchesAddress; @@ -85,12 +92,16 @@ class CreateOrderLogic extends AbstractControllerLogic $this->newLeadTaskToPerfexCRMProcessor = $newLeadTaskToPerfexCRMProcessor; $this->connectOrderToExchangeBooking = $connectOrderToExchangeBooking; $this->connectOrderToExchangeBookingOnExchangeProcessor = $connectOrderToExchangeBookingOnExchangeProcessor; + $this->createsKeyValuePair = $createsKeyValuePair; } public function logic(Request $request): JsonResponse { - + $isTermsAgreed = $request->input('is_terms_agree'); + if(!$isTermsAgreed){ + throw new RequestValidationException('You must read and agree to our terms and conditions to proceed'); + } $company = $this->fetchesCompany->execute(['id' => $request->input('company_id')]); @@ -116,8 +127,15 @@ class CreateOrderLogic extends AbstractControllerLogic throw new RequestValidationException('Our Yiwu warehouse is unable to ship goods to Sabah & Sarawak at the moment. you can select our Guangzhou warehouse as an alternative.'); } + /** @var Order $order */ $order = $this->createOrderProcessor->execute($company, $originWarehouse, $address, $this->generatesOrderNumber->execute()); + $keyValuePairObject = new KeyValuePairObject( + "TERMS_AND_CONDITIONS", + $isTermsAgreed + ); + $this->createsKeyValuePair->execute($order, $keyValuePairObject); + if(config('perfexcrm.is_enabled') == 'true'){ $this->newLeadTaskToPerfexCRMProcessor->execute($company); } diff --git a/app/Classes/Modules/Orders/Processors/CreateOrderProcessor.php b/app/Classes/Modules/Orders/Processors/CreateOrderProcessor.php index c427a20f..d60fb05d 100644 --- a/app/Classes/Modules/Orders/Processors/CreateOrderProcessor.php +++ b/app/Classes/Modules/Orders/Processors/CreateOrderProcessor.php @@ -67,7 +67,7 @@ class CreateOrderProcessor * @param CompanyModule $originWarehouse * @param Address $address * @param int|null $orderNumber - * @return Addressable + * @return Order * @throws \App\Classes\Exceptions\AccessForbiddenException * @throws \App\Classes\Exceptions\MalformedRequestException * @throws \App\Classes\Exceptions\RequestValidationException diff --git a/app/Classes/Modules/PackingLists/ControllersLogic/Containers/RescheduleContainerLogic.php b/app/Classes/Modules/PackingLists/ControllersLogic/Containers/RescheduleContainerLogic.php index f0214cba..84e71e9c 100644 --- a/app/Classes/Modules/PackingLists/ControllersLogic/Containers/RescheduleContainerLogic.php +++ b/app/Classes/Modules/PackingLists/ControllersLogic/Containers/RescheduleContainerLogic.php @@ -58,32 +58,21 @@ class RescheduleContainerLogic extends AbstractControllerLogic */ public function logic(Request $request): JsonResponse { - try { - $container = $this->fetchesContainer->execute(['id' => $request->route('id')]); - $transport = $container->transports()->first(); + $container = $this->fetchesContainer->execute(['id' => $request->route('id')]); + $transport = $container->transports()->first(); - $old_sechedule = $transport->schedules()->first(); + $old_schedule = $transport->schedules()->delete(); - $this->updatesScheduleStatus->execute($old_sechedule, ApprovalStatus::REJECTED); + // $this->updatesScheduleStatus->execute($old_schedule, ApprovalStatus::REJECTED); - $scheduleObject = new ScheduleObject( - Carbon::parse($request->input('etd')), - Carbon::parse($request->input('eta')), - ApprovalStatus::APPROVED - ); - $schedule = $this->createsSchedule->execute($transport, $scheduleObject); - - //no relationship - /* return fractal() - ->item($container, new ContainerTransformer()) - ->respond(200, [], JSON_PRETTY_PRINT);*/ - - return $this->resourceResponse(new ContainerResource($container)); - - } catch (\Exception $exception) { - throw new ErrorException($exception->getMessage(), $exception->getCode()); - } + $scheduleObject = new ScheduleObject( + Carbon::parse($request->input('etd')), + Carbon::parse($request->input('eta')), + ApprovalStatus::APPROVED + ); + $schedule = $this->createsSchedule->execute($transport, $scheduleObject); + return $this->resourceResponse(new ContainerResource($container)); } } diff --git a/app/Classes/Modules/Remarks/DataTransferObjects/RemarkObject.php b/app/Classes/Modules/Remarks/DataTransferObjects/RemarkObject.php index 44a9507f..5a07c508 100644 --- a/app/Classes/Modules/Remarks/DataTransferObjects/RemarkObject.php +++ b/app/Classes/Modules/Remarks/DataTransferObjects/RemarkObject.php @@ -13,10 +13,14 @@ class RemarkObject implements DataTransferObject /** @var string*/ private $content; - public function __construct(string $content, int $commenterID) + /** @var int|null */ + private $type; + + public function __construct(string $content, int $commenterID, int $type = null) { $this->commenterID = $commenterID; $this->content = $content; + $this->type = $type; } /** @@ -35,4 +39,12 @@ class RemarkObject implements DataTransferObject return $this->content; } + /** + * @return int|null + */ + public function getType(): ?int + { + return $this->type; + } + } diff --git a/app/Classes/Modules/Remarks/Services/CreatesRemark.php b/app/Classes/Modules/Remarks/Services/CreatesRemark.php index ac0d57a3..b7bcf388 100644 --- a/app/Classes/Modules/Remarks/Services/CreatesRemark.php +++ b/app/Classes/Modules/Remarks/Services/CreatesRemark.php @@ -24,6 +24,7 @@ class CreatesRemark extends AbstractUpdateRelationshipRecord $model->commenter_id = $object->getCommenterId(); $model->content = $object->getContent(); + $model->type = $object->getType(); return $this->handler($remarkable->remarks(), $model); diff --git a/app/Classes/Modules/Transactions/ControllersLogic/CreateGroupsLogic.php b/app/Classes/Modules/Transactions/ControllersLogic/CreateGroupsLogic.php index c750f3f2..561fb23d 100644 --- a/app/Classes/Modules/Transactions/ControllersLogic/CreateGroupsLogic.php +++ b/app/Classes/Modules/Transactions/ControllersLogic/CreateGroupsLogic.php @@ -22,7 +22,7 @@ use App\Models\GroupTransaction; use App\Http\Resources\WalletTransactionResource; use App\Models\Wallet; use App\Classes\Modules\Transactions\Processors\ReleaseGoodsToCustomerProcessor; - +use Illuminate\Support\Facades\Log; class CreateGroupsLogic extends AbstractControllerLogic { @@ -200,7 +200,9 @@ 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(',', '', $reqAmount)); + $amount2 = floatval(str_replace(',', '', $reqAmount)); + Log::channel('storage_invoices')->info('CreateGroupsLogic reqAmount from client: ' .$amount2); + Log::channel('storage_invoices')->info('CreateGroupsLogic amount from backend: ' .$amount); //the real amount should always be from backend $companyModuleId = $invoice->receiver; $companyModule = $this->fetchesCompanyModule->execute(['id' => $companyModuleId]); diff --git a/app/Classes/Modules/Transactions/Processors/CheckStorageInvoiceTransactionProcessor.php b/app/Classes/Modules/Transactions/Processors/CheckStorageInvoiceTransactionProcessor.php index 2217ca57..2595c770 100644 --- a/app/Classes/Modules/Transactions/Processors/CheckStorageInvoiceTransactionProcessor.php +++ b/app/Classes/Modules/Transactions/Processors/CheckStorageInvoiceTransactionProcessor.php @@ -4,7 +4,6 @@ namespace App\Classes\Modules\Transactions\Processors; use App\Classes\Exceptions\MalformedRequestException; -use App\Classes\General\LogHelper; use App\Classes\Modules\Orders\Services\FetchesOrder; use App\Classes\Modules\Transactions\Services\GeneratesTransactionBillNumber; use App\Classes\Modules\Transactions\Services\CreatesTransaction; @@ -124,7 +123,7 @@ class CheckStorageInvoiceTransactionProcessor $result = $this->processSingleTransactionOfTypeShippingInvoice($invoice_transaction, $packingList, $order->company_module_id, $eta); } else{ - $result = $this->isPaidOrWaivedStorageInvoiceExist($invoice_transaction, $packingList, $eta); + $result = $this->isExistPaidOrWaivedStorageInvoice($invoice_transaction, $packingList, $eta); } if($result){ $results[] = $result; @@ -165,6 +164,7 @@ class CheckStorageInvoiceTransactionProcessor if ($transport) { $schedule = $transport->schedules->last(); if ($schedule) { + Log::channel('storage_invoices')->info('schedule: '.json_encode($schedule)); return $schedule->eta; } } @@ -178,11 +178,14 @@ class CheckStorageInvoiceTransactionProcessor $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'); + $dt2 = Carbon::now()->copy()->addDay()->startOfDay(); $interval = Carbon::parse($dt2)->diff($dt1); + Log::channel('storage_invoices')->info('eta: '.json_encode($eta)); + Log::channel('storage_invoices')->info('dt1: '.json_encode($dt1)); + Log::channel('storage_invoices')->info('dt2: '.json_encode($dt2)); + Log::channel('storage_invoices')->info('interval: '.json_encode($interval)); + Log::channel('storage_invoices')->info('Carbon now: '.json_encode(Carbon::now())); + $resultNumberOfDaysExceeded = $interval->days - $resultNumberOfDaysFree; $storageInvoice = $destinationWarehousePackage->transactions()->where('transactions.type', TransactionType::STORAGE_INVOICE)->first(); @@ -201,14 +204,14 @@ class CheckStorageInvoiceTransactionProcessor $taxPercentage = TaxPercentage::DEFAULT; $price_cbm = $pricePerCBM * $cbm * $resultNumberOfDaysExceeded; $dateToCompare = Carbon::parse(env('SST_START_DATE', '2024-04-01 00:00:00')); - $shippingInvoiceTransactionCreatedDate = Carbon::now(); - LogHelper::channel('storage_invoices')->info('storageInvoice: '.json_encode($storageInvoice).', $transaction->status: '.$transaction->status); + + Log::channel('storage_invoices')->info('storageInvoice: '.json_encode($storageInvoice).', $transaction->status: '.$transaction->status); if(!$storageInvoice && $resultNumberOfDaysExceeded > 0 && $transaction->status != ApprovalStatus::COMPLETED){ - LogHelper::channel('storage_invoices')->info('Created $transaction->id: '.$transaction->id); + Log::channel('storage_invoices')->info('Created $transaction->id: '.$transaction->id); $billNumber = $this->generatesTransactionBillNumber->execute('STOR-'); - if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare)) { + if (Carbon::now()->isAfter($dateToCompare)) { $taxPercentage = TaxPercentage::SIX_PERCENT; $total_tax = $price_cbm * $taxPercentage / 100; $price_cbm = $price_cbm + $total_tax; @@ -229,13 +232,13 @@ class CheckStorageInvoiceTransactionProcessor $paymentStorageTransaction = $storageInvoice->transactions()->where('transactions.type', TransactionType::PAYMENT)->where('transactions.status', ApprovalStatus::APPROVED)->first(); if($paymentStorageTransaction){ $dateStorageInvoicePaid = $paymentStorageTransaction->created_at->copy()->addDay()->startOfDay(); - LogHelper::channel('storage_invoices')->info('dateStorageInvoicePaid: '.$dateStorageInvoicePaid.', resultCurrentDate: '.$resultCurrentDate); + Log::channel('storage_invoices')->info('dateStorageInvoicePaid: '.$dateStorageInvoicePaid.', resultCurrentDate: '.$resultCurrentDate); $intervalRecalculate = Carbon::parse($dateStorageInvoicePaid)->diff($dt1); $resultNumberOfDaysExceeded = $intervalRecalculate->days - $resultNumberOfDaysFree; $price_cbm = $pricePerCBM * $cbm * $resultNumberOfDaysExceeded; } - if ($shippingInvoiceTransactionCreatedDate->isAfter($dateToCompare)) { + if (Carbon::now()->isAfter($dateToCompare)) { $taxPercentage = TaxPercentage::SIX_PERCENT; $total_tax = $price_cbm * $taxPercentage / 100; $price_cbm = $price_cbm + $total_tax; @@ -250,7 +253,7 @@ class CheckStorageInvoiceTransactionProcessor $proceedToUpdate = false; - if(abs($price_cbm - $amount) > $epsilon && $storageInvoice->status !== ApprovalStatus::COMPLETED){ + if(abs($price_cbm - $amount) > $epsilon && $storageInvoice->status !== ApprovalStatus::COMPLETED && !$this->isExistPendingVerificationManualPayment($storageInvoice)){ $paymentTransactions = $storageInvoice->transactions()->where('transactions.type', TransactionType::PAYMENT)->where('transactions.status', ApprovalStatus::PENDING_SUBMISSION)->get(); // if(!$isBackDoorCheck){ if(count($paymentTransactions) > 0){ @@ -281,8 +284,8 @@ class CheckStorageInvoiceTransactionProcessor 'storageInvoiceId' => $storageInvoiceId, 'numberOfDaysExceeded' => $resultNumberOfDaysExceeded, 'numberOfDaysFree' => $resultNumberOfDaysFree, - 'startDate' => $resultStartDate, - 'currentDate' => $resultCurrentDate, + 'startDate' => $dt1->format('Y-m-d'), + 'currentDate' => $dt2->format('Y-m-d H:i:s'), 'cbm' => $cbm, 'pricePerCBM' => $pricePerCBM, 'storageInvoice' => new TransactionWithStorageResource($storageInvoice) @@ -292,7 +295,7 @@ class CheckStorageInvoiceTransactionProcessor } - private function isPaidOrWaivedStorageInvoiceExist($transaction, $packingList, $eta){ + private function isExistPaidOrWaivedStorageInvoice($transaction, $packingList, $eta){ $pricePerCBM = 3; $resultNumberOfDaysFree = 10; $dt1 = $eta->copy()->addDay()->startOfDay(); @@ -347,6 +350,21 @@ class CheckStorageInvoiceTransactionProcessor return []; } + private function isExistPendingVerificationManualPayment($storageInvoice){ + $g = $storageInvoice->groups()->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::SUSPENDED])->where('payment_method', PaymentMethodType::CASH)->latest('updated_at')->first(); + Log::channel('storage_invoices')->info('group: ' .json_encode($g)); + if($g){ + $gr = $g->reference; + $manualPaymentTransaction =Transaction::where('payment_reference', $gr)->first(); + Log::channel('storage_invoices')->info('manualPaymentTransaction: ' .json_encode($manualPaymentTransaction)); + if($manualPaymentTransaction->status === ApprovalStatus::PENDING_SUBMISSION || $manualPaymentTransaction->status === ApprovalStatus::PENDING_VERIFICATION){ + Log::channel('storage_invoices')->info('isExistPendingVerificationManualPayment'); + return true; + } + } + return false; + } + private function updatePaymentTransactionViaGroupPayment($storageInvoice){ LogHelper::channel('storage_invoices')->info('updatePaymentTransactionViaGroupPayment'); $groups = $storageInvoice->groups()->whereNotIn('status', [ApprovalStatus::COMPLETED, ApprovalStatus::SUSPENDED])->get(); @@ -360,7 +378,7 @@ class CheckStorageInvoiceTransactionProcessor $this->updatesTransactionStatus->execute($walletTransaction, ApprovalStatus::EXPIRED); if($walletTransaction->payment_reference){ $deletedBillplzBill = $this->deletesBillplzBill->execute($walletTransaction->payment_reference); - LogHelper::channel('storage_invoices')->info('deletedBillplzBill TransactionType::WALLET: '.json_encode($deletedBillplzBill)); + Log::channel('storage_invoices')->info('deletedBillplzBill TransactionType::WALLET: '.json_encode($deletedBillplzBill)); } } } diff --git a/app/Classes/ValueObjects/Constants/RemarkTypes.php b/app/Classes/ValueObjects/Constants/RemarkTypes.php index 9629e89a..7c233594 100644 --- a/app/Classes/ValueObjects/Constants/RemarkTypes.php +++ b/app/Classes/ValueObjects/Constants/RemarkTypes.php @@ -10,4 +10,6 @@ final class RemarkTypes public const EXTERNAL = 1; -} \ No newline at end of file + public const ADDRESS_EXTRA_COLUMNS = 2; + +} diff --git a/app/Http/Resources/AddressResource.php b/app/Http/Resources/AddressResource.php index 70461cd6..5d2d8b5b 100644 --- a/app/Http/Resources/AddressResource.php +++ b/app/Http/Resources/AddressResource.php @@ -27,6 +27,9 @@ class AddressResource extends JsonResource $outstationPostcodeConstant = $outstationPostcodeConstantObject->isEmpty() ? [] : (array)$outstationPostcodeConstantObject->first()->value; in_array((String)$this->postcode, $outstationPostcodeConstant) ? $postcodeArea = 'OUTSTATION_POSTCODE' : null; + $extrafields = json_decode($this->addressExtraFields->first()); + $extrafields = $extrafields ? (isset($extrafields->content) ? json_decode($extrafields->content) : null) : null; + return [ 'id' => $this->id, 'reference' => $this->reference, @@ -43,6 +46,11 @@ class AddressResource extends JsonResource 'contact' => new ContactResource($this->contacts->first()), 'remark' => new RemarkResource($this->remarks->first()), 'type' => $this->type, + 'extrafields' => $extrafields, + 'property_type' => $extrafields ? $extrafields->property_type : null, + 'tools_required_unload' => $extrafields ? $extrafields->tools_required_unload : null, + 'pickup_time_from' => $extrafields ? $extrafields->pickup_time_from : null, + 'pickup_time_to' => $extrafields ? $extrafields->pickup_time_to : null, $this->mergeWhen($this->relationLoaded('owner'), [ 'owner' => $this->when($this->owner instanceof Order, [ 'reference' => $this->owner->reference, diff --git a/app/Http/Resources/CompanyResource.php b/app/Http/Resources/CompanyResource.php index d969ac0d..27a04166 100644 --- a/app/Http/Resources/CompanyResource.php +++ b/app/Http/Resources/CompanyResource.php @@ -40,7 +40,8 @@ class CompanyResource extends JsonResource 'last_order' => $companyModule->type === 7 ? new DeliveryOrderResource($companyModule->orders()->orderBy('id', 'DESC')->first()) : new OrderResource($companyModule->orders()->orderBy('id', 'DESC')->first()), 'order_count' => $companyModule->orders()->count(), 'identification' => new DocumentResource($this->documents->whereIn('document_type', DocumentType::IDENTIFICATION_DOCUMENTS)->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::APPROVED])->first()), - 'created_at' => $this->created_at->format('d-m-Y') + 'created_at' => $this->created_at->format('d-m-Y'), + 'whatsapp' => new ContactResource($this->contacts()->where('reference', 'LIKE', '%Whatsapp%')->orderBy('created_at', 'DESC')->first()) ]; diff --git a/app/Http/Resources/SegmentResource.php b/app/Http/Resources/SegmentResource.php index 2ec22145..85c61f61 100644 --- a/app/Http/Resources/SegmentResource.php +++ b/app/Http/Resources/SegmentResource.php @@ -18,7 +18,7 @@ class SegmentResource extends JsonResource $constant = $this->constants->where('reference', SegmentConstants::CUSTOM_PRICE)->first(); return [ 'id' => $this->id, - 'name' => $this->name, + 'name' => ucwords(str_replace('_', ' ', $this->name)), 'price' => $constant ? $constant->value[0] : 0 ]; } diff --git a/app/Http/Resources/TransactionWithStorageResource.php b/app/Http/Resources/TransactionWithStorageResource.php index dd307ad8..52f35fdf 100644 --- a/app/Http/Resources/TransactionWithStorageResource.php +++ b/app/Http/Resources/TransactionWithStorageResource.php @@ -5,6 +5,7 @@ namespace App\Http\Resources; use App\Classes\ValueObjects\Constants\ApprovalStatus; use App\Classes\ValueObjects\Constants\TransactionType; use App\Models\Group; +use App\Models\PackingList; use App\Models\Transaction; use App\Models\Wallet; use Carbon\Carbon; @@ -27,7 +28,9 @@ class TransactionWithStorageResource extends JsonResource $groupPaymentAttemptsFiltered = []; $group_payment_expired = null; $group_payment_history = null; + $group_payment_history_query = null; $groupTotalAmount = 0; + $payment_history = null; if ($this->owner instanceof Transaction) { if ($this->owner) { @@ -43,7 +46,8 @@ class TransactionWithStorageResource extends JsonResource if($this->groups){ $group_payment_attempts = GroupForOrderV2Resource::collection($this->groups->whereNotIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::COMPLETED])); $group_payment_expired = GroupForOrderV2Resource::collection($this->groupsWithTrashed->whereIn('status', [ApprovalStatus::EXPIRED])); - $group_payment_history = GroupForOrderV2Resource::collection($this->groups->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::REJECTED])); + $group_payment_history_query = $this->groups->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::REJECTED]); + $group_payment_history = GroupForOrderV2Resource::collection($group_payment_history_query); } } else { @@ -54,9 +58,13 @@ class TransactionWithStorageResource extends JsonResource } + $packingListReference = null; + if ($this->owner instanceof PackingList) { + $packingListReference = $this->owner->reference; + } $ts = $this->groups->whereIn('status', [ApprovalStatus::PENDING_VERIFICATION])->last(); - if ($ts) { + if ($ts && $group_payment_history && $group_payment_attempts) { $paymentTransaction = Transaction::where('payment_reference', $ts->reference)->whereIn('status', [ApprovalStatus::PENDING_SUBMISSION])->first(); if($paymentTransaction){ $groupTotalAmount = (double) $this->amount; @@ -76,6 +84,21 @@ class TransactionWithStorageResource extends JsonResource } + $payment_history = TransactionResource::collection($this->transactions() + ->payments() + ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::REJECTED]) + ->get()); + + //For 'Your Payment Proof' at frontend + + if($group_payment_history_query && count($group_payment_history_query) > 0){ + if($this->getReferenceForGroupPayment($group_payment_history_query)){ + foreach ($payment_history as $item) { + $item['payment_reference'] = $this->getReferenceForGroupPayment($group_payment_history_query); + } + } + } + return [ 'id' => $this->id, 'owner_type' => $this->owner_type, @@ -112,13 +135,9 @@ class TransactionWithStorageResource extends JsonResource ->payments()->where('status', ApprovalStatus::EXPIRED) ->get() ), - 'payment_history' => TransactionResource::collection( - $this->transactions() - ->payments() - ->whereIn('status', [ApprovalStatus::APPROVED, ApprovalStatus::PENDING_VERIFICATION, ApprovalStatus::COMPLETED, ApprovalStatus::REJECTED]) - ->get() - ), + 'payment_history' => $payment_history, 'remarks' => RemarkResource::collection($this->remarks), + 'packing_list_reference' => $packingListReference, '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:i:s A'), @@ -126,4 +145,12 @@ class TransactionWithStorageResource extends JsonResource 'created_at' => Carbon::parse($this->created_at)->format('d-m-Y') ]; } + + private function getReferenceForGroupPayment($groups){ + if(count($groups)){ + $firstGroup = $groups[0]; + return $firstGroup['reference']; + } + return null; + } } diff --git a/app/Models/Address.php b/app/Models/Address.php index 32ac4841..ca41c484 100644 --- a/app/Models/Address.php +++ b/app/Models/Address.php @@ -5,6 +5,7 @@ namespace App\Models; use App\Classes\General\Interfaces\Contactable; use App\Classes\General\Interfaces\Remarkable; use Barryvdh\LaravelIdeHelper\Eloquent; +use App\Classes\ValueObjects\Constants\RemarkTypes; use Illuminate\Database\Eloquent\Builder; use Illuminate\Database\Eloquent\Collection; use Illuminate\Database\Eloquent\Model; @@ -142,4 +143,12 @@ class Address extends AbstractModel implements Contactable, Remarkable { return $this->morphMany(Remark::class, 'owner'); } + + /** + * @return MorphMany + */ + public function addressExtraFields(): MorphMany + { + return $this->morphMany(Remark::class, 'owner')->where('type', RemarkTypes::ADDRESS_EXTRA_COLUMNS); + } } diff --git a/app/Models/CompanyConnection.php b/app/Models/CompanyConnection.php index b382e237..894cdafc 100644 --- a/app/Models/CompanyConnection.php +++ b/app/Models/CompanyConnection.php @@ -69,4 +69,12 @@ class CompanyConnection extends AbstractModel return $this->belongsToMany(Segment::class, (new ConnectionSegment())->getTable(), 'company_connection_id', 'segment_id'); } + /** + * @return belongsToMany + */ + public function connectionSegments(): HasMany + { + return $this->hasMany(ConnectionSegment::class, 'company_connection_id'); + } + } diff --git a/app/Models/KeyValuePair.php b/app/Models/KeyValuePair.php new file mode 100644 index 00000000..3ad6d6cd --- /dev/null +++ b/app/Models/KeyValuePair.php @@ -0,0 +1,15 @@ +morphTo(); + } +} diff --git a/app/Models/Order.php b/app/Models/Order.php index 8bb7955f..f1bfd9f0 100644 --- a/app/Models/Order.php +++ b/app/Models/Order.php @@ -4,6 +4,7 @@ namespace App\Models; use App\Classes\General\Interfaces\Addressable; use App\Classes\General\Interfaces\Contactable; +use App\Classes\General\Interfaces\KeyValueInterface; use App\Classes\General\Interfaces\Packable; use App\Classes\General\Interfaces\Remarkable; use App\Classes\General\Interfaces\Notifiable; @@ -75,7 +76,7 @@ use Staudenmeir\EloquentHasManyDeep\HasRelationships; * @method static Builder|Order withoutTrashed() * @mixin Eloquent */ -class Order extends AbstractModel implements Addressable, Packable, Remarkable, Notifiable +class Order extends AbstractModel implements Addressable, Packable, Remarkable, Notifiable, KeyValueInterface { use SoftDeletes; use HasRelationships; @@ -225,4 +226,9 @@ class Order extends AbstractModel implements Addressable, Packable, Remarkable, { return $this->hasManyDeep(Transaction::class, [PackingList::class], ['owner_id', 'owner_id'], ['id', 'id']); } + + public function attributes(): MorphMany + { + return $this->morphMany(KeyValuePair::class, 'owner'); + } } diff --git a/config/logging.php b/config/logging.php index 9db3d892..c1833677 100644 --- a/config/logging.php +++ b/config/logging.php @@ -149,6 +149,24 @@ return [ 'groupNamePrefix' => env('CLOUDWATCH_LOGGROUP_PREFIX'), ], + 'apiResponseTimeLog' => [ + 'driver' => 'single', + 'path' => storage_path('logs/apiResponseTime.log'), + 'level' => 'info', + ], + + 'webResponseTimeLog' => [ + 'driver' => 'single', + 'path' => storage_path('logs/webResponseTimeLog.log'), + 'level' => 'info', + ], + + 'priceCbmLog' => [ + 'driver' => 'single', + 'path' => storage_path('logs/priceCbmLog.log'), + 'level' => 'info', + ], + 'deletePaidGroupOrder' => [ 'driver' => 'single', 'path' => storage_path('logs/deletePaidGroupOrder.log'), diff --git a/database/migrations/2024_06_02_135259_create_key_value_pairs_table.php b/database/migrations/2024_06_02_135259_create_key_value_pairs_table.php new file mode 100644 index 00000000..b952ff56 --- /dev/null +++ b/database/migrations/2024_06_02_135259_create_key_value_pairs_table.php @@ -0,0 +1,37 @@ +id(); + $table->string('owner_type'); //'user', 'order', 'transaction' + $table->unsignedBigInteger('owner_id'); + $table->string('key'); + $table->string('value'); + $table->timestamps(); + + $table->index(['owner_type', 'owner_id']); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::dropIfExists('key_value_pairs'); + } +} diff --git a/database/migrations/2024_06_12_110706_add_type_to_remarks_table.php b/database/migrations/2024_06_12_110706_add_type_to_remarks_table.php new file mode 100644 index 00000000..76ed8bac --- /dev/null +++ b/database/migrations/2024_06_12_110706_add_type_to_remarks_table.php @@ -0,0 +1,32 @@ +string('type')->nullable(); + }); + } + + /** + * Reverse the migrations. + * + * @return void + */ + public function down() + { + Schema::table('remarks', function (Blueprint $table) { + $table->dropColumn('type'); + }); + } +} diff --git a/package.json b/package.json index 534b3459..a86f3379 100644 --- a/package.json +++ b/package.json @@ -31,6 +31,7 @@ "vue": "^2.6.10", "vue-avatar": "^2.1.8", "vue-debounce": "^2.6.0", + "vue-gtag": "^1.16.1", "vue-template-compiler": "^2.6.10", "vue-the-mask": "^0.11.1", "vuelidate": "^0.7.4", diff --git a/resources/assets/vue/app.js b/resources/assets/vue/app.js index aa1668a2..23b19672 100644 --- a/resources/assets/vue/app.js +++ b/resources/assets/vue/app.js @@ -2,6 +2,7 @@ /** Dependencies */ import Vue from 'vue' import store from './vuex/store'; +import VueGtag from 'vue-gtag' window.route = require('./general/functions/router'); @@ -47,7 +48,7 @@ Vue.mixin({ asset: window.Vapor.asset }, mixins: [request, crudHandler] - }); +}); /** Components Registrations */ Vue.component(Avatar); @@ -55,6 +56,16 @@ Vue.component(Avatar); const files = require.context('./', true, /\.vue$/i); files.keys().map(key => Vue.component(key.split('/').pop().split('.')[0], files(key).default)); +// Google Analytics 4 (GA4) Integration +Vue.use(VueGtag, { + property: { + id: 'G-SP04J05142', + params: { + user_id: store.getters.getUserId + } + } +}); + const app = new Vue({ el: '#app', store, diff --git a/resources/assets/vue/components/addresses/forms/AddressFormComponent.vue b/resources/assets/vue/components/addresses/forms/AddressFormComponent.vue index 11fe9c7a..ca7748b0 100644 --- a/resources/assets/vue/components/addresses/forms/AddressFormComponent.vue +++ b/resources/assets/vue/components/addresses/forms/AddressFormComponent.vue @@ -3,14 +3,6 @@
Packinglist Reference
+
+ + Please Select a Segment +
+