Compare commits

...

3 Commits

4 changed files with 53 additions and 9 deletions

View File

@ -81,8 +81,8 @@ public function withValidator(Validator $validator): void
continue; continue;
} }
if (($good + $reject) !== (int) $originalResult->cutting_result) { if (($good + $reject) > (int) $originalResult->cutting_result) {
$validator->errors()->add("results.{$index}.good", "Total jumlah (bagus + reject) harus sama dengan hasil cutting asli ({$originalResult->cutting_result} pcs)."); $validator->errors()->add("results.{$index}.good", "Total jumlah (bagus + reject) tidak boleh melebihi hasil cutting asli ({$originalResult->cutting_result} pcs).");
} }
} }
} }

View File

@ -98,6 +98,9 @@ function getGroupedMaterials(materials: any[]): GroupedCuttingMaterials[] {
<p v-if="cutting.submitted_by"> <p v-if="cutting.submitted_by">
Diajukan oleh {{ cutting.submitted_by.profile?.full_name ?? cutting.submitted_by.username }} Diajukan oleh {{ cutting.submitted_by.profile?.full_name ?? cutting.submitted_by.username }}
</p> </p>
<p v-if="cutting.rejection?.reason">
Catatan: {{ cutting.rejection.reason }}
</p>
</div> </div>
<div class="flex flex-wrap gap-x-4 gap-y-1 text-sm"> <div class="flex flex-wrap gap-x-4 gap-y-1 text-sm">
<span>Total Hasil Cutting <strong class="text-primary">{{ cutting.total_result_pieces ?? <span>Total Hasil Cutting <strong class="text-primary">{{ cutting.total_result_pieces ??
@ -124,7 +127,8 @@ function getGroupedMaterials(materials: any[]): GroupedCuttingMaterials[] {
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
<template v-for="group in getGroupedMaterials(cutting.materials)" :key="group.rawMaterialId"> <template v-for="group in getGroupedMaterials(cutting.materials)"
:key="group.rawMaterialId">
<TableRow class="bg-muted/20 hover:bg-muted/20"> <TableRow class="bg-muted/20 hover:bg-muted/20">
<TableCell colspan="3" class="font-semibold text-foreground"> <TableCell colspan="3" class="font-semibold text-foreground">
<template v-if="group.isCombination"> <template v-if="group.isCombination">
@ -140,7 +144,8 @@ function getGroupedMaterials(materials: any[]): GroupedCuttingMaterials[] {
</template> </template>
<template v-else> <template v-else>
{{ group.rawMaterialName }} {{ group.rawMaterialName }}
<Badge v-if="group.unitLabel" variant="secondary" class="ml-2 font-normal"> <Badge v-if="group.unitLabel" variant="secondary"
class="ml-2 font-normal">
{{ group.unitLabel }} {{ group.unitLabel }}
</Badge> </Badge>
</template> </template>
@ -154,7 +159,8 @@ function getGroupedMaterials(materials: any[]): GroupedCuttingMaterials[] {
<MediaThumbnailCell :items="material.images ?? []" :max-visible="1" /> <MediaThumbnailCell :items="material.images ?? []" :max-visible="1" />
</TableCell> </TableCell>
<TableCell class="tabular-nums"> <TableCell class="tabular-nums">
<template v-if="!group.isCombination && material.material_result !== null && material.material_result !== undefined"> <template
v-if="!group.isCombination && material.material_result !== null && material.material_result !== undefined">
{{ material.material_result }} pcs {{ material.material_result }} pcs
</template> </template>
<template v-else> <template v-else>
@ -179,11 +185,12 @@ function getGroupedMaterials(materials: any[]): GroupedCuttingMaterials[] {
<TableHead>Hasil</TableHead> <TableHead>Hasil</TableHead>
<TableHead>Bagus</TableHead> <TableHead>Bagus</TableHead>
<TableHead>Reject</TableHead> <TableHead>Reject</TableHead>
<TableHead>Harga</TableHead>
</TableRow> </TableRow>
</TableHeader> </TableHeader>
<TableBody> <TableBody>
<TableRow v-if="!cutting.results.length" :key="`${cutting.id}-result-empty`"> <TableRow v-if="!cutting.results.length" :key="`${cutting.id}-result-empty`">
<TableCell colspan="5" class="text-muted-foreground"> <TableCell colspan="6" class="text-muted-foreground">
Belum ada hasil verifikasi Belum ada hasil verifikasi
</TableCell> </TableCell>
</TableRow> </TableRow>
@ -192,7 +199,8 @@ function getGroupedMaterials(materials: any[]): GroupedCuttingMaterials[] {
{{ result.product_variant?.product?.name }} ({{ result.product_variant?.name }}) {{ result.product_variant?.product?.name }} ({{ result.product_variant?.name }})
</TableCell> </TableCell>
<TableCell> <TableCell>
<MediaThumbnailCell :items="result.product_variant?.images ?? []" :max-visible="1" /> <MediaThumbnailCell :items="result.product_variant?.images ?? []"
:max-visible="1" />
</TableCell> </TableCell>
<TableCell class="tabular-nums"> <TableCell class="tabular-nums">
{{ result.cutting_result }} pcs {{ result.cutting_result }} pcs
@ -203,6 +211,22 @@ function getGroupedMaterials(materials: any[]): GroupedCuttingMaterials[] {
<TableCell class="tabular-nums"> <TableCell class="tabular-nums">
{{ result.original_outside_sample }} pcs {{ result.original_outside_sample }} pcs
</TableCell> </TableCell>
<TableCell>
<div v-if="cutting.result_prices?.filter(p => p.product_variant_id === result.product_variant?.id).length"
class="space-y-0.5 text-xs">
<div v-for="price in cutting.result_prices.filter(p => p.product_variant_id === result.product_variant?.id)"
:key="price.id"
class="flex items-center justify-between gap-3">
<span class="text-muted-foreground">
{{ price.type_label }}
</span>
<span class="font-medium tabular-nums">
{{ price.price_formatted }}
</span>
</div>
</div>
<span v-else class="text-xs text-muted-foreground">-</span>
</TableCell>
</TableRow> </TableRow>
</TableBody> </TableBody>
</Table> </Table>

View File

@ -87,6 +87,16 @@ interface VariantPriceRow {
prices: Record<string, string>; prices: Record<string, string>;
} }
function onGoodChange(result: any, value: string | number) {
const val = Number(value) || 0;
result.good = val;
}
function onRejectChange(result: any, value: string | number) {
const val = Number(value) || 0;
result.reject = val;
}
const verifyForm = useForm({ const verifyForm = useForm({
verification_note: '', verification_note: '',
results: props.cutting.results.map(res => ({ results: props.cutting.results.map(res => ({
@ -227,13 +237,15 @@ function submitVerify() {
<label :for="`stock-good-${index}`" <label :for="`stock-good-${index}`"
class="text-[10px] text-muted-foreground block mb-0.5">Bagus</label> class="text-[10px] text-muted-foreground block mb-0.5">Bagus</label>
<NumberInput :id="`stock-good-${index}`" :model-value="result.good" <NumberInput :id="`stock-good-${index}`" :model-value="result.good"
class="h-7 w-20 px-1.5 text-xs text-center" /> class="h-7 w-20 px-1.5 text-xs text-center"
@update:model-value="val => onGoodChange(result, val)" />
</div> </div>
<div class="text-center"> <div class="text-center">
<label :for="`stock-reject-${index}`" <label :for="`stock-reject-${index}`"
class="text-[10px] text-muted-foreground block mb-0.5">Reject</label> class="text-[10px] text-muted-foreground block mb-0.5">Reject</label>
<NumberInput :id="`stock-reject-${index}`" :model-value="result.reject" <NumberInput :id="`stock-reject-${index}`" :model-value="result.reject"
class="h-7 w-20 px-1.5 text-xs text-center" /> class="h-7 w-20 px-1.5 text-xs text-center"
@update:model-value="val => onRejectChange(result, val)" />
</div> </div>
</div> </div>
</div> </div>

View File

@ -45,6 +45,14 @@ export type CuttingResultPriceItem = {
cost_per_unit: number; cost_per_unit: number;
cost_per_unit_formatted: string; cost_per_unit_formatted: string;
type_label: string; type_label: string;
product_variant?: {
id: number;
name: string;
product?: {
id: number;
name: string;
};
};
}; };
export type CuttingResultListItem = { export type CuttingResultListItem = {