refactor: enhance stock verification logic and error handling in StockVerifyDialog
This commit is contained in:
parent
2209f4901c
commit
39c8bd01a8
@ -2,7 +2,7 @@
|
||||
import { useForm } from '@inertiajs/vue3';
|
||||
import { computed, watch } from 'vue';
|
||||
import { toast } from 'vue-sonner';
|
||||
import NumberInput from '@/components/form/number-input/NumberInput.vue';
|
||||
import { NumberInput } from '@/components/form/number-input';
|
||||
import { RupiahInput } from '@/components/form/rupiah-input';
|
||||
import { Button } from '@/components/ui/button';
|
||||
import {
|
||||
@ -51,10 +51,14 @@ const verifyForm = useForm({
|
||||
cutting_result: res.cutting_result,
|
||||
original_sample: res.sample,
|
||||
original_outside_sample: res.original_outside_sample,
|
||||
good: res.original_outside_sample,
|
||||
good: res.cutting_result,
|
||||
reject: 0,
|
||||
})),
|
||||
variant_prices: [] as VariantPriceRow[],
|
||||
variant_prices: props.cutting.results.map(res => ({
|
||||
product_variant_id: res.product_variant?.id || 0,
|
||||
name: `${res.product_variant?.product?.name || ''} (${res.product_variant?.name || ''})`,
|
||||
prices: buildEmptyPrices(),
|
||||
})),
|
||||
shared_prices: buildEmptyPrices(),
|
||||
});
|
||||
|
||||
@ -67,7 +71,7 @@ watch(open, (isOpen) => {
|
||||
cutting_result: res.cutting_result,
|
||||
original_sample: res.sample,
|
||||
original_outside_sample: res.original_outside_sample,
|
||||
good: res.original_outside_sample,
|
||||
good: res.cutting_result,
|
||||
reject: 0,
|
||||
}));
|
||||
verifyForm.variant_prices = props.cutting.results.map(res => ({
|
||||
@ -80,6 +84,18 @@ watch(open, (isOpen) => {
|
||||
}
|
||||
});
|
||||
|
||||
function onGoodChange(result: any, value: string | number) {
|
||||
const val = Number(value) || 0;
|
||||
result.good = val;
|
||||
result.reject = Math.max(0, result.cutting_result - val);
|
||||
}
|
||||
|
||||
function onRejectChange(result: any, value: string | number) {
|
||||
const val = Number(value) || 0;
|
||||
result.reject = val;
|
||||
result.good = Math.max(0, result.cutting_result - val);
|
||||
}
|
||||
|
||||
function setSharedPrice(type: string, value: string) {
|
||||
verifyForm.shared_prices[type] = value;
|
||||
verifyForm.variant_prices = verifyForm.variant_prices.map((row) => ({
|
||||
@ -89,13 +105,13 @@ function setSharedPrice(type: string, value: string) {
|
||||
}
|
||||
|
||||
const resultPricesErrors = computed(() => {
|
||||
const message = (verifyForm.errors as Record<string, string | undefined>).result_prices;
|
||||
|
||||
return message ? [message] : [];
|
||||
return Object.entries(verifyForm.errors)
|
||||
.filter(([key]) => key === 'result_prices' || key.startsWith('result_prices.'))
|
||||
.map(([_, message]) => message) as string[];
|
||||
});
|
||||
|
||||
function buildResultPricesPayload() {
|
||||
return verifyForm.variant_prices.map((row) => ({
|
||||
function buildResultPricesPayload(variantPrices: VariantPriceRow[]) {
|
||||
return variantPrices.map((row) => ({
|
||||
product_variant_id: row.product_variant_id,
|
||||
prices: PRICE_TYPES.map((type) => ({
|
||||
type,
|
||||
@ -113,7 +129,7 @@ function submitVerify() {
|
||||
good,
|
||||
reject,
|
||||
})),
|
||||
result_prices: buildResultPricesPayload(),
|
||||
result_prices: buildResultPricesPayload(data.variant_prices),
|
||||
}))
|
||||
.post(verify.url(props.cutting.id), {
|
||||
preserveScroll: true,
|
||||
@ -121,8 +137,22 @@ function submitVerify() {
|
||||
open.value = false;
|
||||
},
|
||||
onError: (errors: Record<string, string>) => {
|
||||
if (errors.system) {
|
||||
toast.error(errors.system);
|
||||
const shown = new Set<string>();
|
||||
|
||||
for (const [key, message] of Object.entries(errors)) {
|
||||
if (
|
||||
key === 'result_prices' ||
|
||||
key.startsWith('result_prices.') ||
|
||||
key.startsWith('results.') ||
|
||||
key === 'verification_note'
|
||||
) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (!shown.has(message)) {
|
||||
shown.add(message);
|
||||
toast.error(message);
|
||||
}
|
||||
}
|
||||
},
|
||||
});
|
||||
@ -145,31 +175,38 @@ function submitVerify() {
|
||||
|
||||
<div class="space-y-2">
|
||||
<div v-for="(result, index) in verifyForm.results" :key="result.product_variant_id"
|
||||
class="flex items-center gap-3 rounded-lg border p-3">
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="font-medium text-sm truncate">{{ result.name }}</p>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ result.cutting_result }} pcs
|
||||
<span class="text-[10px]">({{ result.original_sample }} Sample, {{
|
||||
result.original_outside_sample }} Diluar Sample)</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="text-center">
|
||||
<label :for="`stock-good-${index}`"
|
||||
class="text-[10px] text-muted-foreground block">Bagus</label>
|
||||
<NumberInput :id="`stock-good-${index}`" v-model="result.good"
|
||||
class="h-7 w-20 px-1.5 text-xs text-center"
|
||||
@input="result.reject = result.cutting_result - result.good" />
|
||||
class="flex flex-col gap-1 rounded-lg border p-3">
|
||||
<div class="flex items-center gap-3">
|
||||
<div class="flex-1 min-w-0">
|
||||
<p class="font-medium text-sm truncate">{{ result.name }}</p>
|
||||
<p class="text-xs text-muted-foreground">
|
||||
{{ result.cutting_result }} pcs
|
||||
<span class="text-[10px]">({{ result.original_sample }} Sample, {{
|
||||
result.original_outside_sample }} Diluar Sample)</span>
|
||||
</p>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<label :for="`stock-reject-${index}`"
|
||||
class="text-[10px] text-muted-foreground block">Reject</label>
|
||||
<NumberInput :id="`stock-reject-${index}`" v-model="result.reject"
|
||||
class="h-7 w-20 px-1.5 text-xs text-center"
|
||||
@input="result.good = result.cutting_result - result.reject" />
|
||||
<div class="flex items-center gap-2 shrink-0">
|
||||
<div class="text-center">
|
||||
<label :for="`stock-good-${index}`"
|
||||
class="text-[10px] text-muted-foreground block">Bagus</label>
|
||||
<NumberInput :id="`stock-good-${index}`" :model-value="result.good"
|
||||
class="h-7 w-20 px-1.5 text-xs text-center"
|
||||
@update:model-value="val => onGoodChange(result, val)" />
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<label :for="`stock-reject-${index}`"
|
||||
class="text-[10px] text-muted-foreground block">Reject</label>
|
||||
<NumberInput :id="`stock-reject-${index}`" :model-value="result.reject"
|
||||
class="h-7 w-20 px-1.5 text-xs text-center"
|
||||
@update:model-value="val => onRejectChange(result, val)" />
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<FieldError :errors="[
|
||||
verifyForm.errors[`results.${index}.good`],
|
||||
verifyForm.errors[`results.${index}.reject`],
|
||||
verifyForm.errors[`results.${index}.product_variant_id`]
|
||||
].filter(Boolean) as string[]" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user