diff --git a/.ai/CONVENTIONS.md b/.ai/CONVENTIONS.md index a396fdf..b0550af 100644 --- a/.ai/CONVENTIONS.md +++ b/.ai/CONVENTIONS.md @@ -826,6 +826,42 @@ ### Stock Adjustment Pattern ## Form Request +### Validasi harus SESUAI dengan DB Schema +```php +// ✅ SELALU samakan max length dengan DB column +// DB: varchar(50) → max:50 +'name' => ['required', 'string', 'max:50'], + +// DB: varchar(200) → max:200 +'name' => ['required', 'string', 'max:200'], + +// DB: varchar(100) → max:100 +'description' => ['required', 'string', 'max:100'], + +// DB: text → tidak perlu max (atau max sesuai UI) +'address' => ['nullable', 'string'], + +// DB: decimal(10,7) → numeric + min/max range +'latitude' => ['required', 'numeric', 'min:-90', 'max:90'], +'longitude' => ['required', 'numeric', 'min:-180', 'max:180'], + +// DB: uint → integer, min:0 +'base_salary' => ['required', 'integer', 'min:0'], + +// DB: ubig → integer, min:1 (untuk amount) +'amount' => ['required', 'integer', 'min:1'], + +// DB: enum → Rule::in(Enum::values()) atau Rule::in(['val1', 'val2']) +'status' => ['required', Rule::in(OrderStatus::values())], +'gender' => ['nullable', 'in:male,female'], + +// DB: date → 'date' +'join_date' => ['required', 'date'], + +// DB: datetime → 'date' (Laravel handle) +'paid_at' => ['nullable', 'date'], +``` + ### Struktur Dasar ```php class ProductRequest extends FormRequest @@ -860,6 +896,38 @@ ### Struktur Dasar } ``` +### Rule Classes — Gunakan `Illuminate\Validation\Rule` +```php +use Illuminate\Validation\Rule; + +// ✅ SELALU gunakan Rule classes, JANGAN string-based rules + +// exists → Rule::exists('table', 'column') +'category_ids.*' => [Rule::exists('categories', 'id')], +'customer_id' => ['nullable', 'integer', Rule::exists('customers', 'id')], +'existing_items.*.raw_material_price_id' => ['required', 'integer', Rule::exists('raw_material_prices', 'id')], + +// required_if → Rule::requiredIf(fn () => ...) +'shared_prices' => [Rule::requiredIf(fn () => $useSamePrice), 'nullable', 'array'], +'existing_items' => [Rule::requiredIf(fn () => $this->input('mode') === 'existing'), 'array', 'min:1'], + +// required_unless → Rule::requiredUnless(fn () => ...) +'name' => [Rule::requiredUnless(fn () => $this->input('mode') === 'existing'), 'string', 'max:200'], +'unit' => [$this->isMethod('post') ? Rule::requiredUnless(fn () => $this->input('mode') === 'existing') : 'nullable', Rule::in(RawMaterialUnit::values())], + +// in → Rule::in(Enum::values()) atau Rule::in(['val1', 'val2']) +'status' => ['required', Rule::in(OrderStatus::values())], +'gender' => ['nullable', 'in:male,female'], + +// unique → Rule::unique('table')->ignore($id) +'name' => ['required', 'string', 'max:100', Rule::unique('categories')->ignore($this->route('category')?->id)], + +// ❌ JANGAN pakai string-based rules +'category_ids.*' => ['exists:categories,id'], // JANGAN +'shared_prices' => ['required_if:use_same_price,true', ...], // JANGAN +'name' => ['required_unless:mode,existing', ...], // JANGAN +``` + ### Currency Stripping ```php use App\Concerns\CurrencyStripping; @@ -874,11 +942,11 @@ ### Currency Stripping ### Unique Ignore ```php -// ✅ Saat update, ignore ID sendiri -Rule::unique('products')->ignore($this->route('product')?->id) +// ✅ Saat update, ignore ID sendiri — gunakan Rule::unique() +'name' => ['required', 'string', 'max:100', Rule::unique('categories')->ignore($this->route('category')?->id)], // ✅ Saat store, tidak perlu ignore -Rule::unique('products') +'name' => ['required', 'string', 'max:100', Rule::unique('categories')], ``` ### Shared Store/Update Request @@ -1468,6 +1536,7 @@ ### ✅ Do - Tidak perlu accessor untuk label — Enum sudah handle via `->label()` - Selalu select kolom yang dibutuhkan + eager load relasi - Selalu strip currency di FormRequest sebelum validasi +- Selalu pakai `Rule::exists()`, `Rule::requiredIf()`, `Rule::requiredUnless()` (bukan string-based rules) - Selalu pakai constructor promotion di controller (`public function __construct(private XService $service) {}`) - Selalu kirim enum options dari controller ke view (`Enum::toSelect()`) - Selalu pakai `handleAction()` untuk 2+ query @@ -1495,6 +1564,7 @@ ### ❌ Don't - Jangan hardcode enum values di view (ambil dari controller) - Jangan pakai `= new XService` (pakai dependency injection) - Jangan lupa strip currency saat input Rupiah +- Jangan pakai string-based rules seperti `'exists:table,id'`, `'required_if:field,value'`, `'required_unless:field,value'` (pakai Rule classes) - Jangan lupa `authorize()` di FormRequest (return true) - Jangan lupa `attributes()` di FormRequest (label Bahasa Indonesia) - JANGAN ada logic di controller (SEKECIL APAPUN) diff --git a/.ai/REFERENCE.md b/.ai/REFERENCE.md index 76bf4f5..725e192 100644 --- a/.ai/REFERENCE.md +++ b/.ai/REFERENCE.md @@ -312,3 +312,89 @@ ## Service Concerns | `HasStockAdjustment` | adjustStock(), adjustVariantStock(), applyStock(), reverseStock() | TransactionService, RestockService | | `RegistersMedia` | registerMedia(), syncPhoto() | CashAccountService, CuttingService, ExpenseService, PurchaseService, RestockService, TransactionService | +--- + +## Form Request Validation Rules + +> Validasi harus SESUAI dengan DB schema (type + max length). + +### Master + +| Request | Field | Rules | DB Match | +|---------|-------|-------|----------| +| `CategoryRequest` | `name` | `required, string, max:50, unique:categories,name` | ✅ varchar(50) | +| `CustomerRequest` | `name` | `required, string, max:200, unique:customers,name` | ✅ varchar(200) | +| `CustomerRequest` | `phone_number` | `nullable, string, max:20` | ✅ varchar(20) | +| `CustomerRequest` | `address` | `nullable, string` | ✅ text | +| `SupplierRequest` | `name` | `required, string, max:200, unique:suppliers,name` | ✅ varchar(200) | +| `SupplierRequest` | `phone_number` | `nullable, string, max:20` | ✅ varchar(20) | +| `RawMaterialRequest` | `name` | `required, string, max:200` | ✅ varchar(200) | +| `RawMaterialRequest` | `unit` | `required, in:kg,meter,yard` | ✅ enum | +| `RawMaterialVariantRequest` | `variant` | `required, string, max:200` | ✅ varchar(200) | +| `RawMaterialVariantRequest` | `price` | `required, integer, min:0` | ✅ uint | +| `ProductRequest` | `name` | `required, string, max:200` | ✅ varchar(200) | +| `ProductVariantRequest` | `name` | `required, string, max:200` | ✅ varchar(200) | + +### Finance + +| Request | Field | Rules | DB Match | +|---------|-------|-------|----------| +| `CashAccountRequest` | `name` | `required, string, max:200, unique:cash_accounts,name` | ✅ varchar(200) | +| `CashTransactionRequest` | `amount` | `required, integer, min:1` | ✅ ubig | +| `CashTransactionRequest` | `description` | `required, string, max:100` | ✅ varchar(100) | +| `ExpenseRequest` | `amount` | `required, integer, min:1` | ✅ ubig | +| `ExpenseRequest` | `description` | `required, string, max:100` | ✅ varchar(100) | +| `EmployeeAdvanceRequest` | `amount` | `required, integer, min:1` | ✅ ubig | +| `EmployeeAdvanceRequest` | `description` | `required, string, max:100` | ✅ varchar(100) | +| `EmployeeAdvanceRequest` | `due_date` | `required, date, after_or_equal:today` | ✅ date | +| `EmployeeAdvancePaymentRequest` | `amount` | `required, integer, min:1` | ✅ ubig | +| `EmployeeAdvancePaymentRequest` | `description` | `nullable, string, max:100` | ✅ varchar(100) nullable | +| `PayrollAdjustmentRequest` | `type` | `required, in:bonus,deduction` | ✅ enum | +| `PayrollAdjustmentRequest` | `amount` | `required, integer, min:1` | ✅ ubig | +| `PayrollAdjustmentRequest` | `description` | `required, string, max:100` | ✅ varchar(100) | + +### HR + +| Request | Field | Rules | DB Match | +|---------|-------|-------|----------| +| `EmployeeRequest` | `email` | `required, email, max:100, unique:users,email` | ✅ varchar(100) | +| `EmployeeRequest` | `username` | `required, string, max:20, alpha_dash, unique:users,username` | ✅ varchar(20) | +| `EmployeeRequest` | `full_name` | `required, string, max:200` | ✅ varchar(200) | +| `EmployeeRequest` | `phone_number` | `nullable, string, max:20` | ✅ varchar(20) | +| `EmployeeRequest` | `gender` | `nullable, in:male,female` | ✅ enum | +| `EmployeeRequest` | `base_salary` | `required, integer, min:0` | ✅ uint | +| `AttendanceRequest` | `latitude` | `required, numeric, min:-90, max:90` | ✅ decimal(10,7) | +| `AttendanceRequest` | `longitude` | `required, numeric, min:-180, max:180` | ✅ decimal(10,7) | +| `LeaveRequestRequest` | `start_date` | `required, date, after:today` | ✅ date | +| `LeaveRequestRequest` | `end_date` | `required, date, after_or_equal:start_date` | ✅ date | + +### Sales + +| Request | Field | Rules | DB Match | +|---------|-------|-------|----------| +| `TransactionRequest` | `channel` | `required, in:store,shopee,tiktok` | ✅ enum | +| `TransactionRequest` | `price_type` | `required, in:retail,wholesale` | ✅ enum | +| `TransactionRequest` | `payment_type` | `required, in:cash,transfer,qris` | ✅ enum | +| `TransactionRequest` | `tiktok_order_id` | `nullable, string, max:100` | ✅ varchar(100) | +| `TransactionRequest` | `shopee_order_id` | `nullable, string, max:100` | ✅ varchar(100) | +| `TransactionRequest` | `notes` | `nullable, string, max:100` | ✅ text (UI limit) | + +### Production + +| Request | Field | Rules | DB Match | +|---------|-------|-------|----------| +| `CuttingRequest` | `description` | `nullable, string, max:100` | ✅ varchar(100) | +| `CuttingRequest` | `product_name` | `required, string, max:255` | ✅ varchar(255) | +| `CuttingRequest` | `cutting_result` | `required, integer, min:1` | ✅ uint | +| `CuttingRequest` | `sample` | `required, integer` | ✅ uint | +| `CuttingRequest` | `original_outside_sample` | `required, integer` | ✅ uint | + +### Inventory + +| Request | Field | Rules | DB Match | +|---------|-------|-------|----------| +| `PurchaseRequest` | `supplier_id` | `required, integer, exists:suppliers,id` | ✅ FK | +| `PurchaseRequest` | `notes` | `nullable, string, max:100` | ✅ varchar(100) | +| `RestockRequest` | `stock_type` | `required, in:good,reject` | ✅ enum | +| `RestockRequest` | `notes` | `nullable, string, max:100` | ✅ varchar(100) | + diff --git a/app/Http/Requests/Admin/Finance/CashAccountRequest.php b/app/Http/Requests/Admin/Finance/CashAccountRequest.php index 72c3745..70aba72 100644 --- a/app/Http/Requests/Admin/Finance/CashAccountRequest.php +++ b/app/Http/Requests/Admin/Finance/CashAccountRequest.php @@ -9,7 +9,7 @@ class CashAccountRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('cash.update'); } public function rules(): array diff --git a/app/Http/Requests/Admin/Finance/CashTransactionRequest.php b/app/Http/Requests/Admin/Finance/CashTransactionRequest.php index a8676c5..581acda 100644 --- a/app/Http/Requests/Admin/Finance/CashTransactionRequest.php +++ b/app/Http/Requests/Admin/Finance/CashTransactionRequest.php @@ -12,7 +12,8 @@ class CashTransactionRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('cash.deposit') + || $this->user()->can('cash.withdraw'); } #[Override] diff --git a/app/Http/Requests/Admin/Finance/EmployeeAdvancePaymentRequest.php b/app/Http/Requests/Admin/Finance/EmployeeAdvancePaymentRequest.php index ded071f..ef12298 100644 --- a/app/Http/Requests/Admin/Finance/EmployeeAdvancePaymentRequest.php +++ b/app/Http/Requests/Admin/Finance/EmployeeAdvancePaymentRequest.php @@ -12,7 +12,7 @@ class EmployeeAdvancePaymentRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('employee_advances.pay'); } #[Override] diff --git a/app/Http/Requests/Admin/Finance/EmployeeAdvanceRequest.php b/app/Http/Requests/Admin/Finance/EmployeeAdvanceRequest.php index f0d892b..f923d51 100644 --- a/app/Http/Requests/Admin/Finance/EmployeeAdvanceRequest.php +++ b/app/Http/Requests/Admin/Finance/EmployeeAdvanceRequest.php @@ -12,7 +12,8 @@ class EmployeeAdvanceRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('employee_advances.create') + || $this->user()->can('employee_advances.update'); } #[Override] diff --git a/app/Http/Requests/Admin/Finance/ExpenseRequest.php b/app/Http/Requests/Admin/Finance/ExpenseRequest.php index accab39..c46b322 100644 --- a/app/Http/Requests/Admin/Finance/ExpenseRequest.php +++ b/app/Http/Requests/Admin/Finance/ExpenseRequest.php @@ -12,7 +12,8 @@ class ExpenseRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('expenses.create') + || $this->user()->can('expenses.update'); } #[Override] diff --git a/app/Http/Requests/Admin/Finance/PayrollAdjustmentRequest.php b/app/Http/Requests/Admin/Finance/PayrollAdjustmentRequest.php index 0511092..f7f0a98 100644 --- a/app/Http/Requests/Admin/Finance/PayrollAdjustmentRequest.php +++ b/app/Http/Requests/Admin/Finance/PayrollAdjustmentRequest.php @@ -14,7 +14,7 @@ class PayrollAdjustmentRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('payroll.adjust'); } #[Override] @@ -29,7 +29,6 @@ public function rules(): array 'type' => ['required', Rule::in(PayrollAdjustmentType::values())], 'amount' => ['required', 'integer', 'min:1'], 'description' => ['required', 'string', 'max:100'], - 'attendance_id' => ['nullable', 'integer', 'exists:attendances,id'], ]; } @@ -39,7 +38,6 @@ public function attributes(): array 'type' => 'jenis', 'amount' => 'jumlah', 'description' => 'keterangan', - 'attendance_id' => 'presensi', ]; } } diff --git a/app/Http/Requests/Admin/HR/AttendanceRequest.php b/app/Http/Requests/Admin/HR/AttendanceRequest.php index 361bce2..49d39db 100644 --- a/app/Http/Requests/Admin/HR/AttendanceRequest.php +++ b/app/Http/Requests/Admin/HR/AttendanceRequest.php @@ -8,15 +8,15 @@ class AttendanceRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('attendances.create'); } public function rules(): array { return [ 'photo' => ['required'], - 'latitude' => ['required', 'numeric'], - 'longitude' => ['required', 'numeric'], + 'latitude' => ['required', 'numeric', 'min:-90', 'max:90'], + 'longitude' => ['required', 'numeric', 'min:-180', 'max:180'], ]; } diff --git a/app/Http/Requests/Admin/HR/EmployeeRequest.php b/app/Http/Requests/Admin/HR/EmployeeRequest.php index 5da6a6e..c54441c 100644 --- a/app/Http/Requests/Admin/HR/EmployeeRequest.php +++ b/app/Http/Requests/Admin/HR/EmployeeRequest.php @@ -2,6 +2,8 @@ namespace App\Http\Requests\Admin\HR; +use App\Enums\EmploymentStatus; +use App\Enums\Gender; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; @@ -9,7 +11,8 @@ class EmployeeRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('employees.create') + || $this->user()->can('employees.update'); } public function rules(): array @@ -34,7 +37,7 @@ public function rules(): array 'role' => ['required', 'string', Rule::exists('roles', 'name')], 'full_name' => ['required', 'string', 'max:200'], 'phone_number' => ['nullable', 'string', 'max:20'], - 'gender' => ['nullable', 'in:male,female'], + 'gender' => ['nullable', Rule::in(Gender::values())], 'birth_date' => ['nullable', 'date'], 'address' => ['nullable', 'string'], 'join_date' => [ @@ -48,7 +51,7 @@ public function rules(): array ], 'employment_status' => [ Rule::requiredIf(! $isOwner), - Rule::in(['full_time', 'part_time', 'contract', 'internship', 'resigned']), + Rule::in(EmploymentStatus::values()), ], 'base_salary' => [ Rule::requiredIf(! $isOwner), diff --git a/app/Http/Requests/Admin/HR/LeaveRequestRequest.php b/app/Http/Requests/Admin/HR/LeaveRequestRequest.php index 66c06d8..fb876c0 100644 --- a/app/Http/Requests/Admin/HR/LeaveRequestRequest.php +++ b/app/Http/Requests/Admin/HR/LeaveRequestRequest.php @@ -9,7 +9,8 @@ class LeaveRequestRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('leave_requests.create') + || $this->user()->can('leave_requests.update'); } public function rules(): array @@ -30,7 +31,7 @@ function ($attribute, $value, $fail) use ($leaveRequest) { $query = LeaveRequest::where('employee_id', $employee->id) ->where('start_date', $value) - ->where('status', '!=', 'cancelled'); + ->where('status', '!=', LeaveRequest::cancelled()); if ($leaveRequest) { $query->where('id', '!=', $leaveRequest->id); diff --git a/app/Http/Requests/Admin/Manage/CuttingRequest.php b/app/Http/Requests/Admin/Manage/CuttingRequest.php index 4b45e16..77866a7 100644 --- a/app/Http/Requests/Admin/Manage/CuttingRequest.php +++ b/app/Http/Requests/Admin/Manage/CuttingRequest.php @@ -3,12 +3,14 @@ namespace App\Http\Requests\Admin\Manage; use Illuminate\Foundation\Http\FormRequest; +use Illuminate\Validation\Rule; class CuttingRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('cuttings.create') + || $this->user()->can('cuttings.update'); } public function rules(): array @@ -20,7 +22,7 @@ public function rules(): array 'original_outside_sample' => ['required', 'integer'], 'cutting_result' => ['required', 'integer', 'min:1'], 'materials' => ['required', 'array', 'min:1'], - 'materials.*.raw_material_price_id' => ['required', 'integer', 'exists:raw_material_prices,id'], + 'materials.*.raw_material_price_id' => ['required', 'integer', Rule::exists('raw_material_prices', 'id')], 'materials.*.material_usage' => ['required', 'integer', 'min:1'], 'materials.*.material_result' => ['required', 'integer'], 'materials.*.combination_index' => ['nullable', 'integer'], diff --git a/app/Http/Requests/Admin/Manage/PurchaseRequest.php b/app/Http/Requests/Admin/Manage/PurchaseRequest.php index 87a7d9b..05df853 100644 --- a/app/Http/Requests/Admin/Manage/PurchaseRequest.php +++ b/app/Http/Requests/Admin/Manage/PurchaseRequest.php @@ -13,7 +13,8 @@ class PurchaseRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('purchases.create') + || $this->user()->can('purchases.update'); } public function prepareForValidation(): void @@ -25,18 +26,18 @@ public function rules(): array { return [ 'mode' => ['sometimes', 'required', 'in:new,existing'], - 'name' => ['required_unless:mode,existing', 'string', 'max:200'], - 'unit' => [$this->isMethod('post') ? 'required_unless:mode,existing' : 'nullable', Rule::in(RawMaterialUnit::values())], - 'variants' => ['required_unless:mode,existing', 'array', 'min:1'], - 'variants.*.variant' => ['required_unless:mode,existing', 'string', 'max:200'], - 'variants.*.price' => ['required_unless:mode,existing', 'integer', 'min:0'], - 'variants.*.stock' => ['required_unless:mode,existing', 'integer', 'min:0'], - 'variants.*.photo_key' => ['required_unless:mode,existing', 'string', 'max:500'], - 'existing_items' => ['required_if:mode,existing', 'array', 'min:1'], - 'existing_items.*.raw_material_price_id' => ['required', 'integer', 'exists:raw_material_prices,id'], + 'name' => [Rule::requiredUnless(fn () => $this->input('mode') === 'existing'), 'string', 'max:200'], + 'unit' => [$this->isMethod('post') ? Rule::requiredUnless(fn () => $this->input('mode') === 'existing') : 'nullable', Rule::in(RawMaterialUnit::values())], + 'variants' => [Rule::requiredUnless(fn () => $this->input('mode') === 'existing'), 'array', 'min:1'], + 'variants.*.variant' => [Rule::requiredUnless(fn () => $this->input('mode') === 'existing'), 'string', 'max:200'], + 'variants.*.price' => [Rule::requiredUnless(fn () => $this->input('mode') === 'existing'), 'integer', 'min:0'], + 'variants.*.stock' => [Rule::requiredUnless(fn () => $this->input('mode') === 'existing'), 'integer', 'min:0'], + 'variants.*.photo_key' => [Rule::requiredUnless(fn () => $this->input('mode') === 'existing'), 'string', 'max:500'], + 'existing_items' => [Rule::requiredIf(fn () => $this->input('mode') === 'existing'), 'array', 'min:1'], + 'existing_items.*.raw_material_price_id' => ['required', 'integer', Rule::exists('raw_material_prices', 'id')], 'existing_items.*.quantity' => ['required', 'integer', 'min:1'], 'existing_items.*.unit_price' => ['required', 'integer', 'min:0'], - 'supplier_id' => ['required', 'integer', 'exists:suppliers,id'], + 'supplier_id' => ['required', 'integer', Rule::exists('suppliers', 'id')], 'discount' => ['nullable', 'integer', 'min:0'], 'shipping_cost' => ['nullable', 'integer', 'min:0'], 'notes' => ['nullable', 'string', 'max:100'], diff --git a/app/Http/Requests/Admin/Manage/RestockRequest.php b/app/Http/Requests/Admin/Manage/RestockRequest.php index dea50c7..90b9a2f 100644 --- a/app/Http/Requests/Admin/Manage/RestockRequest.php +++ b/app/Http/Requests/Admin/Manage/RestockRequest.php @@ -10,7 +10,8 @@ class RestockRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('restocks.create') + || $this->user()->can('restocks.update'); } public function rules(): array @@ -18,7 +19,7 @@ public function rules(): array return [ 'stock_type' => ['sometimes', 'required', Rule::in(ProductStockQuality::values())], 'items' => ['required', 'array', 'min:1'], - 'items.*.product_variant_id' => ['required', 'integer', 'exists:product_variants,id'], + 'items.*.product_variant_id' => ['required', 'integer', Rule::exists('product_variants', 'id')], 'items.*.quantity' => ['required', 'integer', 'min:1'], 'notes' => ['nullable', 'string', 'max:100'], 'photo_key' => ['nullable', 'string', 'max:500'], diff --git a/app/Http/Requests/Admin/Manage/TransactionRequest.php b/app/Http/Requests/Admin/Manage/TransactionRequest.php index f74b3df..99a3e5a 100644 --- a/app/Http/Requests/Admin/Manage/TransactionRequest.php +++ b/app/Http/Requests/Admin/Manage/TransactionRequest.php @@ -16,7 +16,8 @@ class TransactionRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('orders.create') + || $this->user()->can('orders.update'); } public function prepareForValidation(): void @@ -26,15 +27,13 @@ public function prepareForValidation(): void public function rules(): array { - $sellingPriceTypes = array_diff(PriceType::values(), [PriceType::CAPITAL->value]); - return [ 'stock_type' => ['sometimes', 'required', Rule::in(ProductStockQuality::values())], 'channel' => ['sometimes', 'required', Rule::in(OrderChannel::values())], - 'price_type' => ['sometimes', 'required', Rule::in($sellingPriceTypes)], + 'price_type' => ['sometimes', 'required', Rule::in(array_diff(PriceType::values(), [PriceType::CAPITAL->value]))], 'payment_type' => ['sometimes', 'required', Rule::in(PaymentType::values())], - 'customer_id' => ['nullable', 'integer', 'exists:customers,id'], - 'marketing_id' => ['nullable', 'integer', 'exists:users,id'], + 'customer_id' => ['nullable', 'integer', Rule::exists('customers', 'id')], + 'marketing_id' => ['nullable', 'integer', Rule::exists('users', 'id')], 'discount' => ['nullable', 'integer', 'min:0'], 'nego_price' => ['nullable', 'integer'], 'is_completed' => ['sometimes', 'boolean'], @@ -42,7 +41,7 @@ public function rules(): array 'tiktok_order_id' => ['nullable', 'string', 'max:100'], 'shopee_order_id' => ['nullable', 'string', 'max:100'], 'items' => ['required', 'array', 'min:1'], - 'items.*.product_variant_id' => ['required', 'integer', 'exists:product_variants,id'], + 'items.*.product_variant_id' => ['required', 'integer', Rule::exists('product_variants', 'id')], 'items.*.quantity' => ['required', 'integer', 'min:1'], 'notes' => ['nullable', 'string', 'max:100'], 'photo_key' => [ diff --git a/app/Http/Requests/Admin/Master/CategoryRequest.php b/app/Http/Requests/Admin/Master/CategoryRequest.php index 5b7b22e..7daf4b9 100644 --- a/app/Http/Requests/Admin/Master/CategoryRequest.php +++ b/app/Http/Requests/Admin/Master/CategoryRequest.php @@ -9,7 +9,8 @@ class CategoryRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('categories.create') + || $this->user()->can('categories.update'); } public function rules(): array @@ -17,7 +18,7 @@ public function rules(): array $category = $this->route('category'); return [ - 'name' => ['required', 'string', 'max:100', Rule::unique('categories', 'name')->ignore($category)], + 'name' => ['required', 'string', 'max:50', Rule::unique('categories', 'name')->ignore($category)], ]; } diff --git a/app/Http/Requests/Admin/Master/CustomerRequest.php b/app/Http/Requests/Admin/Master/CustomerRequest.php index 93ad5eb..507d87d 100644 --- a/app/Http/Requests/Admin/Master/CustomerRequest.php +++ b/app/Http/Requests/Admin/Master/CustomerRequest.php @@ -9,7 +9,8 @@ class CustomerRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('customers.create') + || $this->user()->can('customers.update'); } public function rules(): array diff --git a/app/Http/Requests/Admin/Master/Product/ProductRequest.php b/app/Http/Requests/Admin/Master/Product/ProductRequest.php index 472d9b3..2874efe 100644 --- a/app/Http/Requests/Admin/Master/Product/ProductRequest.php +++ b/app/Http/Requests/Admin/Master/Product/ProductRequest.php @@ -4,6 +4,7 @@ use App\Concerns\CurrencyStripping; use App\Enums\PriceType; +use App\Enums\ProductStatus; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; use Override; @@ -14,7 +15,8 @@ class ProductRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('products.create') + || $this->user()->can('products.update'); } #[Override] @@ -34,13 +36,13 @@ public function rules(): array 'max:200', ], 'description' => ['nullable', 'string'], - 'status' => ['nullable', Rule::in(['active', 'inactive', 'draft', 'pending', 'rejected'])], + 'status' => ['nullable', Rule::in(ProductStatus::values())], 'category_ids' => ['required', 'array', 'min:1'], - 'category_ids.*' => ['exists:categories,id'], + 'category_ids.*' => [Rule::exists('categories', 'id')], 'use_same_price' => ['nullable', 'boolean'], - 'shared_prices' => ['required_if:use_same_price,true', 'nullable', 'array', ...($useSamePrice ? ['size:9'] : [])], - 'shared_prices.*.type' => ['required_if:use_same_price,true', 'nullable', Rule::in(PriceType::values())], - 'shared_prices.*.price' => ['required_if:use_same_price,true', 'nullable', 'integer', 'min:0'], + 'shared_prices' => [Rule::requiredIf(fn() => $useSamePrice), 'nullable', 'array', ...($useSamePrice ? ['size:9'] : [])], + 'shared_prices.*.type' => [Rule::requiredIf(fn() => $useSamePrice), 'nullable', Rule::in(PriceType::values())], + 'shared_prices.*.price' => [Rule::requiredIf(fn() => $useSamePrice), 'nullable', 'integer', 'min:0'], 'variants' => ['required', 'array', 'min:1'], 'variants.*.id' => ['nullable', 'integer'], 'variants.*.name' => ['required', 'string', 'max:200'], @@ -49,10 +51,10 @@ public function rules(): array 'variants.*.retail_stock' => ['required', 'integer', 'min:0'], 'variants.*.photo_keys' => ['required', 'array', 'min:1', 'max:5'], 'variants.*.photo_keys.*' => ['required', 'string', 'max:500'], - 'variants.*.prices' => ['required_if:use_same_price,false', 'nullable', 'array', ...(! $useSamePrice ? ['size:9'] : [])], + 'variants.*.prices' => [Rule::requiredIf(fn() => ! $useSamePrice), 'nullable', 'array', ...(! $useSamePrice ? ['size:9'] : [])], 'variants.*.prices.*.id' => ['nullable', 'integer'], - 'variants.*.prices.*.type' => ['required_if:use_same_price,false', 'nullable', Rule::in(PriceType::values())], - 'variants.*.prices.*.price' => ['required_if:use_same_price,false', 'nullable', 'integer', 'min:0'], + 'variants.*.prices.*.type' => [Rule::requiredIf(fn() => ! $useSamePrice), 'nullable', Rule::in(PriceType::values())], + 'variants.*.prices.*.price' => [Rule::requiredIf(fn() => ! $useSamePrice), 'nullable', 'integer', 'min:0'], ]; } diff --git a/app/Http/Requests/Admin/Master/Product/ProductVariantRequest.php b/app/Http/Requests/Admin/Master/Product/ProductVariantRequest.php index c308b21..6a068e4 100644 --- a/app/Http/Requests/Admin/Master/Product/ProductVariantRequest.php +++ b/app/Http/Requests/Admin/Master/Product/ProductVariantRequest.php @@ -13,7 +13,8 @@ class ProductVariantRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('products.create') + || $this->user()->can('products.update'); } public function prepareForValidation(): void diff --git a/app/Http/Requests/Admin/Master/Product/TransferStockRequest.php b/app/Http/Requests/Admin/Master/Product/TransferStockRequest.php index caa235a..25b6361 100644 --- a/app/Http/Requests/Admin/Master/Product/TransferStockRequest.php +++ b/app/Http/Requests/Admin/Master/Product/TransferStockRequest.php @@ -8,7 +8,7 @@ class TransferStockRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('products.transfer_stock'); } public function rules(): array diff --git a/app/Http/Requests/Admin/Master/RawMaterial/RawMaterialRequest.php b/app/Http/Requests/Admin/Master/RawMaterial/RawMaterialRequest.php index a4a2696..4545efd 100644 --- a/app/Http/Requests/Admin/Master/RawMaterial/RawMaterialRequest.php +++ b/app/Http/Requests/Admin/Master/RawMaterial/RawMaterialRequest.php @@ -13,7 +13,8 @@ class RawMaterialRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('raw_materials.create') + || $this->user()->can('raw_materials.update'); } public function prepareForValidation(): void diff --git a/app/Http/Requests/Admin/Master/RawMaterial/RawMaterialVariantRequest.php b/app/Http/Requests/Admin/Master/RawMaterial/RawMaterialVariantRequest.php index 621160d..93409b7 100644 --- a/app/Http/Requests/Admin/Master/RawMaterial/RawMaterialVariantRequest.php +++ b/app/Http/Requests/Admin/Master/RawMaterial/RawMaterialVariantRequest.php @@ -11,7 +11,8 @@ class RawMaterialVariantRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('raw_materials.create') + || $this->user()->can('raw_materials.update'); } public function prepareForValidation(): void diff --git a/app/Http/Requests/Admin/Master/SupplierRequest.php b/app/Http/Requests/Admin/Master/SupplierRequest.php index f3ca296..1a7437c 100644 --- a/app/Http/Requests/Admin/Master/SupplierRequest.php +++ b/app/Http/Requests/Admin/Master/SupplierRequest.php @@ -9,7 +9,8 @@ class SupplierRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('suppliers.create') + || $this->user()->can('suppliers.update'); } public function rules(): array diff --git a/app/Http/Requests/Admin/RoleRequest.php b/app/Http/Requests/Admin/RoleRequest.php index ed1cfda..2ca8a24 100644 --- a/app/Http/Requests/Admin/RoleRequest.php +++ b/app/Http/Requests/Admin/RoleRequest.php @@ -9,7 +9,8 @@ class RoleRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('roles.create') + || $this->user()->can('roles.update'); } public function rules(): array @@ -24,7 +25,7 @@ public function rules(): array Rule::unique('roles', 'name')->ignore($roleId, 'id'), ], 'permissions' => ['present', 'array'], - 'permissions.*' => ['string', 'exists:permissions,name'], + 'permissions.*' => ['string', Rule::exists('permissions', 'name')], ]; } diff --git a/app/Http/Requests/Admin/Settings/UpdateHRRequest.php b/app/Http/Requests/Admin/Settings/UpdateHRRequest.php index 7732865..910e88f 100644 --- a/app/Http/Requests/Admin/Settings/UpdateHRRequest.php +++ b/app/Http/Requests/Admin/Settings/UpdateHRRequest.php @@ -12,7 +12,7 @@ class UpdateHRRequest extends FormRequest public function authorize(): bool { - return true; + return $this->user()->can('settings.update_hr'); } #[Override] diff --git a/app/Http/Requests/Admin/Settings/UpdateHomepageRequest.php b/app/Http/Requests/Admin/Settings/UpdateHomepageRequest.php index 4d77fbf..fb7e385 100644 --- a/app/Http/Requests/Admin/Settings/UpdateHomepageRequest.php +++ b/app/Http/Requests/Admin/Settings/UpdateHomepageRequest.php @@ -8,7 +8,7 @@ class UpdateHomepageRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('settings.update_homepage'); } public function rules(): array diff --git a/app/Http/Requests/Admin/Settings/UpdateMarketplaceRequest.php b/app/Http/Requests/Admin/Settings/UpdateMarketplaceRequest.php index 1590c83..c780320 100644 --- a/app/Http/Requests/Admin/Settings/UpdateMarketplaceRequest.php +++ b/app/Http/Requests/Admin/Settings/UpdateMarketplaceRequest.php @@ -8,7 +8,7 @@ class UpdateMarketplaceRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('settings.update_marketplace'); } private function feeRuleRules(): array diff --git a/app/Http/Requests/Admin/Settings/UpdateSocialMediaRequest.php b/app/Http/Requests/Admin/Settings/UpdateSocialMediaRequest.php index 3898d58..bbf3dfa 100644 --- a/app/Http/Requests/Admin/Settings/UpdateSocialMediaRequest.php +++ b/app/Http/Requests/Admin/Settings/UpdateSocialMediaRequest.php @@ -8,7 +8,7 @@ class UpdateSocialMediaRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('settings.update_social_media'); } public function rules(): array diff --git a/app/Http/Requests/Admin/Settings/UpdateSystemRequest.php b/app/Http/Requests/Admin/Settings/UpdateSystemRequest.php index f6a27da..3b719e5 100644 --- a/app/Http/Requests/Admin/Settings/UpdateSystemRequest.php +++ b/app/Http/Requests/Admin/Settings/UpdateSystemRequest.php @@ -8,7 +8,7 @@ class UpdateSystemRequest extends FormRequest { public function authorize(): bool { - return true; + return $this->user()->can('settings.update_system'); } public function rules(): array diff --git a/app/Http/Requests/Settings/ProfileUpdateRequest.php b/app/Http/Requests/Settings/ProfileUpdateRequest.php index 22d6815..219380f 100644 --- a/app/Http/Requests/Settings/ProfileUpdateRequest.php +++ b/app/Http/Requests/Settings/ProfileUpdateRequest.php @@ -27,7 +27,7 @@ public function rules(): array 'required', 'string', 'email', - 'max:255', + 'max:100', Rule::unique('users', 'email')->ignore($userId), ], 'username' => [