From 175e0dc5af0231ab1cd28cacb7e05d77e3e82db3 Mon Sep 17 00:00:00 2001 From: Yoga Pangestu Date: Sun, 21 Jun 2026 11:02:54 +0700 Subject: [PATCH] refactor: update material usage and remaining material precision to four decimal places across cutting management components for improved accuracy --- .../Manage/CuttingDraftMaterialRequest.php | 4 +- .../Requests/Admin/Manage/CuttingRequest.php | 4 +- app/Models/CuttingMaterial.php | 12 ++-- app/Services/Manage/CuttingService.php | 26 +++---- ...te_cutting_materials_decimal_precision.php | 24 +++++++ .../form/decimal-input/DecimalInput.vue | 4 +- .../manage/cuttings/form/CuttingPosForm.vue | 72 +++---------------- .../table/CuttingCompletedSection.vue | 37 ++++++++-- .../cuttings/table/CuttingGroupedTable.vue | 5 -- .../table/CuttingInProgressSection.vue | 33 ++++++++- .../cuttings/table/data-table-actions.vue | 30 -------- 11 files changed, 123 insertions(+), 128 deletions(-) create mode 100644 database/migrations/2026_06_21_040000_update_cutting_materials_decimal_precision.php diff --git a/app/Http/Requests/Admin/Manage/CuttingDraftMaterialRequest.php b/app/Http/Requests/Admin/Manage/CuttingDraftMaterialRequest.php index 078bcaa..0486a82 100644 --- a/app/Http/Requests/Admin/Manage/CuttingDraftMaterialRequest.php +++ b/app/Http/Requests/Admin/Manage/CuttingDraftMaterialRequest.php @@ -24,8 +24,8 @@ public function rules(): array 'integer', Rule::exists('raw_material_prices', 'id')->whereNull('deleted_at'), ], - 'material_usage' => ['required', 'numeric', 'decimal:0,2', 'gt:0'], - 'remaining_material' => ['required', 'numeric', 'decimal:0,2', 'gte:0'], + 'material_usage' => ['required', 'numeric', 'decimal:0,4', 'gt:0'], + 'remaining_material' => ['required', 'numeric', 'decimal:0,4', 'gte:0'], ]; } } diff --git a/app/Http/Requests/Admin/Manage/CuttingRequest.php b/app/Http/Requests/Admin/Manage/CuttingRequest.php index ad7bfc0..f8a4e3f 100644 --- a/app/Http/Requests/Admin/Manage/CuttingRequest.php +++ b/app/Http/Requests/Admin/Manage/CuttingRequest.php @@ -39,8 +39,8 @@ public function rules(): array 'distinct', Rule::exists('raw_material_prices', 'id')->whereNull('deleted_at'), ]; - $rules['materials.*.material_usage'] = ['required', 'numeric', 'decimal:0,2', 'gt:0']; - $rules['materials.*.remaining_material'] = ['required', 'numeric', 'decimal:0,2', 'gte:0']; + $rules['materials.*.material_usage'] = ['required', 'numeric', 'decimal:0,4', 'gt:0']; + $rules['materials.*.remaining_material'] = ['required', 'numeric', 'decimal:0,4', 'gte:0']; $rules['results'] = ['required', 'array', 'min:1']; $rules['results.*.product_variant_id'] = [ diff --git a/app/Models/CuttingMaterial.php b/app/Models/CuttingMaterial.php index 8f37aba..6cc1743 100644 --- a/app/Models/CuttingMaterial.php +++ b/app/Models/CuttingMaterial.php @@ -31,8 +31,8 @@ class CuttingMaterial extends Model protected function casts(): array { return [ - 'material_usage' => 'decimal:2', - 'remaining_material' => 'decimal:2', + 'material_usage' => 'decimal:4', + 'remaining_material' => 'decimal:4', ]; } @@ -172,7 +172,7 @@ private function formatCmQuantity(float|string|null $value): ?string return null; } - $formatted = rtrim(rtrim(number_format($cm, 2, ',', '.'), '0'), ','); + $formatted = rtrim(rtrim(number_format($cm, 4, ',', '.'), '0'), ','); return "{$formatted} cm"; } @@ -195,18 +195,18 @@ private function formatCmQuantityInput(float|string|null $value): ?string return null; } - return rtrim(rtrim(number_format($cm, 2, '.', ''), '0'), '.'); + return rtrim(rtrim(number_format($cm, 4, '.', ''), '0'), '.'); } private function formatQuantity(float|string|null $value): string { - $formatted = rtrim(rtrim(number_format((float) $value, 2, ',', '.'), '0'), ','); + $formatted = rtrim(rtrim(number_format((float) $value, 4, ',', '.'), '0'), ','); return "{$formatted} {$this->unitAbbreviation}"; } private function formatQuantityInput(float|string|null $value): string { - return rtrim(rtrim(number_format((float) $value, 2, '.', ''), '0'), '.'); + return rtrim(rtrim(number_format((float) $value, 4, '.', ''), '0'), '.'); } } diff --git a/app/Services/Manage/CuttingService.php b/app/Services/Manage/CuttingService.php index ff20b76..aac51a5 100644 --- a/app/Services/Manage/CuttingService.php +++ b/app/Services/Manage/CuttingService.php @@ -284,12 +284,12 @@ public function syncDraftMaterial(array $validated, User $user): array ->findOrFail($validated['raw_material_price_id']); $unit = $price->rawMaterial?->unit; - $usageInput = round((float) $validated['material_usage'], 2); - $remainingInput = round((float) $validated['remaining_material'], 2); + $usageInput = round((float) $validated['material_usage'], 4); + $remainingInput = round((float) $validated['remaining_material'], 4); if ($unit !== null && $unit->usesLengthUnit()) { - $materialUsage = round($unit->fromCm($usageInput), 2); - $remainingMaterial = round($unit->fromCm($remainingInput), 2); + $materialUsage = round($unit->fromCm($usageInput), 4); + $remainingMaterial = round($unit->fromCm($remainingInput), 4); } else { $materialUsage = $usageInput; $remainingMaterial = $remainingInput; @@ -655,12 +655,12 @@ private function buildMaterials(array $materials): array } $unit = $price->rawMaterial?->unit; - $usageInput = round((float) $itemData['material_usage'], 2); - $remainingInput = round((float) $itemData['remaining_material'], 2); + $usageInput = round((float) $itemData['material_usage'], 4); + $remainingInput = round((float) $itemData['remaining_material'], 4); if ($unit !== null && $unit->usesLengthUnit()) { - $materialUsage = round($unit->fromCm($usageInput), 2); - $remainingMaterial = round($unit->fromCm($remainingInput), 2); + $materialUsage = round($unit->fromCm($usageInput), 4); + $remainingMaterial = round($unit->fromCm($remainingInput), 4); } else { $materialUsage = $usageInput; $remainingMaterial = $remainingInput; @@ -898,10 +898,10 @@ private function presentDraftMaterial(CuttingMaterial $item): array // Convert stored native unit back to cm for display if ($usesLengthUnit && $unit !== null) { - $materialUsageCm = round($unit->toCm((float) $item->material_usage), 2); - $remainingMaterialCm = round($unit->toCm((float) $item->remaining_material), 2); - $materialUsageDisplay = (string) $materialUsageCm; - $remainingMaterialDisplay = (string) $remainingMaterialCm; + $materialUsageCm = round($unit->toCm((float) $item->material_usage), 4); + $remainingMaterialCm = round($unit->toCm((float) $item->remaining_material), 4); + $materialUsageDisplay = rtrim(rtrim(number_format($materialUsageCm, 4, '.', ''), '0'), '.'); + $remainingMaterialDisplay = rtrim(rtrim(number_format($remainingMaterialCm, 4, '.', ''), '0'), '.'); } else { $materialUsageDisplay = $this->formatQuantityInput((float) $item->material_usage); $remainingMaterialDisplay = $this->formatQuantityInput((float) $item->remaining_material); @@ -942,7 +942,7 @@ private function presentDraftResult(CuttingResult $item): array private function formatQuantityInput(float $value): string { - return rtrim(rtrim(number_format($value, 2, '.', ''), '0'), '.'); + return rtrim(rtrim(number_format($value, 4, '.', ''), '0'), '.'); } private function appendCostPreview(Cutting $cutting): void diff --git a/database/migrations/2026_06_21_040000_update_cutting_materials_decimal_precision.php b/database/migrations/2026_06_21_040000_update_cutting_materials_decimal_precision.php new file mode 100644 index 0000000..4ba2339 --- /dev/null +++ b/database/migrations/2026_06_21_040000_update_cutting_materials_decimal_precision.php @@ -0,0 +1,24 @@ +decimal('material_usage', 18, 4)->change(); + $table->decimal('remaining_material', 18, 4)->change(); + }); + } + + public function down(): void + { + Schema::table('cutting_materials', function (Blueprint $table): void { + $table->decimal('material_usage', 18, 2)->change(); + $table->decimal('remaining_material', 18, 2)->change(); + }); + } +}; diff --git a/resources/js/components/form/decimal-input/DecimalInput.vue b/resources/js/components/form/decimal-input/DecimalInput.vue index c042fb7..3c505c4 100644 --- a/resources/js/components/form/decimal-input/DecimalInput.vue +++ b/resources/js/components/form/decimal-input/DecimalInput.vue @@ -36,7 +36,7 @@ return ''; let decimalPart = parts[1]; if (decimalPart !== undefined) { - decimalPart = decimalPart.slice(0, 2); + decimalPart = decimalPart.slice(0, 4); return `${integerPart},${decimalPart}`; } @@ -68,7 +68,7 @@ function parseDecimal(value: string): string { const cleanParts = clean.split('.'); if (cleanParts[1] !== undefined) { - clean = `${cleanParts[0]}.${cleanParts[1].slice(0, 2)}`; + clean = `${cleanParts[0]}.${cleanParts[1].slice(0, 4)}`; } return clean; diff --git a/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue b/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue index eb6ca95..debec21 100644 --- a/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue +++ b/resources/js/pages/admin/manage/cuttings/form/CuttingPosForm.vue @@ -3,11 +3,8 @@ import { useForm } from '@inertiajs/vue3'; import { Minus, Plus, Save, Scissors, Search, Trash2 } from '@lucide/vue'; import { computed, ref, watch } from 'vue'; import { toast } from 'vue-sonner'; -import PosCatalogCard from '../../shared/PosCatalogCard.vue'; -import PosCatalogVariantThumb from '../../shared/PosCatalogVariantThumb.vue'; import { DecimalInput } from '@/components/form/decimal-input'; import { NumberInput } from '@/components/form/number-input'; -import { RupiahInput } from '@/components/form/rupiah-input'; import { Badge } from '@/components/ui/badge'; import { Button } from '@/components/ui/button'; import { Card, CardContent, CardHeader, CardTitle } from '@/components/ui/card'; @@ -45,6 +42,8 @@ import type { CuttingRawMaterialCatalogItem, CuttingResultCartItem, } from '@/types/cutting'; +import PosCatalogCard from '../../shared/PosCatalogCard.vue'; +import PosCatalogVariantThumb from '../../shared/PosCatalogVariantThumb.vue'; function usesLengthUnit(unit: string): boolean { return unit === 'yard' || unit === 'meter'; @@ -167,7 +166,7 @@ const estimatedCostPerUnit = computed(() => { return 0; } - return Math.round(totalProductionCost.value / totalResultPieces.value); + return Math.round(totalMaterialCost.value / totalResultPieces.value); }); function populateForm() { @@ -314,7 +313,8 @@ async function decreaseMaterialQty(priceId: number) { return; } - const nextQty = (Number(item.material_usage) || 0) - 1; + const decrement = item.uses_length_unit ? 100 : 1; + const nextQty = (Number(item.material_usage) || 0) - decrement; if (nextQty <= 0) { const index = materialCart.value.findIndex( @@ -355,8 +355,9 @@ async function addMaterial( ); const defaultUsage = usesLengthUnit(rawMaterial.unit) ? '100' : '1'; + const increment = usesLengthUnit(rawMaterial.unit) ? 100 : 1; const nextUsage = existing - ? String((Number(existing.material_usage) || 0) + 1) + ? String((Number(existing.material_usage) || 0) + increment) : defaultUsage; const remaining = existing?.remaining_material ?? '0'; @@ -1002,7 +1003,7 @@ function submit() { -
+
Pemakaian ({{ item.uses_length_unit ? 'cm' : item.unit_abbreviation }}) @@ -1035,16 +1036,6 @@ function submit() { " /> - - - Harga Modal - -
- {{ formatRupiah(materialLineCost(item)) }} -
-
@@ -1151,41 +1142,6 @@ function submit() { - - -
- - Jasa Jahit - - - - - Biaya Lainnya - - - -
- - -