feat: include and display media images for raw material prices and product variants in cutting management
This commit is contained in:
parent
e76fd8107b
commit
9f0676c923
@ -35,8 +35,9 @@ public function paginateForIndex(array $tableQuery, User $user): LengthAwarePagi
|
||||
'createdBy.profile',
|
||||
'rejection.rejectedBy.profile',
|
||||
'materials.rawMaterialPrice.rawMaterial:id,name,unit',
|
||||
'materials.rawMaterialPrice.media',
|
||||
'results.productVariant.product:id,name',
|
||||
'results.productVariant:id,product_id,name',
|
||||
'results.productVariant.media',
|
||||
])
|
||||
->when($tableQuery['search'] !== '', function (Builder $query) use ($tableQuery): void {
|
||||
$search = $tableQuery['search'];
|
||||
@ -62,6 +63,7 @@ public function paginateForIndex(array $tableQuery, User $user): LengthAwarePagi
|
||||
$cutting->setAttribute('available_actions', $this->filterActionsForUser($cutting, $user));
|
||||
$cutting->setAttribute('is_editable', $cutting->status->isEditable());
|
||||
$this->appendCostPreview($cutting);
|
||||
$this->appendPhotos($cutting);
|
||||
$cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m));
|
||||
|
||||
return $cutting;
|
||||
@ -75,8 +77,9 @@ public function getInProgressCuttings(User $user): Collection
|
||||
'createdBy.profile',
|
||||
'rejection.rejectedBy.profile',
|
||||
'materials.rawMaterialPrice.rawMaterial:id,name,unit',
|
||||
'materials.rawMaterialPrice.media',
|
||||
'results.productVariant.product:id,name',
|
||||
'results.productVariant:id,product_id,name',
|
||||
'results.productVariant.media',
|
||||
])
|
||||
->inProgress()
|
||||
->latest()
|
||||
@ -85,6 +88,7 @@ public function getInProgressCuttings(User $user): Collection
|
||||
$cutting->setAttribute('available_actions', $this->filterActionsForUser($cutting, $user));
|
||||
$cutting->setAttribute('is_editable', $cutting->status->isEditable());
|
||||
$this->appendCostPreview($cutting);
|
||||
$this->appendPhotos($cutting);
|
||||
$cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m));
|
||||
});
|
||||
}
|
||||
@ -96,8 +100,9 @@ public function getCompletedCuttings(User $user): Collection
|
||||
'createdBy.profile',
|
||||
'rejection.rejectedBy.profile',
|
||||
'materials.rawMaterialPrice.rawMaterial:id,name,unit',
|
||||
'materials.rawMaterialPrice.media',
|
||||
'results.productVariant.product:id,name',
|
||||
'results.productVariant:id,product_id,name',
|
||||
'results.productVariant.media',
|
||||
])
|
||||
->completed()
|
||||
->latest()
|
||||
@ -106,6 +111,7 @@ public function getCompletedCuttings(User $user): Collection
|
||||
$cutting->setAttribute('available_actions', $this->filterActionsForUser($cutting, $user));
|
||||
$cutting->setAttribute('is_editable', $cutting->status->isEditable());
|
||||
$this->appendCostPreview($cutting);
|
||||
$this->appendPhotos($cutting);
|
||||
$cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m));
|
||||
});
|
||||
}
|
||||
@ -187,14 +193,37 @@ public function findForEdit(Cutting $cutting): Cutting
|
||||
'rejection.rejectedBy.profile',
|
||||
]);
|
||||
|
||||
$this->appendPhotos($cutting);
|
||||
$cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m));
|
||||
|
||||
return $cutting;
|
||||
}
|
||||
|
||||
public function findForShare(Cutting $cutting): Cutting
|
||||
{
|
||||
$cutting->load([
|
||||
'createdBy.profile',
|
||||
'materials.rawMaterialPrice.rawMaterial:id,name,unit',
|
||||
'materials.rawMaterialPrice.media',
|
||||
'results.productVariant.product:id,name',
|
||||
'results.productVariant.media',
|
||||
]);
|
||||
|
||||
$this->appendCostPreview($cutting);
|
||||
$this->appendPhotos($cutting);
|
||||
$cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m));
|
||||
|
||||
return $cutting;
|
||||
}
|
||||
|
||||
private function appendPhotos(Cutting $cutting): void
|
||||
{
|
||||
$cutting->materials->each(function (CuttingMaterial $material): void {
|
||||
$price = $material->rawMaterialPrice;
|
||||
|
||||
if ($price) {
|
||||
$price->setAttribute('images', MediaPresenter::collection($price, 'images'));
|
||||
}
|
||||
|
||||
$this->breakMaterialCircularReference($material);
|
||||
});
|
||||
|
||||
$cutting->results->each(function (CuttingResult $result): void {
|
||||
@ -207,23 +236,6 @@ public function findForEdit(Cutting $cutting): Cutting
|
||||
);
|
||||
}
|
||||
});
|
||||
|
||||
return $cutting;
|
||||
}
|
||||
|
||||
public function findForShare(Cutting $cutting): Cutting
|
||||
{
|
||||
$cutting->load([
|
||||
'createdBy.profile',
|
||||
'materials.rawMaterialPrice.rawMaterial:id,name,unit',
|
||||
'results.productVariant.product:id,name',
|
||||
'results.productVariant:id,product_id,name',
|
||||
]);
|
||||
|
||||
$this->appendCostPreview($cutting);
|
||||
$cutting->materials->each(fn (CuttingMaterial $m) => $this->breakMaterialCircularReference($m));
|
||||
|
||||
return $cutting;
|
||||
}
|
||||
|
||||
public function draftMaterialsForUser(User $user): array
|
||||
|
||||
@ -10,6 +10,7 @@ import {
|
||||
TableRow,
|
||||
} from '@/components/ui/table';
|
||||
import { cuttingStatusBadgeVariant } from '@/constants/cutting-status';
|
||||
import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue';
|
||||
import type { CuttingListItem } from '@/types/cutting';
|
||||
|
||||
const props = defineProps<{
|
||||
@ -120,13 +121,14 @@ const groupedResults = computed<GroupedResults[]>(() => {
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Varian</TableHead>
|
||||
<TableHead>Foto</TableHead>
|
||||
<TableHead class="text-right">Pemakaian</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<template v-for="group in groupedMaterials" :key="group.key">
|
||||
<TableRow class="bg-muted/20 hover:bg-muted/20">
|
||||
<TableCell colspan="2" class="font-semibold">
|
||||
<TableCell colspan="3" class="font-semibold">
|
||||
{{ group.name }}
|
||||
<Badge v-if="group.unitLabel" variant="secondary" class="ml-2 font-normal">
|
||||
{{ group.unitLabel }}
|
||||
@ -137,6 +139,9 @@ const groupedResults = computed<GroupedResults[]>(() => {
|
||||
<TableCell class="pl-6">
|
||||
{{ material.variant }}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<MediaThumbnailCell :items="material.images ?? []" />
|
||||
</TableCell>
|
||||
<TableCell class="text-right tabular-nums">
|
||||
{{ material.material_usage_formatted }}
|
||||
</TableCell>
|
||||
@ -155,6 +160,7 @@ const groupedResults = computed<GroupedResults[]>(() => {
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Varian</TableHead>
|
||||
<TableHead>Foto</TableHead>
|
||||
<TableHead class="text-right">Hasil</TableHead>
|
||||
<TableHead class="text-right">Sample</TableHead>
|
||||
<TableHead class="text-right">Diluar Sample</TableHead>
|
||||
@ -163,7 +169,7 @@ const groupedResults = computed<GroupedResults[]>(() => {
|
||||
<TableBody>
|
||||
<template v-for="group in groupedResults" :key="group.key">
|
||||
<TableRow class="bg-muted/20 hover:bg-muted/20">
|
||||
<TableCell colspan="4" class="font-semibold">
|
||||
<TableCell colspan="5" class="font-semibold">
|
||||
{{ group.name }}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@ -171,6 +177,9 @@ const groupedResults = computed<GroupedResults[]>(() => {
|
||||
<TableCell class="pl-6">
|
||||
{{ result.product_variant?.name }}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<MediaThumbnailCell :items="result.product_variant?.images ?? []" />
|
||||
</TableCell>
|
||||
<TableCell class="text-right tabular-nums">
|
||||
{{ result.cutting_result }} pcs
|
||||
</TableCell>
|
||||
|
||||
@ -15,6 +15,7 @@ import {
|
||||
} from '@/components/ui/table';
|
||||
import { usePaginationSummary } from '@/composables/usePaginationSummary';
|
||||
import { cuttingStatusBadgeVariant } from '@/constants/cutting-status';
|
||||
import MediaThumbnailCell from '@/components/media/MediaThumbnailCell.vue';
|
||||
import { groupedTableRowNumber } from '@/lib/grouped-table';
|
||||
import type { CuttingListItem } from '@/types/cutting';
|
||||
import type {
|
||||
@ -155,19 +156,20 @@ function getGroupedResults(results: any[]): GroupedCuttingResults[] {
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Varian</TableHead>
|
||||
<TableHead>Foto</TableHead>
|
||||
<TableHead>Pemakaian</TableHead>
|
||||
</TableRow>
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow v-if="!cutting.materials.length" :key="`${cutting.id}-material-empty`">
|
||||
<TableCell colspan="2" class="text-muted-foreground">
|
||||
<TableCell colspan="3" class="text-muted-foreground">
|
||||
Belum ada bahan baku
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<template v-else v-for="group in getGroupedMaterials(cutting.materials)"
|
||||
:key="group.rawMaterialId">
|
||||
<TableRow class="bg-muted/20 hover:bg-muted/20">
|
||||
<TableCell colspan="2" class="font-semibold text-foreground">
|
||||
<TableCell colspan="3" class="font-semibold text-foreground">
|
||||
{{ group.rawMaterialName }}
|
||||
<Badge v-if="group.unitLabel" variant="secondary"
|
||||
class="ml-2 font-normal">
|
||||
@ -179,6 +181,9 @@ function getGroupedResults(results: any[]): GroupedCuttingResults[] {
|
||||
<TableCell class="pl-6 font-medium">
|
||||
{{ material.variant }}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<MediaThumbnailCell :items="material.images ?? []" />
|
||||
</TableCell>
|
||||
<TableCell class="tabular-nums">
|
||||
{{ material.material_usage_formatted }}
|
||||
</TableCell>
|
||||
@ -196,6 +201,7 @@ function getGroupedResults(results: any[]): GroupedCuttingResults[] {
|
||||
<TableHeader>
|
||||
<TableRow>
|
||||
<TableHead>Varian</TableHead>
|
||||
<TableHead>Foto</TableHead>
|
||||
<TableHead>Hasil</TableHead>
|
||||
<TableHead>Sample</TableHead>
|
||||
<TableHead>Diluar Sample</TableHead>
|
||||
@ -203,14 +209,14 @@ function getGroupedResults(results: any[]): GroupedCuttingResults[] {
|
||||
</TableHeader>
|
||||
<TableBody>
|
||||
<TableRow v-if="!cutting.results.length" :key="`${cutting.id}-result-empty`">
|
||||
<TableCell colspan="4" class="text-muted-foreground">
|
||||
<TableCell colspan="5" class="text-muted-foreground">
|
||||
Belum ada hasil produk
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
<template v-else v-for="group in getGroupedResults(cutting.results)"
|
||||
:key="group.productId">
|
||||
<TableRow class="bg-muted/20 hover:bg-muted/20">
|
||||
<TableCell colspan="4" class="font-semibold text-foreground">
|
||||
<TableCell colspan="5" class="font-semibold text-foreground">
|
||||
{{ group.productName }}
|
||||
</TableCell>
|
||||
</TableRow>
|
||||
@ -218,6 +224,9 @@ function getGroupedResults(results: any[]): GroupedCuttingResults[] {
|
||||
<TableCell class="pl-6 font-medium">
|
||||
{{ result.product_variant?.name }}
|
||||
</TableCell>
|
||||
<TableCell>
|
||||
<MediaThumbnailCell :items="result.product_variant?.images ?? []" />
|
||||
</TableCell>
|
||||
<TableCell class="tabular-nums">
|
||||
{{ result.cutting_result }} pcs
|
||||
</TableCell>
|
||||
|
||||
@ -18,9 +18,11 @@ export type CuttingMaterialListItem = {
|
||||
raw_material_id?: number;
|
||||
raw_material_name?: string;
|
||||
raw_material_unit_label?: string;
|
||||
images?: MediaItem[];
|
||||
raw_material_price?: {
|
||||
id: number;
|
||||
variant: string;
|
||||
images?: MediaItem[];
|
||||
raw_material?: {
|
||||
id: number;
|
||||
name: string;
|
||||
@ -50,6 +52,7 @@ export type CuttingResultListItem = {
|
||||
product_variant?: {
|
||||
id: number;
|
||||
name: string;
|
||||
images?: MediaItem[];
|
||||
product?: {
|
||||
id: number;
|
||||
name: string;
|
||||
|
||||
Loading…
Reference in New Issue
Block a user