Add reject_stock input to product CRUD form
- Add reject_stock field alongside stock (renamed to 'Stok Bagus') and retail_stock ('Stok Ecer')
- Update TypeScript types (ProductVariantFormItem, ProductFormInitialData)
- Update ProductVariantSection, ProductVariantEditModal, and ProductForm with new field
- Add validation rule and attribute label for reject_stock
- Update ProductService to persist reject_stock in create, update, and apply flows
This commit is contained in:
parent
ee9bff3043
commit
ee08188190
@ -24,6 +24,7 @@ protected function productVariantRules(string $variantsKey = 'variants', ?int $p
|
||||
"{$variantsKey}" => ['required', 'array', 'min:1'],
|
||||
"{$variantsKey}.*.name" => ['required', 'string', 'max:200'],
|
||||
"{$variantsKey}.*.stock" => ['required', 'integer', 'min:0'],
|
||||
"{$variantsKey}.*.reject_stock" => ['required', 'integer', 'min:0'],
|
||||
"{$variantsKey}.*.retail_stock" => ['required', 'integer', 'min:0'],
|
||||
...$this->variantImageRules($variantsKey, required: $imagesRequired),
|
||||
];
|
||||
@ -61,7 +62,8 @@ protected function productVariantAttributes(string $variantsKey = 'variants'): a
|
||||
return [
|
||||
$variantsKey => 'varian',
|
||||
"{$variantsKey}.*.name" => 'nama varian',
|
||||
"{$variantsKey}.*.stock" => 'stok',
|
||||
"{$variantsKey}.*.stock" => 'stok bagus',
|
||||
"{$variantsKey}.*.reject_stock" => 'stok reject',
|
||||
"{$variantsKey}.*.retail_stock" => 'stok ecer',
|
||||
"{$variantsKey}.*.prices" => 'harga',
|
||||
"{$variantsKey}.*.prices.distributor" => 'distributor',
|
||||
|
||||
@ -141,6 +141,7 @@ function () use ($validated, $user, $isOwner, $isDraft): Product {
|
||||
$variant = $product->variants()->create([
|
||||
'name' => $variantData['name'],
|
||||
'stock' => $variantData['stock'],
|
||||
'reject_stock' => $variantData['reject_stock'],
|
||||
'retail_stock' => $variantData['retail_stock'],
|
||||
]);
|
||||
|
||||
@ -574,6 +575,7 @@ private function applyPayloadToProduct(
|
||||
$variant->update([
|
||||
'name' => $variantData['name'],
|
||||
'stock' => $variantData['stock'],
|
||||
'reject_stock' => $variantData['reject_stock'],
|
||||
'retail_stock' => $variantData['retail_stock'],
|
||||
]);
|
||||
|
||||
@ -596,6 +598,7 @@ private function applyPayloadToProduct(
|
||||
$variant = $product->variants()->create([
|
||||
'name' => $variantData['name'],
|
||||
'stock' => $variantData['stock'],
|
||||
'reject_stock' => $variantData['reject_stock'],
|
||||
'retail_stock' => $variantData['retail_stock'],
|
||||
]);
|
||||
|
||||
@ -763,6 +766,7 @@ private function snapshotProduct(Product $product): array
|
||||
'id' => $variant->id,
|
||||
'name' => $variant->name,
|
||||
'stock' => $variant->stock,
|
||||
'reject_stock' => $variant->reject_stock,
|
||||
'retail_stock' => $variant->retail_stock,
|
||||
'prices' => $variant->prices
|
||||
->mapWithKeys(fn ($price) => [$price->type->value => $price->price])
|
||||
@ -795,6 +799,7 @@ private function buildPayloadFromValidated(array $validated): array
|
||||
'id' => $variantData['id'] ?? null,
|
||||
'name' => $variantData['name'],
|
||||
'stock' => $variantData['stock'],
|
||||
'reject_stock' => $variantData['reject_stock'],
|
||||
'retail_stock' => $variantData['retail_stock'],
|
||||
'prices' => $variantData['prices'] ?? [],
|
||||
'remove_media_ids' => $variantData['remove_media_ids'] ?? [],
|
||||
|
||||
@ -22,6 +22,7 @@ const initialData = computed(() => ({
|
||||
id: variant.id,
|
||||
name: variant.name,
|
||||
stock: variant.stock,
|
||||
reject_stock: variant.reject_stock,
|
||||
retail_stock: variant.retail_stock,
|
||||
prices: variant.prices ?? [],
|
||||
images: variant.images ?? [],
|
||||
|
||||
@ -55,6 +55,7 @@ const {
|
||||
client_id: createClientId(),
|
||||
name: '',
|
||||
stock: '0',
|
||||
reject_stock: '0',
|
||||
retail_stock: '0',
|
||||
prices: {
|
||||
distributor: '0',
|
||||
@ -74,6 +75,7 @@ const {
|
||||
client_id: createClientId(),
|
||||
name: '',
|
||||
stock: '0',
|
||||
reject_stock: '0',
|
||||
retail_stock: '0',
|
||||
prices: {
|
||||
distributor: '0',
|
||||
@ -111,6 +113,7 @@ const {
|
||||
id: variant.id,
|
||||
name: variant.name ?? '',
|
||||
stock: variant.stock != null ? String(variant.stock) : '0',
|
||||
reject_stock: variant.reject_stock != null ? String(variant.reject_stock) : '0',
|
||||
retail_stock: variant.retail_stock != null ? String(variant.retail_stock) : '0',
|
||||
prices,
|
||||
media: createMediaUploadState(variant.images ?? []),
|
||||
@ -225,6 +228,7 @@ function buildFormData(): FormData {
|
||||
appendToFormData(formData, (formData, index, variant) => {
|
||||
formData.append(`variants[${index}][name]`, variant.name.trim());
|
||||
formData.append(`variants[${index}][stock]`, String(Number.parseInt(String(variant.stock), 10) || 0));
|
||||
formData.append(`variants[${index}][reject_stock]`, String(Number.parseInt(String(variant.reject_stock), 10) || 0));
|
||||
formData.append(`variants[${index}][retail_stock]`, String(Number.parseInt(String(variant.retail_stock), 10) || 0));
|
||||
|
||||
if (variant.prices && showPrices.value) {
|
||||
@ -291,6 +295,7 @@ function submit() {
|
||||
@remove="confirmRemoveVariant(variant.client_id)"
|
||||
@update:name="setVariantField(variant.client_id, 'name', $event)"
|
||||
@update:stock="setVariantField(variant.client_id, 'stock', $event)"
|
||||
@update:reject-stock="setVariantField(variant.client_id, 'reject_stock', $event)"
|
||||
@update:retail-stock="setVariantField(variant.client_id, 'retail_stock', $event)"
|
||||
@update:prices="setVariantField(variant.client_id, 'prices', $event)"
|
||||
@update:media="setVariantField(variant.client_id, 'media', $event)"
|
||||
|
||||
@ -76,6 +76,7 @@ function populateForm(variant: Variant | null) {
|
||||
id: v.id,
|
||||
name: v.name,
|
||||
stock: String(v.stock),
|
||||
reject_stock: String(v.reject_stock),
|
||||
retail_stock: String(v.retail_stock),
|
||||
prices,
|
||||
media: createMediaUploadState(v.images ?? []),
|
||||
@ -133,6 +134,7 @@ function submit() {
|
||||
|
||||
formData.append(`variants[${index}][name]`, v.name.trim());
|
||||
formData.append(`variants[${index}][stock]`, String(Number.parseInt(v.stock, 10) || 0));
|
||||
formData.append(`variants[${index}][reject_stock]`, String(Number.parseInt(v.reject_stock, 10) || 0));
|
||||
formData.append(`variants[${index}][retail_stock]`, String(Number.parseInt(v.retail_stock, 10) || 0));
|
||||
|
||||
if (v.prices) {
|
||||
@ -178,13 +180,19 @@ function submit() {
|
||||
<FieldError :errors="formErrors(editForm, `variants.${editingVariantIndex}.name`)" />
|
||||
</Field>
|
||||
|
||||
<div class="grid grid-cols-2 gap-4">
|
||||
<div class="grid grid-cols-3 gap-4">
|
||||
<Field>
|
||||
<FieldLabel for="variant-stock" required>Stok</FieldLabel>
|
||||
<FieldLabel for="variant-stock" required>Stok Bagus</FieldLabel>
|
||||
<NumberInput id="variant-stock" v-model="editingVariantFormItem.stock" />
|
||||
<FieldError :errors="formErrors(editForm, `variants.${editingVariantIndex}.stock`)" />
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<FieldLabel for="variant-reject-stock" required>Stok Reject</FieldLabel>
|
||||
<NumberInput id="variant-reject-stock" v-model="editingVariantFormItem.reject_stock" />
|
||||
<FieldError :errors="formErrors(editForm, `variants.${editingVariantIndex}.reject_stock`)" />
|
||||
</Field>
|
||||
|
||||
<Field>
|
||||
<FieldLabel for="variant-retail-stock" required>Stok Ecer</FieldLabel>
|
||||
<NumberInput id="variant-retail-stock" v-model="editingVariantFormItem.retail_stock" />
|
||||
|
||||
@ -39,6 +39,7 @@ const emit = defineEmits<{
|
||||
remove: [];
|
||||
'update:name': [value: string];
|
||||
'update:stock': [value: string];
|
||||
'update:reject-stock': [value: string];
|
||||
'update:retail-stock': [value: string];
|
||||
'update:prices': [value: Record<string, string>];
|
||||
'update:media': [value: MediaUploadState];
|
||||
@ -95,7 +96,7 @@ function updatePrice(type: string, value: string) {
|
||||
</CardHeader>
|
||||
<CardContent>
|
||||
<FieldGroup>
|
||||
<FieldSet class="grid gap-4 md:grid-cols-3">
|
||||
<FieldSet class="grid gap-4 md:grid-cols-4">
|
||||
<Field>
|
||||
<FieldLabel :for="`variant_name_${variant.client_id}`" required>
|
||||
Nama Varian
|
||||
@ -107,12 +108,21 @@ function updatePrice(type: string, value: string) {
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel :for="`variant_stock_${variant.client_id}`" required>
|
||||
Stok
|
||||
Stok Bagus
|
||||
</FieldLabel>
|
||||
<NumberInput :id="`variant_stock_${variant.client_id}`" :model-value="variant.stock"
|
||||
@update:model-value="emit('update:stock', String($event))" />
|
||||
<FieldError :errors="variantErrors(variant.client_id, 'stock')" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel :for="`variant_reject_stock_${variant.client_id}`" required>
|
||||
Stok Reject
|
||||
</FieldLabel>
|
||||
<NumberInput :id="`variant_reject_stock_${variant.client_id}`"
|
||||
:model-value="variant.reject_stock"
|
||||
@update:model-value="emit('update:reject-stock', String($event))" />
|
||||
<FieldError :errors="variantErrors(variant.client_id, 'reject_stock')" />
|
||||
</Field>
|
||||
<Field>
|
||||
<FieldLabel :for="`variant_retail_stock_${variant.client_id}`" required>
|
||||
Stok Ecer
|
||||
|
||||
@ -92,6 +92,7 @@ export interface ProductVariantFormItem {
|
||||
id?: number;
|
||||
name: string;
|
||||
stock: string | number;
|
||||
reject_stock: string | number;
|
||||
retail_stock: string | number;
|
||||
prices?: Record<string, string>;
|
||||
media: MediaUploadState;
|
||||
@ -107,6 +108,7 @@ export type ProductFormInitialData = {
|
||||
id?: number;
|
||||
name?: string;
|
||||
stock?: number | string;
|
||||
reject_stock?: number | string;
|
||||
retail_stock?: number | string;
|
||||
prices?: Price[];
|
||||
images?: MediaItem[];
|
||||
|
||||
Loading…
Reference in New Issue
Block a user