diff --git a/app/Enums/CuttingStatus.php b/app/Enums/CuttingStatus.php index 36859e9..23a85bd 100644 --- a/app/Enums/CuttingStatus.php +++ b/app/Enums/CuttingStatus.php @@ -33,9 +33,8 @@ public function canTransitionTo(self $status): bool { return match ($this) { self::IN_PROGRESS => $status === self::COMPLETED, - self::COMPLETED => in_array($status, [self::VERIFIED, self::REJECTED], true), - self::REJECTED => $status === self::IN_PROGRESS, - self::VERIFIED => false, + self::COMPLETED => $status === self::VERIFIED, + default => false, }; } @@ -73,22 +72,6 @@ public function availableActions(): array 'permission' => Permission::CUTTINGS_VERIFY->value, 'icon_only' => false, ], - [ - 'status' => self::REJECTED->value, - 'label' => 'Tolak', - 'destructive' => true, - 'permission' => Permission::CUTTINGS_REJECT->value, - 'icon_only' => false, - ], - ], - self::REJECTED => [ - [ - 'status' => self::IN_PROGRESS->value, - 'label' => 'Perbaiki', - 'destructive' => false, - 'permission' => Permission::CUTTINGS_UPDATE->value, - 'icon_only' => false, - ], ], default => [], }; diff --git a/app/Http/Controllers/Admin/Manage/CuttingController.php b/app/Http/Controllers/Admin/Manage/CuttingController.php index f31e9bc..fe745be 100644 --- a/app/Http/Controllers/Admin/Manage/CuttingController.php +++ b/app/Http/Controllers/Admin/Manage/CuttingController.php @@ -94,6 +94,8 @@ public function transitionStatus(CuttingStatusTransitionRequest $request, Cuttin $status, $request->user(), $request->validated('reason'), + $request->validated('verification_note'), + $request->validated('results'), ); $message = match ($status) { diff --git a/app/Http/Requests/Admin/Manage/CuttingStatusTransitionRequest.php b/app/Http/Requests/Admin/Manage/CuttingStatusTransitionRequest.php index d014a35..c0c23db 100644 --- a/app/Http/Requests/Admin/Manage/CuttingStatusTransitionRequest.php +++ b/app/Http/Requests/Admin/Manage/CuttingStatusTransitionRequest.php @@ -29,6 +29,11 @@ public function rules(): array return [ 'status' => ['required', Rule::enum(CuttingStatus::class)], 'reason' => ['nullable', 'string', 'max:500'], + 'verification_note' => ['nullable', 'string', 'max:500'], + 'results' => ['nullable', 'array'], + 'results.*.product_variant_id' => ['required_with:results', 'integer', 'exists:product_variants,id'], + 'results.*.warehouse_stock' => ['required_with:results', 'integer', 'min:0'], + 'results.*.cutting_reject' => ['required_with:results', 'integer', 'min:0'], ]; } @@ -40,6 +45,7 @@ public function attributes(): array return [ 'status' => 'status', 'reason' => 'alasan penolakan', + 'verification_note' => 'catatan verifikasi', ]; } @@ -61,6 +67,25 @@ public function withValidator(Validator $validator): void if ($status === CuttingStatus::REJECTED && trim((string) $this->input('reason')) === '') { $validator->errors()->add('reason', 'Alasan penolakan wajib diisi.'); } + + if ($status === CuttingStatus::VERIFIED && $this->has('results')) { + $cuttingResults = $cutting->results->keyBy('product_variant_id'); + foreach ($this->input('results', []) as $index => $item) { + $variantId = $item['product_variant_id'] ?? 0; + $warehouseStock = (int) ($item['warehouse_stock'] ?? 0); + $cuttingReject = (int) ($item['cutting_reject'] ?? 0); + + $originalResult = $cuttingResults->get($variantId); + if ($originalResult === null) { + $validator->errors()->add("results.{$index}.product_variant_id", "Varian produk tidak ditemukan pada cutting ini."); + continue; + } + + if (($warehouseStock + $cuttingReject) !== (int) $originalResult->cutting_result) { + $validator->errors()->add("results.{$index}.warehouse_stock", "Total jumlah (diterima + reject) harus sama dengan hasil cutting asli ({$originalResult->cutting_result} pcs)."); + } + } + } }); } } diff --git a/app/Services/Manage/CuttingService.php b/app/Services/Manage/CuttingService.php index 82c7f19..d84ce55 100644 --- a/app/Services/Manage/CuttingService.php +++ b/app/Services/Manage/CuttingService.php @@ -296,31 +296,47 @@ public function delete(Cutting $cutting): void }); } - public function transitionStatus(Cutting $cutting, CuttingStatus $status, User $user, ?string $reason = null): void - { + public function transitionStatus( + Cutting $cutting, + CuttingStatus $status, + User $user, + ?string $reason = null, + ?string $verificationNote = null, + ?array $results = null + ): void { if (! $cutting->status->canTransitionTo($status)) { throw ValidationException::withMessages([ 'status' => 'Status proses potong tidak dapat diubah.', ]); } - DB::transaction(function () use ($cutting, $status, $reason, $user): void { + DB::transaction(function () use ($cutting, $status, $reason, $verificationNote, $results, $user): void { $cutting->load(['materials', 'results']); if ($status === CuttingStatus::COMPLETED) { $this->applyRemainingMaterialStock($cutting); + } + + if ($status === CuttingStatus::VERIFIED) { + if ($results !== null) { + foreach ($results as $item) { + $cutting->results() + ->where('product_variant_id', $item['product_variant_id']) + ->update([ + 'warehouse_stock' => $item['warehouse_stock'], + 'cutting_reject' => $item['cutting_reject'], + ]); + } + $cutting->load('results'); + } $this->applyProductStockOnVerify($cutting); - } - if ($status === CuttingStatus::REJECTED) { - $this->reverseMaterialStock($cutting); - $this->reverseProductStock($cutting); - $this->storeRejection($cutting, $reason, $user); - } - - if ($status === CuttingStatus::IN_PROGRESS && $cutting->status === CuttingStatus::REJECTED) { - $this->deductMaterialStock($cutting); - $cutting->rejection()?->delete(); + if ($verificationNote !== null && trim($verificationNote) !== '') { + $cutting->rejection()->create([ + 'reason' => trim($verificationNote), + 'rejected_by_id' => $user->id, + ]); + } } $cutting->status = $status; diff --git a/resources/js/components/admin/manage/cuttings/data-table-actions.vue b/resources/js/components/admin/manage/cuttings/data-table-actions.vue index fb22ad0..0848a00 100644 --- a/resources/js/components/admin/manage/cuttings/data-table-actions.vue +++ b/resources/js/components/admin/manage/cuttings/data-table-actions.vue @@ -1,5 +1,6 @@