- Deleted `data-table-actions.vue` component as it is no longer needed. - Removed `CuttingResultPriceItem` type and related properties from `cutting.ts`. - Updated routes in `web.php` to eliminate stock verification routes and permissions. - Removed `StockTest.php` file and its associated tests for stock verification and management. - Adjusted `CuttingTest.php` to reflect changes in cutting results handling and removed references to product variants.
317 lines
14 KiB
Vue
317 lines
14 KiB
Vue
<script setup lang="ts">
|
|
import { computed } from 'vue';
|
|
import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue';
|
|
import { Badge } from '@/components/ui/badge';
|
|
import {
|
|
Table,
|
|
TableBody,
|
|
TableCell,
|
|
TableHead,
|
|
TableHeader,
|
|
TableRow,
|
|
} from '@/components/ui/table';
|
|
import { cuttingStatusBadgeVariant } from '@/constants/cutting-status';
|
|
import type { CuttingListItem } from '@/types/cutting';
|
|
|
|
const props = defineProps<{
|
|
cutting: CuttingListItem;
|
|
}>();
|
|
|
|
interface GroupedMaterials {
|
|
key: number;
|
|
name: string;
|
|
unitLabel?: string;
|
|
items: typeof props.cutting.materials;
|
|
isCombination?: boolean;
|
|
}
|
|
|
|
const groupedMaterials = computed<GroupedMaterials[]>(() => {
|
|
// First, group by combination_id
|
|
const combinationGroups: Record<number, typeof props.cutting.materials> = {};
|
|
const nonCombinationItems: typeof props.cutting.materials = [];
|
|
|
|
props.cutting.materials.forEach((item) => {
|
|
if (item.combination_id) {
|
|
if (!combinationGroups[item.combination_id]) {
|
|
combinationGroups[item.combination_id] = [];
|
|
}
|
|
|
|
combinationGroups[item.combination_id].push(item);
|
|
} else {
|
|
nonCombinationItems.push(item);
|
|
}
|
|
});
|
|
|
|
const result: GroupedMaterials[] = [];
|
|
|
|
// Add combination groups
|
|
Object.entries(combinationGroups).forEach(([combinationId, items]) => {
|
|
result.push({
|
|
key: Number(combinationId) * -1,
|
|
name: 'Kombinasi',
|
|
items,
|
|
isCombination: true,
|
|
});
|
|
});
|
|
|
|
// Group non-combination items by raw material
|
|
const groups: Record<number, GroupedMaterials> = {};
|
|
|
|
nonCombinationItems.forEach((item) => {
|
|
const key = item.raw_material_id ?? 0;
|
|
const name = item.raw_material_name || 'Bahan Baku Tidak Diketahui';
|
|
|
|
if (!groups[key]) {
|
|
groups[key] = {
|
|
key,
|
|
name,
|
|
unitLabel: item.raw_material_unit_label,
|
|
items: [],
|
|
};
|
|
}
|
|
|
|
groups[key].items.push(item);
|
|
});
|
|
|
|
result.push(...Object.values(groups));
|
|
|
|
return result;
|
|
});
|
|
</script>
|
|
|
|
<template>
|
|
<div class="min-h-screen bg-background">
|
|
<div class="mx-auto max-w-3xl px-4 py-8 sm:px-6 lg:px-8">
|
|
<!-- Header -->
|
|
<div class="mb-8 text-center">
|
|
<h1 class="text-2xl font-bold tracking-tight">
|
|
Detail Cutting
|
|
</h1>
|
|
<p class="mt-1 text-muted-foreground">
|
|
Rincian data proses cutting
|
|
</p>
|
|
</div>
|
|
|
|
<!-- Main Card -->
|
|
<div class="overflow-hidden rounded-lg border bg-card shadow-sm">
|
|
<!-- Cutting Info Header -->
|
|
<div class="border-b bg-muted/30 p-6">
|
|
<div class="flex flex-wrap items-center gap-3">
|
|
<h2 class="text-xl font-semibold">
|
|
Cutting #{{ cutting.id }}
|
|
</h2>
|
|
<Badge
|
|
:variant="cuttingStatusBadgeVariant(cutting.status)"
|
|
>
|
|
{{ cutting.status_label }}
|
|
</Badge>
|
|
</div>
|
|
<div class="mt-3 space-y-1 text-sm text-muted-foreground">
|
|
<p>{{ cutting.created_at_formatted }}</p>
|
|
<p>
|
|
Oleh
|
|
{{
|
|
cutting.created_by?.profile?.full_name ??
|
|
cutting.created_by?.username
|
|
}}
|
|
</p>
|
|
</div>
|
|
<p v-if="cutting.description" class="mt-3 text-sm">
|
|
{{ cutting.description }}
|
|
</p>
|
|
|
|
<div v-if="cutting.images?.length" class="mt-4">
|
|
<MediaThumbnailCell
|
|
:items="cutting.images"
|
|
:max-visible="4"
|
|
/>
|
|
</div>
|
|
|
|
</div>
|
|
|
|
<!-- Results Section -->
|
|
<div v-if="cutting.results.length" class="border-b p-6">
|
|
<h3 class="mb-3 text-sm font-semibold">Hasil Produk</h3>
|
|
<div class="overflow-hidden rounded-md border">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Produk</TableHead>
|
|
<TableHead class="text-right"
|
|
>Hasil</TableHead
|
|
>
|
|
<TableHead class="text-right"
|
|
>Sample</TableHead
|
|
>
|
|
<TableHead class="text-right"
|
|
>Diluar Sample</TableHead
|
|
>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
<TableRow
|
|
v-for="result in cutting.results"
|
|
:key="result.id"
|
|
>
|
|
<TableCell>
|
|
{{ result.product_name ?? 'Produk Tidak Diketahui' }}
|
|
</TableCell>
|
|
<TableCell
|
|
class="text-right tabular-nums"
|
|
>
|
|
{{ result.cutting_result }} pcs
|
|
</TableCell>
|
|
<TableCell
|
|
class="text-right tabular-nums"
|
|
>
|
|
{{ result.sample }} pcs
|
|
</TableCell>
|
|
<TableCell
|
|
class="text-right tabular-nums"
|
|
>
|
|
{{ result.original_outside_sample }}
|
|
pcs
|
|
</TableCell>
|
|
</TableRow>
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Materials Section -->
|
|
<div v-if="cutting.materials.length" class="border-b p-6">
|
|
<h3 class="mb-3 text-sm font-semibold">Bahan Baku</h3>
|
|
<div class="overflow-hidden rounded-md border">
|
|
<Table>
|
|
<TableHeader>
|
|
<TableRow>
|
|
<TableHead>Varian</TableHead>
|
|
<TableHead>Foto</TableHead>
|
|
<TableHead class="text-right"
|
|
>Pemakaian</TableHead
|
|
>
|
|
<TableHead class="text-right"
|
|
>Hasil</TableHead
|
|
>
|
|
</TableRow>
|
|
</TableHeader>
|
|
<TableBody>
|
|
<template
|
|
v-for="(group, groupIndex) in groupedMaterials"
|
|
:key="group.key"
|
|
>
|
|
<TableRow
|
|
class="bg-muted/20 hover:bg-muted/20"
|
|
>
|
|
<TableCell
|
|
colspan="4"
|
|
class="font-semibold"
|
|
>
|
|
<template v-if="group.isCombination">
|
|
<span class="text-primary">{{ groupIndex + 1 }}. {{ group.name }}</span>
|
|
<Badge
|
|
variant="default"
|
|
class="ml-2 font-normal"
|
|
>
|
|
{{ group.items.length }} bahan
|
|
</Badge>
|
|
<Badge
|
|
v-if="group.items[0]?.combination_material_result !== null && group.items[0]?.combination_material_result !== undefined"
|
|
variant="secondary"
|
|
class="ml-2 font-normal"
|
|
>
|
|
Hasil: {{ group.items[0].combination_material_result }} pcs
|
|
</Badge>
|
|
</template>
|
|
<template v-else>
|
|
{{ groupIndex + 1 }}. {{ group.name }}
|
|
<Badge
|
|
v-if="group.unitLabel"
|
|
variant="secondary"
|
|
class="ml-2 font-normal"
|
|
>
|
|
{{ group.unitLabel }}
|
|
</Badge>
|
|
</template>
|
|
</TableCell>
|
|
</TableRow>
|
|
<TableRow
|
|
v-for="material in group.items"
|
|
:key="material.id"
|
|
>
|
|
<TableCell class="pl-6">
|
|
{{ material.variant }}
|
|
</TableCell>
|
|
<TableCell>
|
|
<MediaThumbnailCell
|
|
:items="material.images ?? []"
|
|
:max-visible="1"
|
|
:all-stocks="(material.images ?? []).map(() => `Pemakaian: ${material.material_usage_formatted}`)"
|
|
/>
|
|
</TableCell>
|
|
<TableCell
|
|
class="text-right tabular-nums"
|
|
>
|
|
{{
|
|
material.material_usage_formatted
|
|
}}
|
|
</TableCell>
|
|
<TableCell
|
|
class="text-right tabular-nums"
|
|
>
|
|
<template v-if="group.isCombination && material.combination_material_result !== null && material.combination_material_result !== undefined">
|
|
{{ material.combination_material_result }} pcs
|
|
</template>
|
|
<template v-else-if="!group.isCombination && material.material_result !== null && material.material_result !== undefined">
|
|
{{ material.material_result }} pcs
|
|
</template>
|
|
<template v-else>
|
|
-
|
|
</template>
|
|
</TableCell>
|
|
</TableRow>
|
|
</template>
|
|
</TableBody>
|
|
</Table>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Summary -->
|
|
<div class="p-6">
|
|
<h3 class="mb-3 text-sm font-semibold">Ringkasan</h3>
|
|
<div class="grid gap-4 sm:grid-cols-2">
|
|
<div class="rounded-lg border p-3">
|
|
<p class="text-xs text-muted-foreground">
|
|
Total Hasil Cutting
|
|
</p>
|
|
<p class="mt-1 text-lg font-semibold text-primary">
|
|
{{ cutting.total_result_pieces ?? 0 }} pcs
|
|
</p>
|
|
</div>
|
|
<div
|
|
v-if="
|
|
cutting.total_material_usage_summary_formatted
|
|
"
|
|
class="rounded-lg border p-3"
|
|
>
|
|
<p class="text-xs text-muted-foreground">
|
|
Total Pemakaian Bahan
|
|
</p>
|
|
<p class="mt-1 text-lg font-semibold text-primary">
|
|
{{
|
|
cutting.total_material_usage_summary_formatted
|
|
}}
|
|
</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
|
|
<!-- Footer -->
|
|
<div class="mt-6 text-center text-xs text-muted-foreground">
|
|
<p>Data ini dibagikan dari sistem DST Collection</p>
|
|
</div>
|
|
</div>
|
|
</div>
|
|
</template>
|