value => 'stock', ProductStockQuality::REJECT->value => 'reject_stock', ProductStockQuality::RETAIL->value => 'retail_stock', ]; private function adjustStock(Model $model, string $field, int $quantity, int $sign, ?Model $source = null, ?string $description = null): void { $before = (int) $model->{$field}; if ($sign > 0) { $model->increment($field, $quantity); } else { if ($before < $quantity) { $label = match ($field) { 'stock' => 'stok bagus', 'reject_stock' => 'stok reject', 'retail_stock' => 'stok ecer', default => $field, }; throw ValidationException::withMessages([ 'stock' => "Stok {$label} tidak mencukupi. Tersedia: {$model->{$field}}, dibutuhkan: {$quantity}.", ]); } $model->decrement($field, $quantity); } app(StockMutationService::class)->record( model: $model, type: $sign > 0 ? 'in' : 'out', quantity: $sign * $quantity, stockBefore: $before, stockAfter: $before + ($sign * $quantity), stockQuality: StockMutationService::qualityFromField($field), description: $description ?? 'Perubahan stok', source: $source, ); } private function adjustVariantStock(int $variantId, int $quantity, int $sign, string $stockType, ?Model $source = null, ?string $description = null): void { $field = self::QUALITY_STOCK_MAP[$stockType] ?? 'stock'; $this->adjustStock( model: app(ProductVariant::class)->newQuery()->findOrFail($variantId), field: $field, quantity: $quantity, sign: $sign, source: $source, description: $description, ); } private function applyStock(array $items, string $stockType, int $sign, ?Model $source = null, ?string $description = null): void { DB::transaction(function () use ($items, $stockType, $sign, $source, $description) { foreach ($items as $item) { $this->adjustVariantStock($item['product_variant_id'], $item['quantity'], $sign, $stockType, $source, $description); } }); } }