diff --git a/app/Http/Controllers/Admin/Master/RawMaterialController.php b/app/Http/Controllers/Admin/Master/RawMaterialController.php index 661bd0f..3bf53cc 100644 --- a/app/Http/Controllers/Admin/Master/RawMaterialController.php +++ b/app/Http/Controllers/Admin/Master/RawMaterialController.php @@ -5,9 +5,11 @@ use App\Enums\RawMaterialUnit; use App\Http\Controllers\Concerns\FlashesEntityMessage; use App\Http\Controllers\Concerns\ParsesDataTableQuery; +use App\Enums\CuttingStatus; use App\Http\Controllers\Controller; use App\Http\Requests\Admin\Master\RawMaterialRequest; use App\Http\Requests\Admin\ToggleStatusRequest; +use App\Models\CuttingMaterial; use App\Models\RawMaterial; use App\Services\Master\RawMaterialService; use App\Support\Media\MediaPresenter; @@ -84,6 +86,27 @@ public function destroy(Request $request, RawMaterial $rawMaterial): RedirectRes return redirect()->route('admin.master.raw_materials.index'); } + public function checkVariantUsage(Request $request): JsonResponse + { + $priceIds = $request->query('price_ids', []); + + if (! is_array($priceIds) || $priceIds === []) { + return response()->json(['in_use' => []]); + } + + $priceIds = array_map('intval', $priceIds); + + $inUse = CuttingMaterial::query() + ->whereIn('raw_material_price_id', $priceIds) + ->whereHas('cutting', fn ($q) => $q->where('status', '!=', CuttingStatus::COMPLETED)) + ->pluck('raw_material_price_id') + ->unique() + ->values() + ->toArray(); + + return response()->json(['in_use' => $inUse]); + } + public function toggleStatus(ToggleStatusRequest $request, RawMaterial $rawMaterial): RedirectResponse { $this->rawMaterialService->toggleStatus($rawMaterial, $request->validated(), $request->user()); diff --git a/app/Services/Master/RawMaterialService.php b/app/Services/Master/RawMaterialService.php index 1e1ee5a..d2dd82e 100644 --- a/app/Services/Master/RawMaterialService.php +++ b/app/Services/Master/RawMaterialService.php @@ -313,6 +313,27 @@ private function ensureNotUsedInActiveCutting(RawMaterial $rawMaterial): void } } + private function ensurePricesNotUsedInActiveCutting(array $priceIds): void + { + $usedPriceIds = CuttingMaterial::query() + ->whereIn('raw_material_price_id', $priceIds) + ->whereHas('cutting', fn ($q) => $q->where('status', '!=', CuttingStatus::COMPLETED)) + ->pluck('raw_material_price_id') + ->unique() + ->toArray(); + + if ($usedPriceIds !== []) { + $variantNames = RawMaterialPrice::whereIn('id', $usedPriceIds) + ->pluck('variant') + ->unique() + ->implode(', '); + + throw ValidationException::withMessages([ + 'prices' => "Variant '{$variantNames}' tidak dapat dihapus karena masih digunakan dalam proses cutting yang belum selesai.", + ]); + } + } + public function applyToggleStatus(OwnerVerificationRequest $verificationRequest): void { $rawMaterial = $verificationRequest->subject; @@ -353,6 +374,15 @@ private function applyPayloadToRawMaterial( ->map(fn ($id) => (int) $id) ->all(); + $deletingPriceIds = $rawMaterial->prices() + ->whereNotIn('id', $submittedPriceIds) + ->pluck('id') + ->toArray(); + + if ($deletingPriceIds !== []) { + $this->ensurePricesNotUsedInActiveCutting($deletingPriceIds); + } + $rawMaterial->prices() ->whereNotIn('id', $submittedPriceIds) ->get() diff --git a/resources/js/pages/admin/master/raw-materials/form/RawMaterialForm.vue b/resources/js/pages/admin/master/raw-materials/form/RawMaterialForm.vue index 4ce8f30..cae8aa7 100644 --- a/resources/js/pages/admin/master/raw-materials/form/RawMaterialForm.vue +++ b/resources/js/pages/admin/master/raw-materials/form/RawMaterialForm.vue @@ -94,7 +94,23 @@ const useSamePrice = ref(prices.value.length <= 1 || allPricesHaveSameValue()); const showDeleteConfirm = ref(false); const priceToDelete = ref(null); -function confirmRemovePrice(clientId: string) { +async function confirmRemovePrice(clientId: string) { + const price = prices.value.find((p) => p.client_id === clientId); + + if (price?.id) { + try { + const res = await fetch(`/admin/master/raw-materials/check-variant-usage?price_ids[]=${price.id}`); + const data: { in_use: number[] } = await res.json(); + + if (data.in_use?.includes(price.id)) { + toast.error(`Varian "${price.variant}" tidak dapat dihapus karena masih digunakan dalam proses cutting yang belum selesai.`); + return; + } + } catch { + // proceed to confirm dialog if check fails + } + } + priceToDelete.value = clientId; showDeleteConfirm.value = true; } @@ -223,6 +239,9 @@ function submit() { if (errors.system) { toast.error(errors.system); } + if (errors.prices) { + toast.error(errors.prices); + } }, }); } diff --git a/routes/web.php b/routes/web.php index e532744..b451408 100644 --- a/routes/web.php +++ b/routes/web.php @@ -146,6 +146,9 @@ Route::prefix('raw-materials')->name('raw_materials.') ->middleware('permission:'.Permission::RAW_MATERIALS_VIEW->value) ->group(function () { + Route::get('check-variant-usage', [RawMaterialController::class, 'checkVariantUsage']) + ->name('check_variant_usage'); + Route::get('create', [RawMaterialController::class, 'create']) ->middleware('permission:'.Permission::RAW_MATERIALS_CREATE->value) ->name('create');