has('products')) { return [ 'warehouse_id' => 'required|exists:warehouses,id', 'notes' => 'nullable|string|max:1000', // Validación del array de productos 'products' => 'required|array|min:1', 'products.*.inventory_id' => 'required|exists:inventories,id', 'products.*.quantity' => 'required|numeric|min:0.001', 'products.*.serial_numbers' => 'nullable|array', 'products.*.serial_numbers.*' => 'required|string|exists:inventory_serials,serial_number', 'products.*.unit_of_measure_id' => 'nullable|exists:units_of_measurement,id', ]; } // Salida única (formato original) return [ 'inventory_id' => 'required|exists:inventories,id', 'warehouse_id' => 'required|exists:warehouses,id', 'quantity' => 'required|numeric|min:0.001', 'notes' => 'nullable|string|max:1000', 'serial_numbers' => 'nullable|array', 'serial_numbers.*' => 'required|string|exists:inventory_serials,serial_number', 'unit_of_measure_id' => 'nullable|exists:units_of_measurement,id', ]; } public function messages(): array { return [ // Mensajes para salida única 'inventory_id.required' => 'El producto es requerido', 'inventory_id.exists' => 'El producto no existe', 'serial_numbers.array' => 'Los números de serie deben ser un arreglo', 'serial_numbers.*.required' => 'El número de serie no puede estar vacío', 'serial_numbers.*.string' => 'El número de serie debe ser texto', 'serial_numbers.*.exists' => 'El número de serie no existe en el sistema', // Mensajes para salida múltiple 'products.required' => 'Debe incluir al menos un producto', 'products.*.inventory_id.required' => 'El producto es requerido', 'products.*.inventory_id.exists' => 'El producto no existe', 'products.*.quantity.required' => 'La cantidad es requerida', 'products.*.quantity.min' => 'La cantidad debe ser al menos 1', 'products.*.serial_numbers.array' => 'Los números de serie deben ser un arreglo', 'products.*.serial_numbers.*.required' => 'El número de serie no puede estar vacío', 'products.*.serial_numbers.*.string' => 'El número de serie debe ser texto', 'products.*.serial_numbers.*.exists' => 'El número de serie no existe en el sistema', // Mensajes comunes 'warehouse_id.required' => 'El almacén es requerido', 'warehouse_id.exists' => 'El almacén no existe', 'quantity.required' => 'La cantidad es requerida', 'quantity.min' => 'La cantidad debe ser al menos 1', ]; } /** * Validación adicional: cantidades decimales solo con unidades que permiten decimales */ public function withValidator($validator) { $validator->after(function ($validator) { $products = $this->has('products') ? $this->products : [[ 'inventory_id' => $this->inventory_id, 'quantity' => $this->quantity, 'serial_numbers' => $this->serial_numbers ?? null, ]]; foreach ($products as $index => $product) { $inventory = Inventory::with('unitOfMeasure')->find($product['inventory_id']); if (! $inventory || ! $inventory->unitOfMeasure) { continue; } $quantity = $product['quantity']; $isDecimal = floor($quantity) != $quantity; // Si la cantidad es decimal pero la unidad no permite decimales if ($isDecimal && ! $inventory->unitOfMeasure->allows_decimals) { $field = $this->has('products') ? "products.{$index}.quantity" : 'quantity'; $validator->errors()->add( $field, "El producto '{$inventory->name}' usa la unidad '{$inventory->unitOfMeasure->name}' que no permite cantidades decimales. Use cantidades enteras." ); } $serialNumbers = $product['serial_numbers'] ?? null; if (! empty($serialNumbers) && $inventory->unitOfMeasure->allows_decimals) { $field = $this->has('products') ? "products.{$index}.serial_numbers" : 'serial_numbers'; $validator->errors()->add( $field, "No se pueden registrar números de serie para el producto '{$inventory->name}' porque usa la unidad '{$inventory->unitOfMeasure->name}' que permite cantidades decimales. Los seriales solo son válidos para unidades discretas como 'Pieza'." ); } } }); } }