diff --git a/app/Enums/CuttingStatus.php b/app/Enums/CuttingStatus.php index 6cc2076..af9c7c9 100644 --- a/app/Enums/CuttingStatus.php +++ b/app/Enums/CuttingStatus.php @@ -3,6 +3,7 @@ namespace App\Enums; use App\Traits\ProvidesEnumOptions; +use InvalidArgumentException; enum CuttingStatus: string { @@ -24,4 +25,62 @@ public function label(): string self::REJECTED => 'Ditolak', }; } + + public function isEditable(): bool + { + return in_array($this, [self::IN_PROGRESS, self::REJECTED], true); + } + + public function canTransitionTo(self $status): bool + { + return match ($this) { + self::IN_PROGRESS => $status === self::COMPLETED, + self::COMPLETED => in_array($status, [self::PENDING_VERIFICATION, self::REJECTED, self::IN_PROGRESS], true), + self::PENDING_VERIFICATION => in_array($status, [self::VERIFIED, self::REJECTED, self::COMPLETED], true), + self::REJECTED => $status === self::IN_PROGRESS, + default => false, + }; + } + + public function transitionPermission(): Permission + { + return match ($this) { + self::COMPLETED => Permission::CUTTINGS_COMPLETE, + self::PENDING_VERIFICATION => Permission::CUTTINGS_VERIFY, + self::VERIFIED => Permission::CUTTINGS_VERIFY, + self::REJECTED => Permission::CUTTINGS_REJECT, + self::IN_PROGRESS => Permission::CUTTINGS_UPDATE, + default => throw new InvalidArgumentException('Status tidak mendukung transisi.'), + }; + } + + /** + * @return list + */ + public function availableActions(): array + { + return match ($this) { + self::IN_PROGRESS => [ + [ + 'status' => self::COMPLETED->value, + 'label' => 'Selesai', + 'destructive' => false, + 'permission' => Permission::CUTTINGS_COMPLETE->value, + 'icon_only' => false, + ], + ], + self::COMPLETED => [], + self::PENDING_VERIFICATION => [], + self::REJECTED => [ + [ + 'status' => self::IN_PROGRESS->value, + 'label' => 'Kembalikan ke Proses', + 'destructive' => false, + 'permission' => Permission::CUTTINGS_UPDATE->value, + 'icon_only' => false, + ], + ], + default => [], + }; + } } diff --git a/app/Enums/OrderStatus.php b/app/Enums/OrderStatus.php index 169120d..4b19b82 100644 --- a/app/Enums/OrderStatus.php +++ b/app/Enums/OrderStatus.php @@ -3,6 +3,7 @@ namespace App\Enums; use App\Traits\ProvidesEnumOptions; +use InvalidArgumentException; enum OrderStatus: string { @@ -22,4 +23,70 @@ public function label(): string self::CANCELLED => 'Dibatalkan', }; } + + public function isEditable(): bool + { + return in_array($this, [self::PENDING, self::PROCESSING], true); + } + + public function canTransitionTo(self $status): bool + { + return match ($this) { + self::PENDING => in_array($status, [self::PROCESSING, self::CANCELLED], true), + self::PROCESSING => in_array($status, [self::COMPLETED, self::CANCELLED], true), + self::COMPLETED, self::CANCELLED => false, + }; + } + + public function transitionPermission(): Permission + { + return match ($this) { + self::PROCESSING => Permission::ORDERS_SEND, + self::COMPLETED => Permission::ORDERS_COMPLETE, + self::CANCELLED => Permission::ORDERS_CANCEL, + default => throw new InvalidArgumentException('Status tidak mendukung transisi.'), + }; + } + + /** + * @return list + */ + public function availableActions(): array + { + return match ($this) { + self::PENDING => [ + [ + 'status' => self::PROCESSING->value, + 'label' => 'Kirim', + 'destructive' => false, + 'permission' => Permission::ORDERS_SEND->value, + 'icon_only' => true, + ], + [ + 'status' => self::CANCELLED->value, + 'label' => 'Batalkan', + 'destructive' => true, + 'permission' => Permission::ORDERS_CANCEL->value, + 'icon_only' => true, + ], + ], + self::PROCESSING => [ + [ + 'status' => self::COMPLETED->value, + 'label' => 'Selesai', + 'destructive' => false, + 'permission' => Permission::ORDERS_COMPLETE->value, + 'icon_only' => true, + ], + [ + 'status' => self::CANCELLED->value, + 'label' => 'Batalkan', + 'destructive' => true, + 'permission' => Permission::ORDERS_CANCEL->value, + 'icon_only' => true, + ], + ], + default => [], + }; + } } diff --git a/app/Enums/Permission.php b/app/Enums/Permission.php index 39d8516..94aa1c9 100644 --- a/app/Enums/Permission.php +++ b/app/Enums/Permission.php @@ -267,4 +267,12 @@ public function group(): string self::ROLES_DELETE => 'Role & Permission', }; } + + /** + * @return list + */ + public static function values(): array + { + return array_column(self::cases(), 'value'); + } } diff --git a/app/Enums/Role.php b/app/Enums/Role.php index eb7edce..6ef8a7c 100644 --- a/app/Enums/Role.php +++ b/app/Enums/Role.php @@ -285,4 +285,44 @@ public function permissions(): array ], }; } + + public function isAssignable(): bool + { + return $this !== self::DEVELOPER; + } + + /** + * @return list + */ + public static function assignableSelectOptions(): array + { + return collect(self::cases()) + ->filter(fn (self $role) => $role->isAssignable()) + ->map(fn (self $role) => [ + 'value' => $role->value, + 'label' => $role->label(), + ]) + ->values() + ->all(); + } + + /** + * @return list + */ + public static function assignableValues(): array + { + return collect(self::cases()) + ->filter(fn (self $role) => $role->isAssignable()) + ->map(fn (self $role) => $role->value) + ->values() + ->all(); + } + + /** + * @return list + */ + public static function values(): array + { + return array_column(self::cases(), 'value'); + } } diff --git a/app/Http/Controllers/Admin/Hr/EmployeeController.php b/app/Http/Controllers/Admin/Hr/EmployeeController.php index 7339d33..fb1c642 100644 --- a/app/Http/Controllers/Admin/Hr/EmployeeController.php +++ b/app/Http/Controllers/Admin/Hr/EmployeeController.php @@ -27,16 +27,7 @@ public function __construct( private function assignableRoleOptions(): array { - $assignable = config('roles.assignable', []); - - return collect(Role::cases()) - ->filter(fn (Role $role) => in_array($role->value, $assignable, true)) - ->map(fn (Role $role) => [ - 'value' => $role->value, - 'label' => $role->label(), - ]) - ->values() - ->all(); + return Role::assignableSelectOptions(); } public function index(Request $request): Response diff --git a/app/Http/Requests/Admin/Hr/EmployeeRequest.php b/app/Http/Requests/Admin/Hr/EmployeeRequest.php index 5993eae..2020263 100644 --- a/app/Http/Requests/Admin/Hr/EmployeeRequest.php +++ b/app/Http/Requests/Admin/Hr/EmployeeRequest.php @@ -36,7 +36,7 @@ public function rules(): array 'gender' => ['nullable', Rule::enum(Gender::class)], 'birth_date' => ['nullable', 'date', 'before:today'], 'address' => ['nullable', 'string'], - 'role' => ['required', Rule::in(config('roles.assignable', []))], + 'role' => ['required', Rule::in(Role::assignableValues())], ]; if (! $isOwner) { diff --git a/app/Http/Requests/Admin/Manage/CuttingStatusTransitionRequest.php b/app/Http/Requests/Admin/Manage/CuttingStatusTransitionRequest.php index e181b71..6397eaf 100644 --- a/app/Http/Requests/Admin/Manage/CuttingStatusTransitionRequest.php +++ b/app/Http/Requests/Admin/Manage/CuttingStatusTransitionRequest.php @@ -26,10 +26,13 @@ public function authorize(): bool || false; } - $permissions = config('cutting-status.permissions', $status); - $permission = $permissions[$status->value] ?? null; + try { + $permission = $status->transitionPermission(); + } catch (\InvalidArgumentException) { + return false; + } - return $permission ? ($this->user()?->can($permission->value) ?? false) : false; + return $this->user()?->can($permission->value) ?? false; } /** @@ -76,10 +79,7 @@ public function withValidator(Validator $validator): void return; } - $transitions = config('cutting-status.transitions', []); - $allowedTargets = $transitions[$cutting->status->value] ?? []; - - if (! in_array($status, $allowedTargets, true)) { + if (! $cutting->status->canTransitionTo($status)) { $validator->errors()->add('status', 'Status cutting tidak dapat diubah.'); } diff --git a/app/Http/Requests/Admin/Manage/OrderRequest.php b/app/Http/Requests/Admin/Manage/OrderRequest.php index f1ff257..9095ca0 100644 --- a/app/Http/Requests/Admin/Manage/OrderRequest.php +++ b/app/Http/Requests/Admin/Manage/OrderRequest.php @@ -90,7 +90,7 @@ public function withValidator(Validator $validator): void /** @var Order $order */ $order = $this->route('order'); - if (! in_array($order->status, config('order-status.editable'), true)) { + if (! $order->status->isEditable()) { $validator->errors()->add('status', 'Pesanan tidak dapat diubah.'); } }); diff --git a/app/Http/Requests/Admin/Manage/OrderStatusTransitionRequest.php b/app/Http/Requests/Admin/Manage/OrderStatusTransitionRequest.php index b95234a..599921f 100644 --- a/app/Http/Requests/Admin/Manage/OrderStatusTransitionRequest.php +++ b/app/Http/Requests/Admin/Manage/OrderStatusTransitionRequest.php @@ -18,10 +18,13 @@ public function authorize(): bool return false; } - $permissions = config('order-status.permissions', []); - $permission = $permissions[$status->value] ?? null; + try { + $permission = $status->transitionPermission(); + } catch (\InvalidArgumentException) { + return false; + } - return $permission ? ($this->user()?->can($permission->value) ?? false) : false; + return $this->user()?->can($permission->value) ?? false; } /** @@ -55,10 +58,7 @@ public function withValidator(Validator $validator): void return; } - $transitions = config('order-status.transitions', []); - $allowedTargets = $transitions[$order->status->value] ?? []; - - if (! in_array($status, $allowedTargets, true)) { + if (! $order->status->canTransitionTo($status)) { $validator->errors()->add('status', 'Status pesanan tidak dapat diubah.'); } }); diff --git a/app/Services/Manage/CuttingService.php b/app/Services/Manage/CuttingService.php index 73eb44c..746d6ce 100644 --- a/app/Services/Manage/CuttingService.php +++ b/app/Services/Manage/CuttingService.php @@ -30,22 +30,17 @@ public function __construct( public function isEditable(CuttingStatus $status): bool { - return in_array($status, config('cutting-status.editable'), true); + return $status->isEditable(); } public function canTransitionTo(CuttingStatus $from, CuttingStatus $to): bool { - $transitions = config('cutting-status.transitions', []); - - return in_array($to, $transitions[$from->value] ?? [], true); + return $from->canTransitionTo($to); } public function transitionPermission(CuttingStatus $status): Permission { - $permissions = config('cutting-status.permissions', []); - - return $permissions[$status->value] - ?? throw new \InvalidArgumentException('Status tidak mendukung transisi.'); + return $status->transitionPermission(); } /** @@ -53,7 +48,7 @@ public function transitionPermission(CuttingStatus $status): Permission */ public function availableActions(CuttingStatus $status): array { - return config('cutting-status.actions.'.$status->value, []); + return $status->availableActions(); } /** diff --git a/app/Services/Manage/OrderService.php b/app/Services/Manage/OrderService.php index d10a96c..7424d5c 100644 --- a/app/Services/Manage/OrderService.php +++ b/app/Services/Manage/OrderService.php @@ -36,22 +36,17 @@ public function __construct( public function isEditable(OrderStatus $status): bool { - return in_array($status, config('order-status.editable'), true); + return $status->isEditable(); } public function canTransitionTo(OrderStatus $from, OrderStatus $to): bool { - $transitions = config('order-status.transitions', []); - - return in_array($to, $transitions[$from->value] ?? [], true); + return $from->canTransitionTo($to); } public function transitionPermission(OrderStatus $status): Permission { - $permissions = config('order-status.permissions', []); - - return $permissions[$status->value] - ?? throw new \InvalidArgumentException('Status tidak mendukung transisi.'); + return $status->transitionPermission(); } /** @@ -59,7 +54,7 @@ public function transitionPermission(OrderStatus $status): Permission */ public function availableActions(OrderStatus $status): array { - return config('order-status.actions.'.$status->value, []); + return $status->availableActions(); } public function defaultPriceType(OrderChannel $channel): ?PriceType