diff --git a/app/Actions/Analytics/GetSectionRoute.php b/app/Actions/Analytics/GetSectionRoute.php index fa4e7f3c12..b9d7817087 100644 --- a/app/Actions/Analytics/GetSectionRoute.php +++ b/app/Actions/Analytics/GetSectionRoute.php @@ -212,7 +212,7 @@ public function parseGroupSections(string $route, $routeParameters): AikuScopedS } if ($routeParameters) { - return AikuScopedSection::where('code', $sectionCode)->where('model_slug', $routeParameters['group'])->first(); + return AikuScopedSection::where('code', $sectionCode)->where('model_slug', group()->slug)->first(); } else { return AikuScopedSection::where('code', $sectionCode)->first(); } diff --git a/app/Actions/Catalogue/Shop/Hydrators/ShopHydrateSales.php b/app/Actions/Catalogue/Shop/Hydrators/ShopHydrateSales.php index 41efe84fd9..394a2549fa 100644 --- a/app/Actions/Catalogue/Shop/Hydrators/ShopHydrateSales.php +++ b/app/Actions/Catalogue/Shop/Hydrators/ShopHydrateSales.php @@ -67,5 +67,16 @@ public function handle(Shop $shop, ?array $intervals = null, $doPreviousInterval $shop->salesIntervals()->update($stats); } + public string $commandSignature = 'test'; + + public function asCommand($command) + { + $f = Shop::all(); + foreach ($f as $fulfilment) { + $this->handle($fulfilment); + } + } + + } diff --git a/app/Actions/Comms/DispatchedEmail/Hydrators/DispatchedEmailHydrateEmailTracking.php b/app/Actions/Comms/DispatchedEmail/Hydrators/DispatchedEmailHydrateEmailTracking.php new file mode 100644 index 0000000000..1be0754027 --- /dev/null +++ b/app/Actions/Comms/DispatchedEmail/Hydrators/DispatchedEmailHydrateEmailTracking.php @@ -0,0 +1,50 @@ + + * Created: Thu, 20 Feb 2025 13:37:24 Central Indonesia Time, Sanur, Bali, Indonesia + * Copyright (c) 2025, Raul A Perusquia Flores + */ + +namespace App\Actions\Comms\DispatchedEmail\Hydrators; + +use App\Actions\Traits\WithEnumStats; +use App\Enums\Comms\EmailTrackingEvent\EmailTrackingEventTypeEnum; +use App\Models\Comms\DispatchedEmail; +use Illuminate\Queue\Middleware\WithoutOverlapping; +use Lorisleiva\Actions\Concerns\AsAction; + +class DispatchedEmailHydrateEmailTracking +{ + use AsAction; + use WithEnumStats; + + private DispatchedEmail $dispatchedEmail; + + public function __construct(DispatchedEmail $dispatchedEmail) + { + $this->dispatchedEmail = $dispatchedEmail; + } + + public function getJobMiddleware(): array + { + return [(new WithoutOverlapping($this->dispatchedEmail->id))->dontRelease()]; + } + + + public function handle(DispatchedEmail $dispatchedEmail): void + { + $stats = [ + 'number_clicks' => $dispatchedEmail + ->emailTrackingEvents() + ->where('type', EmailTrackingEventTypeEnum::CLICKED) + ->count(), + 'number_reads' => $dispatchedEmail + ->emailTrackingEvents() + ->where('type', EmailTrackingEventTypeEnum::OPENED) + ->count() + ]; + + $dispatchedEmail->update($stats); + } +} diff --git a/app/Actions/Comms/DispatchedEmail/UpdateDispatchedEmail.php b/app/Actions/Comms/DispatchedEmail/UpdateDispatchedEmail.php index 411af4fd67..966c321dca 100644 --- a/app/Actions/Comms/DispatchedEmail/UpdateDispatchedEmail.php +++ b/app/Actions/Comms/DispatchedEmail/UpdateDispatchedEmail.php @@ -40,7 +40,7 @@ public function authorize(ActionRequest $request): bool public function rules(): array { $rules = [ - 'ses_id' => ['sometimes', 'required', 'string'], + 'provider_dispatch_id' => ['sometimes', 'required', 'string'], 'state' => ['sometimes', 'required', Rule::enum(DispatchedEmailStateEnum::class)] ]; if (!$this->strict) { diff --git a/app/Actions/Comms/EmailTrackingEvent/StoreEmailTrackingEvent.php b/app/Actions/Comms/EmailTrackingEvent/StoreEmailTrackingEvent.php index 253ffa2d05..3bf5153fd0 100644 --- a/app/Actions/Comms/EmailTrackingEvent/StoreEmailTrackingEvent.php +++ b/app/Actions/Comms/EmailTrackingEvent/StoreEmailTrackingEvent.php @@ -8,6 +8,7 @@ namespace App\Actions\Comms\EmailTrackingEvent; +use App\Actions\Comms\DispatchedEmail\Hydrators\DispatchedEmailHydrateEmailTracking; use App\Actions\OrgAction; use App\Actions\Traits\Rules\WithNoStrictRules; use App\Enums\Comms\EmailTrackingEvent\EmailTrackingEventTypeEnum; @@ -27,6 +28,8 @@ public function handle(DispatchedEmail $dispatchedEmail, array $modelData): Emai /** @var EmailTrackingEvent $emailTrackingEvent */ $emailTrackingEvent = $dispatchedEmail->emailTrackingEvents()->create($modelData); + DispatchedEmailHydrateEmailTracking::dispatch($dispatchedEmail); + return $emailTrackingEvent; } diff --git a/app/Actions/Comms/Notifications/GetSnsNotification.php b/app/Actions/Comms/Notifications/GetSnsNotification.php index 3c87d9edef..e1e5bb5fc2 100644 --- a/app/Actions/Comms/Notifications/GetSnsNotification.php +++ b/app/Actions/Comms/Notifications/GetSnsNotification.php @@ -24,7 +24,6 @@ public function asController(ServerRequestInterface $request): string { $message = Message::fromPsrRequest($request); $validator = new MessageValidator(); - if ($validator->isValid($message)) { if ($message['Type'] == 'SubscriptionConfirmation') { file_get_contents($message['SubscribeURL']); @@ -45,7 +44,7 @@ public function asController(ServerRequestInterface $request): string ] ); - // ProcessSesNotification::dispatch($sesNotification); + ProcessSesNotification::run($sesNotification); } } diff --git a/app/Actions/Comms/SesNotification/ProcessSesNotification.php b/app/Actions/Comms/SesNotification/ProcessSesNotification.php index 5c40ca6fe7..68ea225a7a 100644 --- a/app/Actions/Comms/SesNotification/ProcessSesNotification.php +++ b/app/Actions/Comms/SesNotification/ProcessSesNotification.php @@ -8,137 +8,77 @@ namespace App\Actions\Comms\SesNotification; -use App\Actions\Comms\DispatchedEmail\UpdateDispatchedEmail; use App\Actions\Comms\EmailTrackingEvent\StoreEmailTrackingEvent; -use App\Actions\CRM\Prospect\UpdateProspectEmailClicked; -use App\Actions\CRM\Prospect\UpdateProspectEmailHardBounced; -use App\Actions\CRM\Prospect\UpdateProspectEmailOpened; -use App\Actions\CRM\Prospect\UpdateProspectEmailSoftBounced; -use App\Actions\CRM\Prospect\UpdateProspectEmailUnsubscribed; +use App\Actions\Traits\WithActionUpdate; use App\Actions\Utils\IsGoogleIp; use App\Enums\Comms\DispatchedEmail\DispatchedEmailStateEnum; -use App\Enums\Comms\DispatchedEmailEvent\DispatchedEmailEventTypeEnum; +use App\Enums\Comms\EmailTrackingEvent\EmailTrackingEventTypeEnum; use App\Models\Comms\DispatchedEmail; use App\Models\Comms\SesNotification; use Exception; use Illuminate\Console\Command; use Illuminate\Support\Arr; -use Illuminate\Support\Carbon; use Lorisleiva\Actions\Concerns\AsAction; class ProcessSesNotification { use AsAction; + use WithActionUpdate; public function handle(SesNotification $sesNotification): ?array { - $dispatchedEmail = DispatchedEmail::where('provider_message_id', $sesNotification->message_id)->first(); + $dispatchedEmail = DispatchedEmail::where('provider_dispatch_id', $sesNotification->message_id)->first(); if (!$dispatchedEmail) { $sesNotification->delete(); return []; } + + $additionalData = []; + switch (Arr::get($sesNotification->data, 'eventType')) { case 'Bounce': - $type = DispatchedEmailEventTypeEnum::BOUNCE; - $date = Arr::get($sesNotification->data, 'bounce.timestamp'); $data = Arr::only($sesNotification->data['bounce'], ['bounceType', 'bounceSubType', 'reportingMTA']); - $isHardBounce = Arr::get($sesNotification->data, 'bounce.bounceType') == 'Permanent'; - if ($dispatchedEmail->recipient_type == 'Prospect') { - if ($isHardBounce) { - UpdateProspectEmailHardBounced::run( - $dispatchedEmail->recipient, - new Carbon($date) - ); - } else { - UpdateProspectEmailSoftBounced::run( - $dispatchedEmail->recipient, - new Carbon($date) - ); - } - } - + $type = EmailTrackingEventTypeEnum::SOFT_BOUNCE; + $dispatchedEmailState = DispatchedEmailStateEnum::SOFT_BOUNCE; if ($isHardBounce) { - $dispatchedEmail->email()->update( - [ - 'is_hard_bounced' => true, - 'hard_bounce_type' => Arr::get($sesNotification->data, 'bounce.bounceSubType') - ] - ); + $type = EmailTrackingEventTypeEnum::HARD_BOUNCE; + $dispatchedEmailState = DispatchedEmailStateEnum::HARD_BOUNCE; } - UpdateDispatchedEmail::run( - $dispatchedEmail, - [ - 'state' => $isHardBounce ? DispatchedEmailStateEnum::HARD_BOUNCE : DispatchedEmailStateEnum::SOFT_BOUNCE, - 'date' => $date, - 'is_hard_bounced' => $isHardBounce, - 'is_soft_bounced' => !$isHardBounce - - ] - ); - break; case 'Complaint': - $type = DispatchedEmailEventTypeEnum::COMPLAIN; - $date = Arr::get($sesNotification->data, 'complaint.timestamp'); + $type = EmailTrackingEventTypeEnum::MARKED_AS_SPAM; + $dispatchedEmailState = DispatchedEmailStateEnum::SPAM; $data = Arr::only($sesNotification->data['complaint'], ['userAgent', 'complaintSubType', 'complaintFeedbackType']); - if ($dispatchedEmail->recipient_type == 'Prospect') { - UpdateProspectEmailUnsubscribed::run($dispatchedEmail->recipient, new Carbon($date)); - } + $additionalData = [ + 'mask_as_spam' => true + ]; - UpdateDispatchedEmail::run( - $dispatchedEmail, - [ - 'state' => DispatchedEmailStateEnum::SPAM, - 'is_spam' => true, - 'date' => $date, - ] - ); break; case 'Delivery': - $type = DispatchedEmailEventTypeEnum::DELIVERY; - $date = Arr::get($sesNotification->data, 'delivery.timestamp'); + $type = EmailTrackingEventTypeEnum::DELIVERED; + $dispatchedEmailState = DispatchedEmailStateEnum::DELIVERED; $data = Arr::only($sesNotification->data['delivery'], ['remoteMtaIp', 'smtpResponse']); - UpdateDispatchedEmail::run( - $dispatchedEmail, - [ - 'state' => DispatchedEmailStateEnum::DELIVERED, - 'date' => $date, - 'delivered_at' => $date, - 'is_delivered' => true - ] - ); break; case 'Reject': + $type = EmailTrackingEventTypeEnum::DECLINED_BY_PROVIDER; + $dispatchedEmailState = DispatchedEmailStateEnum::REJECTED_BY_PROVIDER; + $data = Arr::only($sesNotification->data['reject'], ['ipAddress', 'userAgent']); - if ($dispatchedEmail->state == DispatchedEmailStateEnum::READY) { - UpdateDispatchedEmail::run( - $dispatchedEmail, - [ - 'state' => DispatchedEmailStateEnum::REJECTED, - 'is_rejected' => true, - ] - ); - } - $sesNotification->delete(); - - return null; - + break; case 'Open': - $type = DispatchedEmailEventTypeEnum::OPEN; - $date = Arr::get($sesNotification->data, 'open.timestamp'); + $type = EmailTrackingEventTypeEnum::OPENED; + $dispatchedEmailState = DispatchedEmailStateEnum::OPENED; $data = Arr::only($sesNotification->data['open'], ['ipAddress', 'userAgent']); - - if (Arr::get($data, 'userAgent') == "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/42.0.2311.135 Safari/537.36 Edge/12.246 Mozilla/5.0" and IsGoogleIp::run(Arr::get($data, 'ipAddress')) ) { @@ -146,53 +86,40 @@ public function handle(SesNotification $sesNotification): ?array return null; } + $additionalData = [ + 'last_read_at' => now() + ]; - if ($dispatchedEmail->recipient_type == 'Prospect') { - UpdateProspectEmailOpened::run($dispatchedEmail->recipient, new Carbon($date)); + if (!$dispatchedEmail->first_read_at) { + $additionalData = [ + 'first_read_at' => now(), + 'last_read_at' => now() + ]; } - UpdateDispatchedEmail::run( - $dispatchedEmail, - [ - 'state' => DispatchedEmailStateEnum::OPENED, - 'date' => $date, - 'is_opened' => true - ] - ); - break; case 'Click': - StoreEmailTrackingEvent::make()->action($dispatchedEmail, [ - 'provider_reference' => $sesNotification->message_id - ]); - /* $type = DispatchedEmailEventTypeEnum::CLICK; - $date = Arr::get($sesNotification->data, 'click.timestamp'); - $data = Arr::only($sesNotification->data['click'], ['ipAddress', 'userAgent', 'link', 'linkTags']); - - if ($dispatchedEmail->recipient_type == 'Prospect') { - UpdateProspectEmailClicked::run($dispatchedEmail->recipient, new Carbon($date)); - }*/ - - // Create storetracking event and call hydrators - - /* UpdateDispatchedEmail::run( - $dispatchedEmail, - [ - 'state' => DispatchedEmailStateEnum::CLICKED, - 'date' => $date, - 'is_clicked' => true - ] - );*/ + $type = EmailTrackingEventTypeEnum::CLICKED; + $dispatchedEmailState = DispatchedEmailStateEnum::CLICKED; + $data = Arr::only($sesNotification->data['click'], ['ipAddress', 'userAgent']); + + $additionalData = [ + 'last_clicked_at' => now() + ]; + + if (!$dispatchedEmail->first_read_at) { + $additionalData = [ + 'first_clicked_at' => now(), + 'last_clicked_at' => now() + ]; + } break; case 'DeliveryDelay': - $type = DispatchedEmailEventTypeEnum::DELIVERY_DELAY; - $date = Arr::get($sesNotification->data, 'deliveryDelay.timestamp'); - $data = Arr::only( - $sesNotification->data['deliveryDelay'], - ['delayType', 'expirationTime', 'reportingMTA'] - ); + $type = EmailTrackingEventTypeEnum::DECLINED_BY_PROVIDER; + $dispatchedEmailState = DispatchedEmailStateEnum::DELAY; + $data = Arr::only($sesNotification->data['deliveryDelay'], ['ipAddress', 'userAgent']); break; @@ -200,18 +127,18 @@ public function handle(SesNotification $sesNotification): ?array return $sesNotification->data; } - $sesNotification->delete(); - - - $eventData = [ + StoreEmailTrackingEvent::make()->action($dispatchedEmail, [ + 'provider_reference' => $sesNotification->message_id, 'type' => $type, - 'date' => $date, 'data' => $data - ]; + ]); + $this->update($dispatchedEmail, [ + 'state' => $dispatchedEmailState, + ...$additionalData + ]); - $dispatchedEmail->events()->create($eventData); - + $sesNotification->delete(); return null; } diff --git a/app/Actions/Fulfilment/Fulfilment/Hydrators/FulfilmentHydrateRecurringBills.php b/app/Actions/Fulfilment/Fulfilment/Hydrators/FulfilmentHydrateRecurringBills.php index 1eafc4ca87..1362b0a515 100644 --- a/app/Actions/Fulfilment/Fulfilment/Hydrators/FulfilmentHydrateRecurringBills.php +++ b/app/Actions/Fulfilment/Fulfilment/Hydrators/FulfilmentHydrateRecurringBills.php @@ -36,9 +36,9 @@ public function handle(Fulfilment $fulfilment): void { $stats = [ 'number_recurring_bills' => $fulfilment->recurringBills()->count(), - 'current_recurring_bills_amount' => $fulfilment->recurringBills->where('status',RecurringBillStatusEnum::CURRENT)->sum('net_amount'), - 'current_recurring_bills_amount_org_currency' => $fulfilment->recurringBills->where('status',RecurringBillStatusEnum::CURRENT)->sum('org_net_amount'), - 'current_recurring_bills_amount_grp_currency' => $fulfilment->recurringBills->where('status',RecurringBillStatusEnum::CURRENT)->sum('grp_net_amount'), + 'current_recurring_bills_amount' => $fulfilment->recurringBills->where('status', RecurringBillStatusEnum::CURRENT)->sum('net_amount'), + 'current_recurring_bills_amount_org_currency' => $fulfilment->recurringBills->where('status', RecurringBillStatusEnum::CURRENT)->sum('org_net_amount'), + 'current_recurring_bills_amount_grp_currency' => $fulfilment->recurringBills->where('status', RecurringBillStatusEnum::CURRENT)->sum('grp_net_amount'), ]; diff --git a/app/Actions/Fulfilment/Pallet/SetPalletInReturnAsPicked.php b/app/Actions/Fulfilment/Pallet/SetPalletInReturnAsPicked.php index 89c8774845..7bcea68172 100644 --- a/app/Actions/Fulfilment/Pallet/SetPalletInReturnAsPicked.php +++ b/app/Actions/Fulfilment/Pallet/SetPalletInReturnAsPicked.php @@ -16,13 +16,10 @@ use App\Enums\Fulfilment\Pallet\PalletStateEnum; use App\Enums\Fulfilment\Pallet\PalletStatusEnum; use App\Enums\Fulfilment\PalletReturn\PalletReturnItemStateEnum; -use App\Http\Resources\Fulfilment\PalletReturnItemResource; +use App\Http\Resources\Fulfilment\PalletReturnItemUIResource; use App\Models\CRM\WebUser; -use App\Models\Fulfilment\Fulfilment; use App\Models\Fulfilment\FulfilmentCustomer; use App\Models\Fulfilment\PalletReturnItem; -use App\Models\Inventory\Warehouse; -use App\Models\SysAdmin\Organisation; use Illuminate\Support\Facades\DB; use Lorisleiva\Actions\ActionRequest; @@ -118,13 +115,6 @@ public function asController(PalletReturnItem $palletReturnItem, ActionRequest $ } - public function fromApi(Organisation $organisation, Warehouse $warehouse, Fulfilment $fulfilment, PalletReturnItem $palletReturnItem, ActionRequest $request): PalletReturnItem - { - $this->pallet = $palletReturnItem; - $this->initialisationFromFulfilment($palletReturnItem->palletReturn->fulfilment, $request); - - return $this->handle($palletReturnItem); - } public function action(PalletReturnItem $palletReturnItem, array $modelData, int $hydratorsDelay = 0): PalletReturnItem { @@ -136,8 +126,8 @@ public function action(PalletReturnItem $palletReturnItem, array $modelData, int return $this->handle($palletReturnItem); } - public function jsonResponse(PalletReturnItem $palletReturnItem): PalletReturnItemResource + public function jsonResponse(PalletReturnItem $palletReturnItem): PalletReturnItemUIResource { - return new PalletReturnItemResource($palletReturnItem); + return new PalletReturnItemUIResource($palletReturnItem); } } diff --git a/app/Actions/Fulfilment/Pallet/UI/IndexPalletsInReturn.php b/app/Actions/Fulfilment/Pallet/UI/IndexPalletsInReturn.php index c4bfb48927..b6d88e0e9f 100644 --- a/app/Actions/Fulfilment/Pallet/UI/IndexPalletsInReturn.php +++ b/app/Actions/Fulfilment/Pallet/UI/IndexPalletsInReturn.php @@ -10,7 +10,7 @@ use App\Actions\OrgAction; use App\Actions\Traits\Authorisations\WithFulfilmentAuthorisation; -use App\Http\Resources\Fulfilment\PalletReturnItemsResource; +use App\Http\Resources\Fulfilment\PalletReturnItemsUIResource; use App\Models\Fulfilment\Pallet; use App\Models\Fulfilment\PalletReturn; use App\Models\Inventory\Warehouse; @@ -143,7 +143,7 @@ public function authorize(ActionRequest $request): bool public function jsonResponse(LengthAwarePaginator $pallets): AnonymousResourceCollection { - return PalletReturnItemsResource::collection($pallets); + return PalletReturnItemsUIResource::collection($pallets); } public function asController(Organisation $organisation, Warehouse $warehouse, PalletReturn $palletReturn, ActionRequest $request): LengthAwarePaginator diff --git a/app/Actions/Fulfilment/PalletReturn/IndexPalletsInReturnPalletWholePallets.php b/app/Actions/Fulfilment/PalletReturn/IndexPalletsInReturnPalletWholePallets.php index 82da5db772..7bf610c1ba 100644 --- a/app/Actions/Fulfilment/PalletReturn/IndexPalletsInReturnPalletWholePallets.php +++ b/app/Actions/Fulfilment/PalletReturn/IndexPalletsInReturnPalletWholePallets.php @@ -12,7 +12,7 @@ use App\Enums\Fulfilment\Pallet\PalletStatusEnum; use App\Enums\Fulfilment\PalletReturn\PalletReturnStateEnum; use App\Enums\Fulfilment\PalletReturn\PalletsInPalletReturnWholePalletsOptionEnum; -use App\Http\Resources\Fulfilment\PalletReturnItemsResource; +use App\Http\Resources\Fulfilment\PalletReturnItemsUIResource; use App\InertiaTable\InertiaTable; use App\Models\CRM\WebUser; use App\Models\Fulfilment\Pallet; @@ -143,7 +143,7 @@ public function authorize(ActionRequest $request): bool public function jsonResponse(LengthAwarePaginator $pallets): AnonymousResourceCollection { - return PalletReturnItemsResource::collection($pallets); + return PalletReturnItemsUIResource::collection($pallets); } public function asController(PalletReturn $palletReturn, ActionRequest $request): LengthAwarePaginator diff --git a/app/Actions/Fulfilment/PalletReturn/Json/GetPalletsInReturnPalletWholePallets.php b/app/Actions/Fulfilment/PalletReturn/Json/GetPalletsInReturnPalletWholePallets.php index 0061ebb9c4..9f90ac1c6c 100644 --- a/app/Actions/Fulfilment/PalletReturn/Json/GetPalletsInReturnPalletWholePallets.php +++ b/app/Actions/Fulfilment/PalletReturn/Json/GetPalletsInReturnPalletWholePallets.php @@ -12,7 +12,7 @@ use App\Actions\OrgAction; use App\Enums\Fulfilment\Pallet\PalletStatusEnum; use App\Enums\Fulfilment\PalletReturn\PalletReturnStateEnum; -use App\Http\Resources\Fulfilment\PalletReturnItemsResource; +use App\Http\Resources\Fulfilment\PalletReturnItemsUIResource; use App\InertiaTable\InertiaTable; use App\Models\CRM\WebUser; use App\Models\Fulfilment\Pallet; @@ -101,7 +101,7 @@ public function authorize(ActionRequest $request): bool public function jsonResponse(LengthAwarePaginator $pallets): AnonymousResourceCollection { - return PalletReturnItemsResource::collection($pallets); + return PalletReturnItemsUIResource::collection($pallets); } public function asController(PalletReturn $palletReturn, ActionRequest $request): LengthAwarePaginator diff --git a/app/Actions/Fulfilment/PalletReturn/UI/ShowPalletReturn.php b/app/Actions/Fulfilment/PalletReturn/UI/ShowPalletReturn.php index 22c1c89ee0..1cdd423e28 100644 --- a/app/Actions/Fulfilment/PalletReturn/UI/ShowPalletReturn.php +++ b/app/Actions/Fulfilment/PalletReturn/UI/ShowPalletReturn.php @@ -23,7 +23,7 @@ use App\Enums\UI\Fulfilment\PalletReturnTabsEnum; use App\Http\Resources\Fulfilment\FulfilmentCustomerResource; use App\Http\Resources\Fulfilment\FulfilmentTransactionsResource; -use App\Http\Resources\Fulfilment\PalletReturnItemsResource; +use App\Http\Resources\Fulfilment\PalletReturnItemsUIResource; use App\Http\Resources\Fulfilment\PalletReturnResource; use App\Http\Resources\Helpers\AddressResource; use App\Http\Resources\Helpers\Attachment\AttachmentsResource; @@ -701,8 +701,8 @@ public function htmlResponse(PalletReturn $palletReturn, ActionRequest $request) ], PalletReturnTabsEnum::PALLETS->value => $this->tab == PalletReturnTabsEnum::PALLETS->value ? - fn () => PalletReturnItemsResource::collection(IndexPalletsInReturnPalletWholePallets::run($palletReturn, PalletReturnTabsEnum::PALLETS->value)) - : Inertia::lazy(fn () => PalletReturnItemsResource::collection(IndexPalletsInReturnPalletWholePallets::run($palletReturn, PalletReturnTabsEnum::PALLETS->value))), + fn () => PalletReturnItemsUIResource::collection(IndexPalletsInReturnPalletWholePallets::run($palletReturn, PalletReturnTabsEnum::PALLETS->value)) + : Inertia::lazy(fn () => PalletReturnItemsUIResource::collection(IndexPalletsInReturnPalletWholePallets::run($palletReturn, PalletReturnTabsEnum::PALLETS->value))), PalletReturnTabsEnum::SERVICES->value => $this->tab == PalletReturnTabsEnum::SERVICES->value ? diff --git a/app/Actions/Fulfilment/PalletReturnItem/NotPickedPalletFromReturn.php b/app/Actions/Fulfilment/PalletReturnItem/NotPickedPalletFromReturn.php index 47458ff334..b7bd97f920 100644 --- a/app/Actions/Fulfilment/PalletReturnItem/NotPickedPalletFromReturn.php +++ b/app/Actions/Fulfilment/PalletReturnItem/NotPickedPalletFromReturn.php @@ -15,7 +15,7 @@ use App\Enums\Fulfilment\Pallet\PalletStateEnum; use App\Enums\Fulfilment\Pallet\PalletStatusEnum; use App\Enums\Fulfilment\PalletReturn\PalletReturnItemStateEnum; -use App\Http\Resources\Fulfilment\PalletReturnItemResource; +use App\Http\Resources\Fulfilment\PalletReturnItemUIResource; use App\Models\Fulfilment\PalletReturnItem; use Illuminate\Support\Arr; use Illuminate\Validation\Rule; @@ -98,8 +98,8 @@ public function action(PalletReturnItem $palletReturnItem, $state, int $hydrator return $this->handle($palletReturnItem, $this->validatedData); } - public function jsonResponse(PalletReturnItem $palletReturnItem): PalletReturnItemResource + public function jsonResponse(PalletReturnItem $palletReturnItem): PalletReturnItemUIResource { - return new PalletReturnItemResource($palletReturnItem); + return new PalletReturnItemUIResource($palletReturnItem); } } diff --git a/app/Actions/Fulfilment/PalletReturnItem/PickPalletReturnItem.php b/app/Actions/Fulfilment/PalletReturnItem/PickPalletReturnItem.php index 4aba72676d..8152a23adb 100644 --- a/app/Actions/Fulfilment/PalletReturnItem/PickPalletReturnItem.php +++ b/app/Actions/Fulfilment/PalletReturnItem/PickPalletReturnItem.php @@ -15,6 +15,8 @@ use App\Actions\OrgAction; use App\Actions\Traits\Authorisations\WithFulfilmentAuthorisation; use App\Actions\Traits\WithActionUpdate; +use App\Http\Resources\Fulfilment\PalletReturnItemResource; +use App\Http\Resources\Fulfilment\PalletReturnItemUIResource; use App\Models\Fulfilment\PalletReturnItem; use Illuminate\Support\Arr; use Illuminate\Support\Facades\DB; @@ -33,14 +35,14 @@ public function handle(PalletReturnItem $palletReturnItem, array $modelData): Pa { return DB::transaction(function () use ($palletReturnItem, $modelData) { $quantity = Arr::get($modelData, 'quantity_picked'); - $palletStoredItemQuant = $palletReturnItem->palletStoredItem->quantity; + $palletStoredItemQuantity = $palletReturnItem->palletStoredItem->quantity; $this->update($palletReturnItem, $modelData); StoreStoredItemMovementFromPicking::run($palletReturnItem, [ 'quantity' => $quantity ]); - if ($quantity == $palletStoredItemQuant) { + if ($quantity == $palletStoredItemQuantity) { SetPalletStoredItemStateToReturned::run($palletReturnItem->palletStoredItem); } @@ -66,4 +68,12 @@ public function asController(PalletReturnItem $palletReturnItem, ActionRequest $ return $this->handle($palletReturnItem, $this->validatedData); } + + public function jsonResponse(PalletReturnItem $palletReturnItem, ActionRequest $request): PalletReturnItemResource|PalletReturnItemUIResource + { + if ($request->hasHeader('Maya-Version')) { + return PalletReturnItemResource::make($palletReturnItem); + } + return PalletReturnItemUIResource::make($palletReturnItem); + } } diff --git a/app/Actions/Fulfilment/PalletReturnItem/UndoPalletReturnItem.php b/app/Actions/Fulfilment/PalletReturnItem/UndoPalletReturnItem.php index 3dd68129a8..c548879e40 100644 --- a/app/Actions/Fulfilment/PalletReturnItem/UndoPalletReturnItem.php +++ b/app/Actions/Fulfilment/PalletReturnItem/UndoPalletReturnItem.php @@ -15,7 +15,7 @@ use App\Enums\Fulfilment\Pallet\PalletStateEnum; use App\Enums\Fulfilment\PalletReturn\PalletReturnItemStateEnum; use App\Enums\Fulfilment\PalletReturn\PalletReturnStateEnum; -use App\Http\Resources\Fulfilment\PalletReturnItemResource; +use App\Http\Resources\Fulfilment\PalletReturnItemUIResource; use App\Models\Fulfilment\PalletReturnItem; use Lorisleiva\Actions\ActionRequest; @@ -87,8 +87,8 @@ public function action(PalletReturnItem $palletReturnItem, $state, int $hydrator return $this->handle($palletReturnItem); } - public function jsonResponse(PalletReturnItem $palletReturnItem): PalletReturnItemResource + public function jsonResponse(PalletReturnItem $palletReturnItem): PalletReturnItemUIResource { - return new PalletReturnItemResource($palletReturnItem); + return new PalletReturnItemUIResource($palletReturnItem); } } diff --git a/app/Actions/Fulfilment/PalletReturnItem/UndoPickingPalletFromReturn.php b/app/Actions/Fulfilment/PalletReturnItem/UndoPickingPalletFromReturn.php index 13c4f8cbac..4e785f3358 100644 --- a/app/Actions/Fulfilment/PalletReturnItem/UndoPickingPalletFromReturn.php +++ b/app/Actions/Fulfilment/PalletReturnItem/UndoPickingPalletFromReturn.php @@ -14,7 +14,7 @@ use App\Actions\Traits\WithActionUpdate; use App\Enums\Fulfilment\Pallet\PalletStateEnum; use App\Enums\Fulfilment\PalletReturn\PalletReturnItemStateEnum; -use App\Http\Resources\Fulfilment\PalletReturnItemResource; +use App\Http\Resources\Fulfilment\PalletReturnItemUIResource; use App\Models\Fulfilment\PalletReturnItem; use Lorisleiva\Actions\ActionRequest; @@ -75,8 +75,8 @@ public function action(PalletReturnItem $palletReturnItem, $state, int $hydrator return $this->handle($palletReturnItem); } - public function jsonResponse(PalletReturnItem $palletReturnItem): PalletReturnItemResource + public function jsonResponse(PalletReturnItem $palletReturnItem): PalletReturnItemUIResource { - return new PalletReturnItemResource($palletReturnItem); + return new PalletReturnItemUIResource($palletReturnItem); } } diff --git a/app/Actions/Retina/Fulfilment/FulfilmentTransaction/UpdateRetinaFulfilmentTransaction.php b/app/Actions/Retina/Fulfilment/FulfilmentTransaction/UpdateRetinaFulfilmentTransaction.php index cbd6201d85..0ecf3da87d 100644 --- a/app/Actions/Retina/Fulfilment/FulfilmentTransaction/UpdateRetinaFulfilmentTransaction.php +++ b/app/Actions/Retina/Fulfilment/FulfilmentTransaction/UpdateRetinaFulfilmentTransaction.php @@ -27,11 +27,11 @@ public function rules(): array ]; } - public function asController(FulfilmentTransaction $fulfilmentTransaction, ActionRequest $request): FulfilmentTransaction + public function asController(FulfilmentTransaction $fulfilmentTransaction, ActionRequest $request) { $this->initialisation($request); - return $this->handle($fulfilmentTransaction, $this->validatedData); + $this->handle($fulfilmentTransaction, $this->validatedData); } public function action(FulfilmentTransaction $fulfilmentTransaction, array $modelData): FulfilmentTransaction diff --git a/app/Actions/Retina/Fulfilment/PalletReturn/UI/ShowRetinaPalletReturn.php b/app/Actions/Retina/Fulfilment/PalletReturn/UI/ShowRetinaPalletReturn.php index 22a1d47d1f..68192f5946 100644 --- a/app/Actions/Retina/Fulfilment/PalletReturn/UI/ShowRetinaPalletReturn.php +++ b/app/Actions/Retina/Fulfilment/PalletReturn/UI/ShowRetinaPalletReturn.php @@ -20,7 +20,7 @@ use App\Enums\UI\Fulfilment\PalletReturnTabsEnum; use App\Http\Resources\Fulfilment\FulfilmentCustomerResource; use App\Http\Resources\Fulfilment\FulfilmentTransactionsResource; -use App\Http\Resources\Fulfilment\PalletReturnItemsResource; +use App\Http\Resources\Fulfilment\PalletReturnItemsUIResource; use App\Http\Resources\Fulfilment\PalletReturnResource; use App\Http\Resources\Fulfilment\PalletReturnsResource; use App\Http\Resources\Helpers\AddressResource; @@ -468,8 +468,8 @@ public function htmlResponse(PalletReturn $palletReturn, ActionRequest $request) 'data' => PalletReturnResource::make($palletReturn), PalletReturnTabsEnum::PALLETS->value => $this->tab == PalletReturnTabsEnum::PALLETS->value ? - fn () => PalletReturnItemsResource::collection(IndexPalletsInReturnPalletWholePallets::run($palletReturn, PalletReturnTabsEnum::PALLETS->value)) - : Inertia::lazy(fn () => PalletReturnItemsResource::collection(IndexPalletsInReturnPalletWholePallets::run($palletReturn, PalletReturnTabsEnum::PALLETS->value))), + fn () => PalletReturnItemsUIResource::collection(IndexPalletsInReturnPalletWholePallets::run($palletReturn, PalletReturnTabsEnum::PALLETS->value)) + : Inertia::lazy(fn () => PalletReturnItemsUIResource::collection(IndexPalletsInReturnPalletWholePallets::run($palletReturn, PalletReturnTabsEnum::PALLETS->value))), PalletReturnTabsEnum::SERVICES->value => $this->tab == PalletReturnTabsEnum::SERVICES->value ? fn () => FulfilmentTransactionsResource::collection(IndexServiceInPalletReturn::run($palletReturn, PalletReturnTabsEnum::SERVICES->value)) diff --git a/app/Actions/SysAdmin/Organisation/UI/ShowOrganisationDashboard.php b/app/Actions/SysAdmin/Organisation/UI/ShowOrganisationDashboard.php index aa54c27c4d..f1671f79eb 100644 --- a/app/Actions/SysAdmin/Organisation/UI/ShowOrganisationDashboard.php +++ b/app/Actions/SysAdmin/Organisation/UI/ShowOrganisationDashboard.php @@ -102,7 +102,7 @@ public function getDashboardInterval(Organisation $organisation, array $userSett ], ], 'widgets' => [ - 'column_count' => 4, + 'column_count' => 5, 'components' => [] ] ]; diff --git a/app/Actions/Traits/WithDashboard.php b/app/Actions/Traits/WithDashboard.php index a4648a2e1f..10982be866 100644 --- a/app/Actions/Traits/WithDashboard.php +++ b/app/Actions/Traits/WithDashboard.php @@ -103,6 +103,7 @@ protected function getIntervalPercentage($intervalData, string $prefix, $key, $t { $result = []; + // dd($intervalData->{$prefix . '_' . $key . '_ly'}); if ($key == 'all') { $result = [ 'amount' => $intervalData->{$prefix . '_all'} ?? null, @@ -121,7 +122,7 @@ protected function getIntervalPercentage($intervalData, string $prefix, $key, $t 'difference' => isset($intervalData->{$prefix . '_' . $key}, $intervalData->{$prefix . '_' . $key . '_ly'}) ? $intervalData->{$prefix . '_' . $key} - $intervalData->{$prefix . '_' . $key . '_ly'} : null, - 'tooltip' => "$tooltip" . Number::currency($intervalData->{$prefix . '_' . $key . '_ly'}, $currencyCode), + 'tooltip' => "$tooltip" . Number::currency($intervalData->{$prefix . '_' . $key . '_ly'} ?? 0, $currencyCode), ]; return $result; @@ -161,7 +162,14 @@ public function setDashboardTableData($parent, $childs, &$dashboard, &$visualDat foreach ($childs as $child) { $keyCurrency = $dashboard['settings']['key_currency']; $currencyCode = $selectedCurrency === $keyCurrency ? $parent->currency->code : $child->currency->code; + $salesCurrency = 'sales_'.$selectedCurrency.'_currency'; + + if ($parent instanceof Organisation) { + if ($selectedCurrency == 'shop') { + $salesCurrency = 'sales'; + } + } $responseData = array_merge([ 'name' => $child->name, 'slug' => $child->slug, diff --git a/app/Actions/UI/Profile/UpdateProfile.php b/app/Actions/UI/Profile/UpdateProfile.php index a76aea8907..bbe3ae4793 100644 --- a/app/Actions/UI/Profile/UpdateProfile.php +++ b/app/Actions/UI/Profile/UpdateProfile.php @@ -47,7 +47,8 @@ public function rules(): array 'nullable', File::image() ->max(12 * 1024) - ] + ], + 'settings' => ['sometimes'], ]; } diff --git a/app/Enums/Comms/DispatchedEmail/DispatchedEmailStateEnum.php b/app/Enums/Comms/DispatchedEmail/DispatchedEmailStateEnum.php index 5180dce7a3..3a9c879159 100644 --- a/app/Enums/Comms/DispatchedEmail/DispatchedEmailStateEnum.php +++ b/app/Enums/Comms/DispatchedEmail/DispatchedEmailStateEnum.php @@ -31,6 +31,8 @@ enum DispatchedEmailStateEnum: string case SPAM = 'spam'; case UNSUBSCRIBED = 'unsubscribed'; + case DELAY = 'delay'; + public static function labels(): array { @@ -47,6 +49,7 @@ public static function labels(): array 'clicked' => __('Clicked'), 'spam' => __('Spam'), 'unsubscribed' => __('Unsubscribed'), + 'delay' => __('Delay'), ]; } @@ -134,6 +137,12 @@ public static function stateIcon(): array 'class' => 'text-red-500' ], + 'delay' => [ + 'tooltip' => __('Delay'), + 'icon' => 'fal fa-hand-paper', + 'class' => 'text-red-500' + ], + ]; } } diff --git a/app/Enums/Comms/EmailTrackingEvent/EmailTrackingEventTypeEnum.php b/app/Enums/Comms/EmailTrackingEvent/EmailTrackingEventTypeEnum.php index 665e743d42..f24adf019b 100644 --- a/app/Enums/Comms/EmailTrackingEvent/EmailTrackingEventTypeEnum.php +++ b/app/Enums/Comms/EmailTrackingEvent/EmailTrackingEventTypeEnum.php @@ -23,4 +23,5 @@ enum EmailTrackingEventTypeEnum: string case HARD_BOUNCE = 'hard_bounce'; case MARKED_AS_SPAM = 'marked_as_spam'; case ERROR = 'error'; + case DELAY = 'delay'; } diff --git a/app/Http/Resources/Fulfilment/PalletReturnItemResource.php b/app/Http/Resources/Fulfilment/PalletReturnItemResource.php index 3ad9350729..36c02f2aa2 100644 --- a/app/Http/Resources/Fulfilment/PalletReturnItemResource.php +++ b/app/Http/Resources/Fulfilment/PalletReturnItemResource.php @@ -2,158 +2,66 @@ /* * Author: Raul Perusquia - * Created: Sat, 03 Feb 2024 11:07:20 Malaysia Time, Bali Airport, Indonesia - * Copyright (c) 2024, Raul A Perusquia Flores + * Created: Thu, 20 Feb 2025 12:57:53 Central Indonesia Time, Sanur, Bali, Indonesia + * Copyright (c) 2025, Raul A Perusquia Flores */ namespace App\Http\Resources\Fulfilment; -use App\Enums\Fulfilment\Pallet\PalletStateEnum; +use App\Models\Fulfilment\PalletReturnItem; use Illuminate\Http\Resources\Json\JsonResource; /** * @property mixed $id - * @property mixed $reference - * @property mixed $customer_reference - * @property mixed $fulfilment_customer_id - * @property mixed $slug - * @property mixed $notes + * *@property mixed $quantity_ordered + * @property mixed $quantity_dispatched + * @property mixed $quantity_fail + * @property mixed $quantity_cancelled * @property mixed $state - * @property mixed $type - * @property mixed $pivot - * @property mixed $status - * @property mixed $location_slug * @property mixed $location_code * @property mixed $location_id - * @property mixed $warehouse_id - * @property mixed $pallet_delivery_id - * @property mixed $pallet_return_id - * @property mixed $pallet_id - * @property mixed $fulfilment_customer_name - * @property mixed $fulfilment_customer_slug + * @property mixed $location_slug + * @property mixed $stored_items_reference + * @property mixed $stored_items_id + * @property mixed $stored_items_slug + * @property mixed $stored_items_name + * @property mixed $pallets_reference + * @property mixed $pallets_customer_reference + * @property mixed $pallets_id + * @property mixed $pallets_slug */ class PalletReturnItemResource extends JsonResource { public function toArray($request): array { + /** @var PalletReturnItem $palletReturnItem */ + $palletReturnItem = $this; + return [ - 'id' => $this->id, - 'pallet_id' => $this->pallet->id, - 'slug' => $this->pallet->slug, - 'reference' => $this->pallet->reference, - 'customer_reference' => (string)$this->pallet->customer_reference, - 'fulfilment_customer_name' => $this->pallet->fulfilment_customer_name, - 'fulfilment_customer_slug' => $this->pallet->fulfilment_customer_slug, - 'fulfilment_customer_id' => $this->pallet->fulfilment_customer_id, - 'notes' => (string)$this->pallet->notes, - 'state' => $this->pallet->state->value, - 'type_icon' => $this->pallet->type->typeIcon()[$this->pallet->type->value], - 'type' => $this->pallet->type, - 'state_label' => PalletStateEnum::labels()[$this->pallet->state->value], - 'state_icon' => PalletStateEnum::stateIcon()[$this->pallet->state->value], - 'status' => $this->pallet->status, - 'status_label' => $this->pallet->status->labels()[$this->pallet->status->value], - 'status_icon' => $this->pallet->status->statusIcon()[$this->pallet->status->value], - 'location' => $this->location_slug, - 'location_code' => $this->location_code, - 'stored_items' => $this->pallet->storedItems->map(fn ($storedItem) => [ - 'reference' => $storedItem->reference, - 'quantity' => (int)$storedItem->pivot->quantity, - ]), - 'stored_items_quantity' => (int)$this->pallet->storedItems()->sum('quantity'), - 'syncRoute' => match (request()->routeIs('retina.*')) { - true => [ - 'name' => 'retina.models.pallet.pallet-return-item.update', - 'parameters' => $this->id - ], - default => [ - 'name' => 'grp.models.pallet.pallet-return-item.sync', - 'parameters' => $this->id - ] - }, - 'updateRoute' => match (request()->routeIs('retina.*')) { - true => [ - 'name' => 'retina.models.pallet-return-item.update', - 'parameters' => $this->id - ], - default => [ - 'name' => 'grp.models.pallet-return-item.update', - 'parameters' => $this->id - ] - }, - 'undoPickingRoute' => [ - 'name' => 'grp.models.pallet-return-item.undo-picking', - 'parameters' => [$this->id] - ], - 'undoConfirmedRoute' => [ - 'name' => 'grp.models.pallet-return-item.undo-confirmed', - 'parameters' => [$this->id] - ], - 'notPickedRoute' => [ - 'method' => 'patch', - 'name' => 'grp.models.pallet-return-item.not-picked', - 'parameters' => [$this->id] - ], - 'deleteRoute' => match (request()->routeIs('retina.*')) { - true => [ - 'name' => 'retina.models.pallet.delete', - 'parameters' => $this->id - ], - default => [ - 'name' => 'grp.models.pallet.delete', - 'parameters' => $this->id - ] - }, - 'deleteFromDeliveryRoute' => match (request()->routeIs('retina.*')) { - true => [ - 'name' => 'retina.models.pallet-delivery.pallet.delete', - 'parameters' => [$this->pallet->pallet_delivery_id, $this->id] - ], - default => [ - 'name' => 'grp.models.fulfilment-customer.pallet-delivery.pallet.delete', - 'parameters' => [$this->pallet->fulfilment_customer_id, $this->pallet->pallet_delivery_id, $this->id] - ] - }, - 'deleteFromReturnRoute' => match (request()->routeIs('retina.*')) { - true => [ - 'name' => 'retina.models.pallet-return.pallet.delete', - 'parameters' => [$this->pallet->pallet_return_id, $this->pallet->id] - ], - default => [ - 'name' => 'grp.models.pallet-return.pallet.detach', - 'parameters' => [$this->pallet->pallet_return_id, $this->pallet->id] - ] - }, - 'notReceivedRoute' => [ - 'name' => 'grp.models.pallet.not-received', - 'parameters' => [$this->id] - ], - 'undoNotReceivedRoute' => [ - 'name' => 'grp.models.pallet.undo-not-received', - 'parameters' => [$this->id] - ], - 'bookInRoute' => [ - 'name' => 'grp.models.pallet.book_in', - 'parameters' => [$this->id] - ], - 'undoBookInRoute' => [ - 'name' => 'grp.models.pallet.undo_book_in', - 'parameters' => [$this->id] - ], - 'updateLocationRoute' => [ - 'name' => 'grp.models.warehouse.pallets.location.update', - 'parameters' => [$this->pallet->warehouse_id, $this->id] - ], - 'storeStoredItemRoute' => match (request()->routeIs('retina.*')) { - true => [ - 'name' => 'retina.models.pallet.stored-items.update', - 'parameters' => [$this->id] - ], - default => [ - 'name' => 'grp.models.pallet.stored-items.update', - 'parameters' => [$this->id] - ] - }, + 'id' => $palletReturnItem->id, + 'quantity_ordered' => $palletReturnItem->quantity_ordered, + 'quantity_dispatched' => $palletReturnItem->quantity_dispatched, + 'quantity_fail' => $palletReturnItem->quantity_fail, + 'quantity_cancelled' => $palletReturnItem->quantity_cancelled, + 'state' => $palletReturnItem->state, + 'state_icon' => $palletReturnItem->state->stateIcon()[$this->state->value], + + 'location_code' => $palletReturnItem->pickingLocation->code, + 'location_id' => $palletReturnItem->pickingLocation->id, + 'location_slug' => $palletReturnItem->pickingLocation->slug, + + + 'stored_items_reference' => $palletReturnItem->storedItem->reference, + 'stored_items_id' => $palletReturnItem->storedItem->id, + 'stored_items_slug' => $palletReturnItem->storedItem->slug, + 'stored_items_name' => $palletReturnItem->storedItem->name, + + 'pallets_reference' => $palletReturnItem->pallet->reference, + 'pallets_customer_reference' => $palletReturnItem->pallet->customer_reference, + 'pallets_id' => $palletReturnItem->pallet->id, + 'pallets_slug' => $palletReturnItem->pallet->slug, + + ]; } } diff --git a/app/Http/Resources/Fulfilment/PalletReturnItemUIResource.php b/app/Http/Resources/Fulfilment/PalletReturnItemUIResource.php new file mode 100644 index 0000000000..f8934e34d7 --- /dev/null +++ b/app/Http/Resources/Fulfilment/PalletReturnItemUIResource.php @@ -0,0 +1,159 @@ + + * Created: Thu, 20 Feb 2025 13:57:29 Central Indonesia Time, Sanur, Bali, Indonesia + * Copyright (c) 2025, Raul A Perusquia Flores + */ + +namespace App\Http\Resources\Fulfilment; + +use App\Enums\Fulfilment\Pallet\PalletStateEnum; +use Illuminate\Http\Resources\Json\JsonResource; + +/** + * @property mixed $id + * @property mixed $reference + * @property mixed $customer_reference + * @property mixed $fulfilment_customer_id + * @property mixed $slug + * @property mixed $notes + * @property mixed $state + * @property mixed $type + * @property mixed $pivot + * @property mixed $status + * @property mixed $location_slug + * @property mixed $location_code + * @property mixed $location_id + * @property mixed $warehouse_id + * @property mixed $pallet_delivery_id + * @property mixed $pallet_return_id + * @property mixed $pallet_id + * @property mixed $fulfilment_customer_name + * @property mixed $fulfilment_customer_slug + */ +class PalletReturnItemUIResource extends JsonResource +{ + public function toArray($request): array + { + return [ + 'id' => $this->id, + 'pallet_id' => $this->pallet->id, + 'slug' => $this->pallet->slug, + 'reference' => $this->pallet->reference, + 'customer_reference' => (string)$this->pallet->customer_reference, + 'fulfilment_customer_name' => $this->pallet->fulfilment_customer_name, + 'fulfilment_customer_slug' => $this->pallet->fulfilment_customer_slug, + 'fulfilment_customer_id' => $this->pallet->fulfilment_customer_id, + 'notes' => (string)$this->pallet->notes, + 'state' => $this->pallet->state->value, + 'type_icon' => $this->pallet->type->typeIcon()[$this->pallet->type->value], + 'type' => $this->pallet->type, + 'state_label' => PalletStateEnum::labels()[$this->pallet->state->value], + 'state_icon' => PalletStateEnum::stateIcon()[$this->pallet->state->value], + 'status' => $this->pallet->status, + 'status_label' => $this->pallet->status->labels()[$this->pallet->status->value], + 'status_icon' => $this->pallet->status->statusIcon()[$this->pallet->status->value], + 'location' => $this->location_slug, + 'location_code' => $this->location_code, + 'stored_items' => $this->pallet->storedItems->map(fn ($storedItem) => [ + 'reference' => $storedItem->reference, + 'quantity' => (int)$storedItem->pivot->quantity, + ]), + 'stored_items_quantity' => (int)$this->pallet->storedItems()->sum('quantity'), + 'syncRoute' => match (request()->routeIs('retina.*')) { + true => [ + 'name' => 'retina.models.pallet.pallet-return-item.update', + 'parameters' => $this->id + ], + default => [ + 'name' => 'grp.models.pallet.pallet-return-item.sync', + 'parameters' => $this->id + ] + }, + 'updateRoute' => match (request()->routeIs('retina.*')) { + true => [ + 'name' => 'retina.models.pallet-return-item.update', + 'parameters' => $this->id + ], + default => [ + 'name' => 'grp.models.pallet-return-item.update', + 'parameters' => $this->id + ] + }, + 'undoPickingRoute' => [ + 'name' => 'grp.models.pallet-return-item.undo-picking', + 'parameters' => [$this->id] + ], + 'undoConfirmedRoute' => [ + 'name' => 'grp.models.pallet-return-item.undo-confirmed', + 'parameters' => [$this->id] + ], + 'notPickedRoute' => [ + 'method' => 'patch', + 'name' => 'grp.models.pallet-return-item.not-picked', + 'parameters' => [$this->id] + ], + 'deleteRoute' => match (request()->routeIs('retina.*')) { + true => [ + 'name' => 'retina.models.pallet.delete', + 'parameters' => $this->id + ], + default => [ + 'name' => 'grp.models.pallet.delete', + 'parameters' => $this->id + ] + }, + 'deleteFromDeliveryRoute' => match (request()->routeIs('retina.*')) { + true => [ + 'name' => 'retina.models.pallet-delivery.pallet.delete', + 'parameters' => [$this->pallet->pallet_delivery_id, $this->id] + ], + default => [ + 'name' => 'grp.models.fulfilment-customer.pallet-delivery.pallet.delete', + 'parameters' => [$this->pallet->fulfilment_customer_id, $this->pallet->pallet_delivery_id, $this->id] + ] + }, + 'deleteFromReturnRoute' => match (request()->routeIs('retina.*')) { + true => [ + 'name' => 'retina.models.pallet-return.pallet.delete', + 'parameters' => [$this->pallet->pallet_return_id, $this->pallet->id] + ], + default => [ + 'name' => 'grp.models.pallet-return.pallet.detach', + 'parameters' => [$this->pallet->pallet_return_id, $this->pallet->id] + ] + }, + 'notReceivedRoute' => [ + 'name' => 'grp.models.pallet.not-received', + 'parameters' => [$this->id] + ], + 'undoNotReceivedRoute' => [ + 'name' => 'grp.models.pallet.undo-not-received', + 'parameters' => [$this->id] + ], + 'bookInRoute' => [ + 'name' => 'grp.models.pallet.book_in', + 'parameters' => [$this->id] + ], + 'undoBookInRoute' => [ + 'name' => 'grp.models.pallet.undo_book_in', + 'parameters' => [$this->id] + ], + 'updateLocationRoute' => [ + 'name' => 'grp.models.warehouse.pallets.location.update', + 'parameters' => [$this->pallet->warehouse_id, $this->id] + ], + 'storeStoredItemRoute' => match (request()->routeIs('retina.*')) { + true => [ + 'name' => 'retina.models.pallet.stored-items.update', + 'parameters' => [$this->id] + ], + default => [ + 'name' => 'grp.models.pallet.stored-items.update', + 'parameters' => [$this->id] + ] + }, + ]; + } +} diff --git a/app/Http/Resources/Fulfilment/PalletReturnItemsResource.php b/app/Http/Resources/Fulfilment/PalletReturnItemsUIResource.php similarity index 97% rename from app/Http/Resources/Fulfilment/PalletReturnItemsResource.php rename to app/Http/Resources/Fulfilment/PalletReturnItemsUIResource.php index 705505f39e..b7d2e0de77 100644 --- a/app/Http/Resources/Fulfilment/PalletReturnItemsResource.php +++ b/app/Http/Resources/Fulfilment/PalletReturnItemsUIResource.php @@ -33,7 +33,7 @@ * @property mixed $fulfilment_customer_name * @property mixed $fulfilment_customer_slug */ -class PalletReturnItemsResource extends JsonResource +class PalletReturnItemsUIResource extends JsonResource { public function toArray($request): array { @@ -59,7 +59,7 @@ public function toArray($request): array 'location' => $this->location_slug, 'location_code' => $this->location_code, 'location_id' => $this->location_id, - 'is_checked' => (bool) $this->pallet_return_id, + 'is_checked' => $this->state->value === PalletStateEnum::IN_PROCESS ? (bool) $this->pallet_return_id : false, 'stored_items' => $pallet->storedItems->map(fn ($storedItem) => [ 'reference' => $storedItem->reference, 'quantity' => (int)$storedItem->pivot->quantity, diff --git a/app/Http/Resources/Fulfilment/PalletReturnsResource.php b/app/Http/Resources/Fulfilment/PalletReturnsResource.php index ea39e21216..3a206f41c6 100644 --- a/app/Http/Resources/Fulfilment/PalletReturnsResource.php +++ b/app/Http/Resources/Fulfilment/PalletReturnsResource.php @@ -30,6 +30,7 @@ public function toArray($request): array { return [ 'id' => $this->id, + 'created_at' => $this->created_at, 'slug' => $this->slug, 'reference' => $this->reference, 'state' => $this->state, diff --git a/app/InertiaTable/InertiaTable.php b/app/InertiaTable/InertiaTable.php index fdc52aa4a2..d3b3d475f9 100644 --- a/app/InertiaTable/InertiaTable.php +++ b/app/InertiaTable/InertiaTable.php @@ -233,8 +233,8 @@ protected function transformRadioFilter(): Collection return $radioFilter; } - if(is_array($queryElements)){ - $queryElements=Arr::get($queryElements,'radio.value',''); + if (is_array($queryElements)) { + $queryElements = Arr::get($queryElements, 'radio.value', ''); } return $radioFilter->map(function (RadioFilterGroup $elementRadioGroup) use ($queryElements) { diff --git a/app/Models/Accounting/Invoice.php b/app/Models/Accounting/Invoice.php index 6f561243c9..5d2d08ff66 100644 --- a/app/Models/Accounting/Invoice.php +++ b/app/Models/Accounting/Invoice.php @@ -103,6 +103,7 @@ * @property-read Collection $fixedAddresses * @property-read \App\Models\Accounting\TFactory|null $use_factory * @property-read Group $group + * @property-read \App\Models\Accounting\InvoiceCategory|null $invoiceCategory * @property-read Collection $invoiceTransactions * @property-read Order|null $order * @property-read Collection $orders diff --git a/app/Models/Accounting/InvoiceCategory.php b/app/Models/Accounting/InvoiceCategory.php index c59500f3f5..ede442179e 100644 --- a/app/Models/Accounting/InvoiceCategory.php +++ b/app/Models/Accounting/InvoiceCategory.php @@ -42,6 +42,7 @@ * @property int|null $organisation_id * @property-read \Illuminate\Database\Eloquent\Collection $audits * @property-read \App\Models\SysAdmin\Group $group + * @property-read \Illuminate\Database\Eloquent\Collection $invoices * @property-read \App\Models\Accounting\InvoiceCategoryOrderingIntervals|null $orderingIntervals * @property-read \App\Models\SysAdmin\Organisation|null $organisation * @property-read \App\Models\Accounting\InvoiceCategorySalesIntervals|null $salesIntervals diff --git a/app/Models/CRM/Customer.php b/app/Models/CRM/Customer.php index 70eaf7a7ca..fb5f50e820 100644 --- a/app/Models/CRM/Customer.php +++ b/app/Models/CRM/Customer.php @@ -113,6 +113,7 @@ * @property bool $is_vip VIP customer * @property int|null $as_organisation_id Indicate customer is a organisation in this group * @property int|null $as_employee_id Indicate customer is a employee + * @property string|null $approved_at * @property-read Address|null $address * @property-read Collection $addresses * @property-read Collection $appointments diff --git a/app/Models/Fulfilment/PalletReturnItem.php b/app/Models/Fulfilment/PalletReturnItem.php index e9ad4ef98e..b298dd409a 100644 --- a/app/Models/Fulfilment/PalletReturnItem.php +++ b/app/Models/Fulfilment/PalletReturnItem.php @@ -9,6 +9,7 @@ namespace App\Models\Fulfilment; use App\Enums\Fulfilment\PalletReturn\PalletReturnItemStateEnum; +use App\Models\Inventory\Location; use Illuminate\Database\Eloquent\Model; use Illuminate\Database\Eloquent\Relations\BelongsTo; @@ -34,6 +35,8 @@ * @property-read \App\Models\Fulfilment\Pallet $pallet * @property-read \App\Models\Fulfilment\PalletReturn $palletReturn * @property-read \App\Models\Fulfilment\PalletStoredItem|null $palletStoredItem + * @property-read Location|null $pickingLocation + * @property-read \App\Models\Fulfilment\StoredItem|null $storedItem * @method static \Illuminate\Database\Eloquent\Builder|PalletReturnItem newModelQuery() * @method static \Illuminate\Database\Eloquent\Builder|PalletReturnItem newQuery() * @method static \Illuminate\Database\Eloquent\Builder|PalletReturnItem query() @@ -69,4 +72,15 @@ public function palletStoredItem(): BelongsTo { return $this->belongsTo(PalletStoredItem::class); } + + public function storedItem(): BelongsTo + { + return $this->belongsTo(StoredItem::class); + } + + public function pickingLocation(): BelongsTo + { + return $this->belongsTo(Location::class, 'picking_location_id'); + } + } diff --git a/app/Models/ShopifyUserHasFulfilment.php b/app/Models/ShopifyUserHasFulfilment.php index 2fd62e49a6..ee99291a14 100644 --- a/app/Models/ShopifyUserHasFulfilment.php +++ b/app/Models/ShopifyUserHasFulfilment.php @@ -24,9 +24,8 @@ * @property string $model_type * @property ShopifyFulfilmentStateEnum $state * @property int|null $customer_client_id - * @property string|null $no_fulfilment_reason + * @property ShopifyFulfilmentReasonEnum|null $no_fulfilment_reason * @property string|null $no_fulfilment_reason_notes - * @property ShopifyFulfilmentReasonEnum $reason * @property-read CustomerClient|null $customerClient * @property-read \Illuminate\Database\Eloquent\Model|\Eloquent $model * @property-read ShopifyUser $shopifyUser diff --git a/app/Services/QueryBuilder.php b/app/Services/QueryBuilder.php index 9e2a3950aa..bbf89d592e 100644 --- a/app/Services/QueryBuilder.php +++ b/app/Services/QueryBuilder.php @@ -53,7 +53,7 @@ public function whereRadioFilter( $argumentName = ($prefix ? $prefix.'_' : '').'radioFilter'; if (request()->has($argumentName) or $defaultValue) { $elements = request()->input("$argumentName") ?? $defaultValue; - if(is_array($elements)){ + if (is_array($elements)) { $elements = Arr::get($elements, 'radio.value'); } diff --git a/composer.lock b/composer.lock index 3af6c69d5f..6b220d415a 100644 --- a/composer.lock +++ b/composer.lock @@ -5378,28 +5378,29 @@ }, { "name": "inertiajs/inertia-laravel", - "version": "v1.3.2", + "version": "v2.0.0", "source": { "type": "git", "url": "https://github.com/inertiajs/inertia-laravel.git", - "reference": "7e6a030ffab315099782a4844a2175455f511c68" + "reference": "0259e37f802bc39c814c42ba92c04ada17921f70" }, "dist": { "type": "zip", - "url": "https://api.github.com/repos/inertiajs/inertia-laravel/zipball/7e6a030ffab315099782a4844a2175455f511c68", - "reference": "7e6a030ffab315099782a4844a2175455f511c68", + "url": "https://api.github.com/repos/inertiajs/inertia-laravel/zipball/0259e37f802bc39c814c42ba92c04ada17921f70", + "reference": "0259e37f802bc39c814c42ba92c04ada17921f70", "shasum": "" }, "require": { "ext-json": "*", - "laravel/framework": "^8.74|^9.0|^10.0|^11.0", - "php": "^7.3|~8.0.0|~8.1.0|~8.2.0|~8.3.0|~8.4.0", - "symfony/console": "^5.3|^6.0|^7.0" + "laravel/framework": "^10.0|^11.0", + "php": "^8.1.0", + "symfony/console": "^6.2|^7.0" }, "require-dev": { + "laravel/pint": "^1.16", "mockery/mockery": "^1.3.3", - "orchestra/testbench": "^6.45|^7.44|^8.25|^9.3", - "phpunit/phpunit": "^8.0|^9.5.8|^10.4", + "orchestra/testbench": "^8.0|^9.2", + "phpunit/phpunit": "^10.4|^11.0", "roave/security-advisories": "dev-master" }, "suggest": { @@ -5411,9 +5412,6 @@ "providers": [ "Inertia\\ServiceProvider" ] - }, - "branch-alias": { - "dev-master": "1.x-dev" } }, "autoload": { @@ -5442,7 +5440,7 @@ ], "support": { "issues": "https://github.com/inertiajs/inertia-laravel/issues", - "source": "https://github.com/inertiajs/inertia-laravel/tree/v1.3.2" + "source": "https://github.com/inertiajs/inertia-laravel/tree/v2.0.0" }, "funding": [ { diff --git a/package-lock.json b/package-lock.json index 4585361fa0..718e67238e 100644 --- a/package-lock.json +++ b/package-lock.json @@ -17,7 +17,7 @@ "@fortawesome/free-solid-svg-icons": "^6.1.2", "@fortawesome/vue-fontawesome": "^3.0.3", "@headlessui/vue": "^1.7.14", - "@inertiajs/vue3": "^1.0.16", + "@inertiajs/vue3": "^2.0.2", "@kyvg/vue3-notification": "^3.1.2", "@mailupinc/bee-plugin": "^2.3.0", "@newrelic/browser-agent": "^1.282.0", @@ -994,24 +994,23 @@ } }, "node_modules/@inertiajs/core": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-1.3.0.tgz", - "integrity": "sha512-TJ8R1eUYY473m9DaKlCPRdHTdznFWTDuy5VvEzXg3t/hohbDQedLj46yn/uAqziJPEUZJrSftZzPI2NMzL9tQA==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inertiajs/core/-/core-2.0.2.tgz", + "integrity": "sha512-G2Rs+Qbt0fnFme9hp3ZkCkXSVrTs2Cw4BcFeBN0BVFoxodRERg5ikp0P1RBfxr8gm3GP3C0SBNaJjhsXqkXUwg==", "license": "MIT", "dependencies": { "axios": "^1.6.0", "deepmerge": "^4.0.0", - "nprogress": "^0.2.0", "qs": "^6.9.0" } }, "node_modules/@inertiajs/vue3": { - "version": "1.3.0", - "resolved": "https://registry.npmjs.org/@inertiajs/vue3/-/vue3-1.3.0.tgz", - "integrity": "sha512-GizqdCM3u4JWunit3uUbW4fEmTLKQTi1W7VvPRdrNy8XDt4Qy2cCmfFjq+aH5tHBSS3fI/ngYuhN7XvwqNaKvw==", + "version": "2.0.2", + "resolved": "https://registry.npmjs.org/@inertiajs/vue3/-/vue3-2.0.2.tgz", + "integrity": "sha512-9if+h7MuOTK9vryLJLkgm7B6bqoFcwo0OYgvTbjzNVBXyUiE4U4KTmtjmvLfHJ6Msgdty6Ajhyle77oEQL6R/Q==", "license": "MIT", "dependencies": { - "@inertiajs/core": "1.3.0", + "@inertiajs/core": "2.0.2", "lodash.clonedeep": "^4.5.0", "lodash.isequal": "^4.5.0" }, @@ -5723,12 +5722,6 @@ "node": ">=8" } }, - "node_modules/nprogress": { - "version": "0.2.0", - "resolved": "https://registry.npmjs.org/nprogress/-/nprogress-0.2.0.tgz", - "integrity": "sha512-I19aIingLgR1fmhftnbWWO3dXc0hSxqHQHQb3H8m+K3TnEn/iSeTZZOyvKXWqQESMwuUVnatlCnZdLBZZt2VSA==", - "license": "MIT" - }, "node_modules/nth-check": { "version": "2.1.1", "resolved": "https://registry.npmjs.org/nth-check/-/nth-check-2.1.1.tgz", diff --git a/package.json b/package.json index 35311c184e..7ac221647b 100644 --- a/package.json +++ b/package.json @@ -50,7 +50,7 @@ "@fortawesome/free-solid-svg-icons": "^6.1.2", "@fortawesome/vue-fontawesome": "^3.0.3", "@headlessui/vue": "^1.7.14", - "@inertiajs/vue3": "^1.0.16", + "@inertiajs/vue3": "^2.0.2", "@kyvg/vue3-notification": "^3.1.2", "@mailupinc/bee-plugin": "^2.3.0", "@newrelic/browser-agent": "^1.282.0", diff --git a/resources/js/Components/CMS/Website/Outboxes/Beefree.vue b/resources/js/Components/CMS/Website/Outboxes/Beefree.vue index 54b841ad84..0356c237bd 100644 --- a/resources/js/Components/CMS/Website/Outboxes/Beefree.vue +++ b/resources/js/Components/CMS/Website/Outboxes/Beefree.vue @@ -59,6 +59,7 @@ const beeConfig = () => { console.log('vdv',props.mergeTags) const config = { + /* uid: token.value.userName, */ uid: 'CmsUserName', // Do not modify this container: "bee-plugin-container", language: "en-US", diff --git a/resources/js/Components/DataDisplay/Dashboard/DashboardSettings.vue b/resources/js/Components/DataDisplay/Dashboard/DashboardSettings.vue index eb0020fdf1..97cba224c6 100644 --- a/resources/js/Components/DataDisplay/Dashboard/DashboardSettings.vue +++ b/resources/js/Components/DataDisplay/Dashboard/DashboardSettings.vue @@ -55,7 +55,7 @@ watch( const isLoadingInterval = ref(null) const updateInterval = (interval_code: string) => { router.patch( - route("grp.models.user.update", layout.user?.id), + route("grp.models.profile.update"), { settings: { selected_interval: interval_code, @@ -77,7 +77,7 @@ const updateInterval = (interval_code: string) => { const isLoadingCurrency = ref(false) const updateCurrency = (currency_scope: string) => { router.patch( - route("grp.models.user.update", layout.user?.id), + route("grp.models.profile.update"), { settings: { [`selected_currency_in_${props.settings?.key_currency || "grp"}`]: currency_scope, @@ -97,7 +97,7 @@ const updateCurrency = (currency_scope: string) => { const updateShop = (shop_scope: string) => { router.patch( - route("grp.models.user.update", layout.user?.id), + route("grp.models.profile.update"), { settings: { [`selected_shop_state`]: shop_scope, @@ -117,7 +117,7 @@ const updateShop = (shop_scope: string) => { const updateAmountFormat = (amountFormat: string) => { router.patch( - route("grp.models.user.update", layout.user?.id), + route("grp.models.profile.update"), { settings: { [`selected_amount`]: amountFormat, diff --git a/resources/js/Components/DataDisplay/Dashboard/DashboardTable.vue b/resources/js/Components/DataDisplay/Dashboard/DashboardTable.vue index 475485e892..616ee00bb1 100644 --- a/resources/js/Components/DataDisplay/Dashboard/DashboardTable.vue +++ b/resources/js/Components/DataDisplay/Dashboard/DashboardTable.vue @@ -100,7 +100,7 @@ function useTabChangeDashboard(tab_slug: string) { diff --git a/resources/js/Composables/Listing/DashboardWidgetsList.ts b/resources/js/Composables/Listing/DashboardWidgetsList.ts index 6c4c67ead6..51bd83d75a 100644 --- a/resources/js/Composables/Listing/DashboardWidgetsList.ts +++ b/resources/js/Composables/Listing/DashboardWidgetsList.ts @@ -14,13 +14,14 @@ const OverviewDisplay = defineAsyncComponent(() => import('@/Components/DataDisp const OperationDisplay = defineAsyncComponent(() => import('@/Components/DataDisplay/Dashboard/Widget/OperationDisplay.vue')) const ChartDisplay = defineAsyncComponent(() => import('@/Components/DataDisplay/Dashboard/Widget/ChartDisplay.vue')) const CircleDisplay = defineAsyncComponent(() => import('@/Components/DataDisplay/Dashboard/Widget/CircleDisplay.vue')) +const DoubleDisplay = defineAsyncComponent(() => import('@/Components/DataDisplay/Dashboard/Widget/DoubleChart.vue')) export const widgetList: {[key: string]: Component} = { 'basic': BasicDisplay, 'flat_tree_map': FlatTreeMap, 'overview_display': OverviewDisplay, 'operation_display': OperationDisplay, - 'chart_display' : ChartDisplay, + 'chart_display' : DoubleDisplay, 'circle_display': CircleDisplay } diff --git a/resources/js/Stores/locale.ts b/resources/js/Stores/locale.ts index 66dfcdaee3..4bb9e64009 100644 --- a/resources/js/Stores/locale.ts +++ b/resources/js/Stores/locale.ts @@ -64,10 +64,8 @@ export const useLocaleStore = defineStore("locale", () => { if (useShort) { return new Intl.NumberFormat("en", { style: "currency", - currency: currencyCode, - minimumFractionDigits: 0, - maximumFractionDigits: 0 - }).format(number); + currency: currencyCode + }).format(number || 0); } else { let formattedNumber = new Intl.NumberFormat("en", { notation: "compact",