From 4466c6135230cc69a1262b8c891c9ce90ea4442d Mon Sep 17 00:00:00 2001
From: Yoga Pangestu
Date: Tue, 30 Jun 2026 21:35:52 +0700
Subject: [PATCH] feat: make cutting results nullable and update UI to support
create mode
---
.../Manage/CuttingDraftResultRequest.php | 6 +-
app/Services/Manage/CuttingService.php | 58 +++++++++++--------
..._make_cutting_results_columns_nullable.php | 32 ++++++++++
.../js/pages/admin/manage/cuttings/Edit.vue | 6 +-
.../js/pages/admin/manage/cuttings/Share.vue | 4 +-
.../form/CuttingPosCartDetailDialog.vue | 3 +-
.../manage/cuttings/form/CuttingPosForm.vue | 5 +-
.../form/CuttingPosResultCatalogPanel.vue | 57 +++++++++++-------
.../form/CuttingPosResultSummaryItems.vue | 5 +-
.../cuttings/form/CuttingPosSummaryPanel.vue | 4 +-
.../manage/cuttings/form/useCuttingPosCart.ts | 18 +++---
.../table/CuttingCompletedSection.vue | 2 +-
.../cuttings/table/CuttingGroupedTable.vue | 4 +-
.../table/CuttingInProgressSection.vue | 5 +-
resources/js/types/cutting.ts | 6 +-
15 files changed, 139 insertions(+), 76 deletions(-)
create mode 100644 database/migrations/2026_06_30_213126_make_cutting_results_columns_nullable.php
diff --git a/app/Http/Requests/Admin/Manage/CuttingDraftResultRequest.php b/app/Http/Requests/Admin/Manage/CuttingDraftResultRequest.php
index f27a826..f95614b 100644
--- a/app/Http/Requests/Admin/Manage/CuttingDraftResultRequest.php
+++ b/app/Http/Requests/Admin/Manage/CuttingDraftResultRequest.php
@@ -24,9 +24,9 @@ public function rules(): array
'integer',
Rule::exists('product_variants', 'id')->whereNull('deleted_at'),
],
- 'cutting_result' => ['required', 'integer', 'min:1'],
- 'sample' => ['required', 'integer', 'min:0'],
- 'original_outside_sample' => ['required', 'integer', 'min:0'],
+ 'cutting_result' => ['nullable', 'integer', 'min:1'],
+ 'sample' => ['nullable', 'integer', 'min:0'],
+ 'original_outside_sample' => ['nullable', 'integer', 'min:0'],
];
}
}
diff --git a/app/Services/Manage/CuttingService.php b/app/Services/Manage/CuttingService.php
index 3fd3612..6c4b5c6 100644
--- a/app/Services/Manage/CuttingService.php
+++ b/app/Services/Manage/CuttingService.php
@@ -311,32 +311,40 @@ public function syncDraftResult(array $validated, User $user): array
->with('product:id,name')
->findOrFail($validated['product_variant_id']);
- $cuttingResult = (int) $validated['cutting_result'];
- $sample = (int) $validated['sample'];
- $originalOutsideSample = (int) ($validated['original_outside_sample'] ?? 0);
+ $cuttingResult = array_key_exists('cutting_result', $validated) && $validated['cutting_result'] !== null
+ ? (int) $validated['cutting_result']
+ : null;
+ $sample = array_key_exists('sample', $validated) && $validated['sample'] !== null
+ ? (int) $validated['sample']
+ : null;
+ $originalOutsideSample = array_key_exists('original_outside_sample', $validated) && $validated['original_outside_sample'] !== null
+ ? (int) $validated['original_outside_sample']
+ : null;
- if ($cuttingResult < 1) {
- throw ValidationException::withMessages([
- 'cutting_result' => 'Hasil cutting minimal 1 pcs.',
- ]);
- }
+ if ($cuttingResult !== null) {
+ if ($cuttingResult < 1) {
+ throw ValidationException::withMessages([
+ 'cutting_result' => 'Hasil cutting minimal 1 pcs.',
+ ]);
+ }
- if ($sample < 0) {
- throw ValidationException::withMessages([
- 'sample' => 'sample tidak boleh negatif.',
- ]);
- }
+ if ($sample !== null && $sample < 0) {
+ throw ValidationException::withMessages([
+ 'sample' => 'sample tidak boleh negatif.',
+ ]);
+ }
- if ($originalOutsideSample < 0) {
- throw ValidationException::withMessages([
- 'original_outside_sample' => 'Hasil cutting diluar sample tidak boleh negatif.',
- ]);
- }
+ if ($originalOutsideSample !== null && $originalOutsideSample < 0) {
+ throw ValidationException::withMessages([
+ 'original_outside_sample' => 'Hasil cutting diluar sample tidak boleh negatif.',
+ ]);
+ }
- if (($sample + $originalOutsideSample) !== $cuttingResult) {
- throw ValidationException::withMessages([
- 'cutting_result' => 'Hasil cutting harus sama dengan sample ditambah hasil cutting diluar sample.',
- ]);
+ if ($sample !== null && $originalOutsideSample !== null && ($sample + $originalOutsideSample) !== $cuttingResult) {
+ throw ValidationException::withMessages([
+ 'cutting_result' => 'Hasil cutting harus sama dengan sample ditambah hasil cutting diluar sample.',
+ ]);
+ }
}
$item = CuttingResult::query()->updateOrCreate(
@@ -909,9 +917,9 @@ private function presentDraftResult(CuttingResult $item): array
'product_name' => $variant?->product?->name ?? '',
'variant_name' => $variant?->name ?? '',
'stock' => $variant?->stock ?? 0,
- 'cutting_result' => (string) $item->cutting_result,
- 'sample' => (string) $item->sample,
- 'original_outside_sample' => (string) $item->original_outside_sample,
+ 'cutting_result' => $item->cutting_result !== null ? (string) $item->cutting_result : null,
+ 'sample' => $item->sample !== null ? (string) $item->sample : null,
+ 'original_outside_sample' => $item->original_outside_sample !== null ? (string) $item->original_outside_sample : null,
'images' => $variant ? MediaPresenter::collection($variant, 'images') : [],
];
}
diff --git a/database/migrations/2026_06_30_213126_make_cutting_results_columns_nullable.php b/database/migrations/2026_06_30_213126_make_cutting_results_columns_nullable.php
new file mode 100644
index 0000000..ddbcb0e
--- /dev/null
+++ b/database/migrations/2026_06_30_213126_make_cutting_results_columns_nullable.php
@@ -0,0 +1,32 @@
+unsignedInteger('cutting_result')->nullable()->change();
+ $table->unsignedInteger('sample')->nullable()->change();
+ $table->unsignedInteger('original_outside_sample')->nullable()->default(null)->change();
+ });
+ }
+
+ /**
+ * Reverse the migrations.
+ */
+ public function down(): void
+ {
+ Schema::table('cutting_results', function (Blueprint $table) {
+ $table->unsignedInteger('cutting_result')->nullable(false)->change();
+ $table->unsignedInteger('sample')->nullable(false)->change();
+ $table->unsignedInteger('original_outside_sample')->nullable(false)->default(0)->change();
+ });
+ }
+};
diff --git a/resources/js/pages/admin/manage/cuttings/Edit.vue b/resources/js/pages/admin/manage/cuttings/Edit.vue
index d8545c5..a643b63 100644
--- a/resources/js/pages/admin/manage/cuttings/Edit.vue
+++ b/resources/js/pages/admin/manage/cuttings/Edit.vue
@@ -36,9 +36,9 @@ const initialData = computed(() => ({
product_name: item.product_variant?.product?.name ?? '',
variant_name: item.product_variant?.name ?? '',
stock: item.product_variant?.stock ?? 0,
- cutting_result: String(item.cutting_result),
- sample: String(item.sample),
- original_outside_sample: String(item.original_outside_sample),
+ cutting_result: String(item.cutting_result ?? 0),
+ sample: String(item.sample ?? 0),
+ original_outside_sample: String(item.original_outside_sample ?? 0),
images: item.product_variant?.images ?? [],
})),
}));
diff --git a/resources/js/pages/admin/manage/cuttings/Share.vue b/resources/js/pages/admin/manage/cuttings/Share.vue
index b961a5c..7b97c67 100644
--- a/resources/js/pages/admin/manage/cuttings/Share.vue
+++ b/resources/js/pages/admin/manage/cuttings/Share.vue
@@ -140,7 +140,7 @@ const groupedResults = computed(() => {
{{ material.variant }}
-
+
{{ material.material_usage_formatted }}
@@ -178,7 +178,7 @@ const groupedResults = computed(() => {
{{ result.product_variant?.name }}
-
+
{{ result.cutting_result }} pcs
diff --git a/resources/js/pages/admin/manage/cuttings/form/CuttingPosCartDetailDialog.vue b/resources/js/pages/admin/manage/cuttings/form/CuttingPosCartDetailDialog.vue
index 7897d69..9dfaa20 100644
--- a/resources/js/pages/admin/manage/cuttings/form/CuttingPosCartDetailDialog.vue
+++ b/resources/js/pages/admin/manage/cuttings/form/CuttingPosCartDetailDialog.vue
@@ -13,6 +13,7 @@ defineProps<{
resultCart: CuttingResultCartItem[];
materialLineCost: (item: CuttingMaterialCartItem) => number;
totalMaterialCost: number;
+ isCreateMode: boolean;
}>();
const open = defineModel('open', { required: true });
@@ -61,7 +62,7 @@ const open = defineModel('open', { required: true });
-
+
Hasil: {{ item.cutting_result }}
ยท
Sample: {{ item.sample }}
diff --git a/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue b/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue
index df83ed6..ee2a457 100644
--- a/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue
+++ b/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue
@@ -153,16 +153,19 @@ function submit() {
+ :material-line-cost="materialLineCost" :total-material-cost="totalMaterialCost"
+ :is-create-mode="isCreateMode" />
diff --git a/resources/js/pages/admin/manage/cuttings/form/CuttingPosResultCatalogPanel.vue b/resources/js/pages/admin/manage/cuttings/form/CuttingPosResultCatalogPanel.vue
index 8a0dfb8..931e03e 100644
--- a/resources/js/pages/admin/manage/cuttings/form/CuttingPosResultCatalogPanel.vue
+++ b/resources/js/pages/admin/manage/cuttings/form/CuttingPosResultCatalogPanel.vue
@@ -1,5 +1,5 @@