From 9ba87b9381c05ffe4babfb0b407419c79ecf5dc5 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 5 Jul 2026 15:26:33 +0700 Subject: [PATCH] feat: implement product variant management in CuttingQuickCreateProductRequest and related components; enhance validation rules, add new CuttingProductVariantSection, and improve material handling in QuickCreateProductModal for better user experience --- .../CuttingQuickCreateProductRequest.php | 16 ++- .../manage/cuttings/form/CuttingPosForm.vue | 2 +- .../form/CuttingPosResultCatalogPanel.vue | 4 +- .../form/CuttingProductVariantSection.vue | 86 +++++++++++++ .../cuttings/form/QuickCreateProductModal.vue | 119 ++++++++++++------ .../products/form/ProductVariantSection.vue | 5 +- 6 files changed, 184 insertions(+), 48 deletions(-) create mode 100644 resources/js/pages/admin/manage/cuttings/form/CuttingProductVariantSection.vue diff --git a/app/Http/Requests/Admin/Manage/CuttingQuickCreateProductRequest.php b/app/Http/Requests/Admin/Manage/CuttingQuickCreateProductRequest.php index 71fb494..0b755ce 100644 --- a/app/Http/Requests/Admin/Manage/CuttingQuickCreateProductRequest.php +++ b/app/Http/Requests/Admin/Manage/CuttingQuickCreateProductRequest.php @@ -3,13 +3,13 @@ namespace App\Http\Requests\Admin\Manage; use App\Enums\Permission; -use App\Http\Requests\Concerns\HasProductVariantRules; +use App\Http\Requests\Concerns\ValidatesMediaUploads; use Illuminate\Foundation\Http\FormRequest; use Illuminate\Validation\Rule; class CuttingQuickCreateProductRequest extends FormRequest { - use HasProductVariantRules; + use ValidatesMediaUploads; public function authorize(): bool { @@ -28,7 +28,11 @@ public function rules(): array 'category_ids' => ['nullable', 'array'], 'category_ids.*' => ['integer', Rule::exists('categories', 'id')->whereNull('deleted_at')], - ...$this->productVariantRules(), + 'variants' => ['required', 'array', 'min:1'], + 'variants.*.name' => ['required', 'string', 'max:200'], + 'variants.*.stock' => ['required', 'integer', 'min:0'], + 'variants.*.retail_stock' => ['required', 'integer', 'min:0'], + ...$this->variantImageRules('variants'), ]; } @@ -42,7 +46,11 @@ public function attributes(): array 'description' => 'Deskripsi', 'category_ids' => 'Kategori', 'category_ids.*' => 'Kategori', - ...$this->productVariantAttributes(), + 'variants' => 'Varian', + 'variants.*.name' => 'Nama Varian', + 'variants.*.stock' => 'Stok', + 'variants.*.retail_stock' => 'Stok Ecer', + ...$this->variantImageAttributes('variants', 'Foto Varian'), ]; } } diff --git a/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue b/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue index e6ef0bd..d2c9660 100644 --- a/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue +++ b/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue @@ -283,7 +283,7 @@ function onProductCreated(product: CuttingProductCatalogItem) { + :categories="categories" :material-cart="materialCart" @decrease-result-qty="decreaseResultQty" @product-created="onProductCreated" /> CuttingResultCartItem | undefined; isCreateMode: boolean; categories: CategoryOption[]; + materialCart: CuttingMaterialCartItem[]; }>(); const productSearch = defineModel('productSearch', { required: true }); @@ -151,6 +152,7 @@ const quickCreateOpen = ref(false); diff --git a/resources/js/pages/admin/manage/cuttings/form/CuttingProductVariantSection.vue b/resources/js/pages/admin/manage/cuttings/form/CuttingProductVariantSection.vue new file mode 100644 index 0000000..d524fbf --- /dev/null +++ b/resources/js/pages/admin/manage/cuttings/form/CuttingProductVariantSection.vue @@ -0,0 +1,86 @@ + + + diff --git a/resources/js/pages/admin/manage/cuttings/form/QuickCreateProductModal.vue b/resources/js/pages/admin/manage/cuttings/form/QuickCreateProductModal.vue index 4a1da28..326de0f 100644 --- a/resources/js/pages/admin/manage/cuttings/form/QuickCreateProductModal.vue +++ b/resources/js/pages/admin/manage/cuttings/form/QuickCreateProductModal.vue @@ -1,5 +1,5 @@