fix: permisos de usuario
This commit is contained in:
parent
eaad8a57df
commit
2c8189ca59
@ -90,6 +90,7 @@ public function import(InventoryImportRequest $request)
|
|||||||
return ApiResponse::OK->response([
|
return ApiResponse::OK->response([
|
||||||
'message' => 'Importación completada exitosamente.',
|
'message' => 'Importación completada exitosamente.',
|
||||||
'imported' => $stats['imported'],
|
'imported' => $stats['imported'],
|
||||||
|
'updated' => $stats['updated'],
|
||||||
'skipped' => $stats['skipped'],
|
'skipped' => $stats['skipped'],
|
||||||
'errors' => $stats['errors'],
|
'errors' => $stats['errors'],
|
||||||
]);
|
]);
|
||||||
|
|||||||
@ -44,13 +44,15 @@ public function messages(): array
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Reglas de validación para cada fila del Excel
|
* Reglas de validación para cada fila del Excel
|
||||||
|
* Nota: SKU y código de barras no tienen 'unique' porque se permite reimportar
|
||||||
|
* para agregar stock/seriales a productos existentes
|
||||||
*/
|
*/
|
||||||
public static function rowRules(): array
|
public static function rowRules(): array
|
||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'nombre' => ['required', 'string', 'max:100'],
|
'nombre' => ['required', 'string', 'max:100'],
|
||||||
'sku' => ['nullable', 'string', 'max:50', 'unique:inventories,sku'],
|
'sku' => ['nullable', 'string', 'max:50'],
|
||||||
'codigo_barras' => ['nullable', 'string', 'max:100', 'unique:inventories,barcode'],
|
'codigo_barras' => ['nullable', 'string', 'max:100'],
|
||||||
'categoria' => ['nullable', 'string', 'max:100'],
|
'categoria' => ['nullable', 'string', 'max:100'],
|
||||||
'stock' => ['required', 'integer', 'min:0'],
|
'stock' => ['required', 'integer', 'min:0'],
|
||||||
'costo' => ['required', 'numeric', 'min:0'],
|
'costo' => ['required', 'numeric', 'min:0'],
|
||||||
@ -67,9 +69,7 @@ public static function rowMessages(): array
|
|||||||
return [
|
return [
|
||||||
'nombre.required' => 'El nombre del producto es requerido.',
|
'nombre.required' => 'El nombre del producto es requerido.',
|
||||||
'nombre.max' => 'El nombre no debe exceder los 100 caracteres.',
|
'nombre.max' => 'El nombre no debe exceder los 100 caracteres.',
|
||||||
'sku.unique' => 'El SKU ya existe en el sistema.',
|
|
||||||
'sku.max' => 'El SKU no debe exceder los 50 caracteres.',
|
'sku.max' => 'El SKU no debe exceder los 50 caracteres.',
|
||||||
'codigo_barras.unique' => 'El código de barras ya existe en el sistema.',
|
|
||||||
'stock.required' => 'El stock es requerido.',
|
'stock.required' => 'El stock es requerido.',
|
||||||
'stock.integer' => 'El stock debe ser un número entero.',
|
'stock.integer' => 'El stock debe ser un número entero.',
|
||||||
'stock.min' => 'El stock no puede ser negativo.',
|
'stock.min' => 'El stock no puede ser negativo.',
|
||||||
|
|||||||
@ -33,6 +33,7 @@ class ProductsImport implements ToModel, WithHeadingRow, WithValidation, WithChu
|
|||||||
|
|
||||||
private $errors = [];
|
private $errors = [];
|
||||||
private $imported = 0;
|
private $imported = 0;
|
||||||
|
private $updated = 0;
|
||||||
private $skipped = 0;
|
private $skipped = 0;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@ -64,7 +65,21 @@ public function model(array $row)
|
|||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
// Validar que el precio de venta sea mayor que el costo
|
// Buscar producto existente por SKU o código de barras
|
||||||
|
$existingInventory = null;
|
||||||
|
if (!empty($row['sku'])) {
|
||||||
|
$existingInventory = Inventory::where('sku', trim($row['sku']))->first();
|
||||||
|
}
|
||||||
|
if (!$existingInventory && !empty($row['codigo_barras'])) {
|
||||||
|
$existingInventory = Inventory::where('barcode', trim($row['codigo_barras']))->first();
|
||||||
|
}
|
||||||
|
|
||||||
|
// Si el producto ya existe, solo agregar stock y seriales
|
||||||
|
if ($existingInventory) {
|
||||||
|
return $this->updateExistingProduct($existingInventory, $row);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Producto nuevo: validar precios
|
||||||
$costo = (float) $row['costo'];
|
$costo = (float) $row['costo'];
|
||||||
$precioVenta = (float) $row['precio_venta'];
|
$precioVenta = (float) $row['precio_venta'];
|
||||||
|
|
||||||
@ -90,7 +105,7 @@ public function model(array $row)
|
|||||||
$inventory->sku = !empty($row['sku']) ? trim($row['sku']) : null;
|
$inventory->sku = !empty($row['sku']) ? trim($row['sku']) : null;
|
||||||
$inventory->barcode = !empty($row['codigo_barras']) ? trim($row['codigo_barras']) : null;
|
$inventory->barcode = !empty($row['codigo_barras']) ? trim($row['codigo_barras']) : null;
|
||||||
$inventory->category_id = $categoryId;
|
$inventory->category_id = $categoryId;
|
||||||
$inventory->stock = 0; // Se calculará automáticamente
|
$inventory->stock = 0;
|
||||||
$inventory->is_active = true;
|
$inventory->is_active = true;
|
||||||
$inventory->save();
|
$inventory->save();
|
||||||
|
|
||||||
@ -103,28 +118,7 @@ public function model(array $row)
|
|||||||
]);
|
]);
|
||||||
|
|
||||||
// Crear números de serie si se proporcionan
|
// Crear números de serie si se proporcionan
|
||||||
if (!empty($row['numeros_serie'])) {
|
$this->addSerials($inventory, $row['numeros_serie'] ?? null, $row['stock'] ?? 0);
|
||||||
$serials = explode(',', $row['numeros_serie']);
|
|
||||||
|
|
||||||
foreach ($serials as $serial) {
|
|
||||||
$serial = trim($serial);
|
|
||||||
|
|
||||||
if (!empty($serial)) {
|
|
||||||
InventorySerial::create([
|
|
||||||
'inventory_id' => $inventory->id,
|
|
||||||
'serial_number' => $serial,
|
|
||||||
'status' => 'disponible',
|
|
||||||
]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
// Sincronizar stock basado en los seriales
|
|
||||||
$inventory->syncStock();
|
|
||||||
} else {
|
|
||||||
// Si no se proporcionan seriales, es un producto no serializado.
|
|
||||||
// Asignar el stock directamente desde la columna 'stock'.
|
|
||||||
$inventory->stock = (int) ($row['stock'] ?? 0);
|
|
||||||
$inventory->save();
|
|
||||||
}
|
|
||||||
|
|
||||||
$this->imported++;
|
$this->imported++;
|
||||||
|
|
||||||
@ -136,6 +130,80 @@ public function model(array $row)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Actualiza un producto existente: suma stock y agrega seriales nuevos
|
||||||
|
*/
|
||||||
|
private function updateExistingProduct(Inventory $inventory, array $row)
|
||||||
|
{
|
||||||
|
$serialsAdded = 0;
|
||||||
|
$serialsSkipped = 0;
|
||||||
|
|
||||||
|
// Agregar seriales nuevos (ignorar duplicados)
|
||||||
|
if (!empty($row['numeros_serie'])) {
|
||||||
|
$serials = explode(',', $row['numeros_serie']);
|
||||||
|
|
||||||
|
foreach ($serials as $serial) {
|
||||||
|
$serial = trim($serial);
|
||||||
|
if (empty($serial)) continue;
|
||||||
|
|
||||||
|
// Verificar si el serial ya existe (global, no solo en este producto)
|
||||||
|
$exists = InventorySerial::where('serial_number', $serial)->exists();
|
||||||
|
|
||||||
|
if (!$exists) {
|
||||||
|
InventorySerial::create([
|
||||||
|
'inventory_id' => $inventory->id,
|
||||||
|
'serial_number' => $serial,
|
||||||
|
'status' => 'disponible',
|
||||||
|
]);
|
||||||
|
$serialsAdded++;
|
||||||
|
} else {
|
||||||
|
$serialsSkipped++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Sincronizar stock basado en seriales disponibles
|
||||||
|
$inventory->syncStock();
|
||||||
|
} else {
|
||||||
|
// Producto sin seriales: sumar stock
|
||||||
|
$stockToAdd = (int) ($row['stock'] ?? 0);
|
||||||
|
$inventory->increment('stock', $stockToAdd);
|
||||||
|
}
|
||||||
|
|
||||||
|
$this->updated++;
|
||||||
|
|
||||||
|
if ($serialsSkipped > 0) {
|
||||||
|
$this->errors[] = "Producto '{$inventory->name}': {$serialsSkipped} seriales ya existían y fueron ignorados";
|
||||||
|
}
|
||||||
|
|
||||||
|
return null; // No retornar modelo para evitar que Maatwebsite intente guardarlo
|
||||||
|
}
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Agrega seriales a un producto nuevo
|
||||||
|
*/
|
||||||
|
private function addSerials(Inventory $inventory, ?string $serialsString, int $stockFromExcel)
|
||||||
|
{
|
||||||
|
if (!empty($serialsString)) {
|
||||||
|
$serials = explode(',', $serialsString);
|
||||||
|
|
||||||
|
foreach ($serials as $serial) {
|
||||||
|
$serial = trim($serial);
|
||||||
|
if (!empty($serial)) {
|
||||||
|
InventorySerial::create([
|
||||||
|
'inventory_id' => $inventory->id,
|
||||||
|
'serial_number' => $serial,
|
||||||
|
'status' => 'disponible',
|
||||||
|
]);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
$inventory->syncStock();
|
||||||
|
} else {
|
||||||
|
// Producto sin seriales
|
||||||
|
$inventory->stock = $stockFromExcel;
|
||||||
|
$inventory->save();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Reglas de validación para cada fila
|
* Reglas de validación para cada fila
|
||||||
*/
|
*/
|
||||||
@ -167,6 +235,7 @@ public function getStats(): array
|
|||||||
{
|
{
|
||||||
return [
|
return [
|
||||||
'imported' => $this->imported,
|
'imported' => $this->imported,
|
||||||
|
'updated' => $this->updated,
|
||||||
'skipped' => $this->skipped,
|
'skipped' => $this->skipped,
|
||||||
'errors' => $this->errors,
|
'errors' => $this->errors,
|
||||||
];
|
];
|
||||||
|
|||||||
@ -166,6 +166,7 @@ public function run(): void
|
|||||||
$salesCreate,
|
$salesCreate,
|
||||||
$salesCancel,
|
$salesCancel,
|
||||||
$inventoryIndex,
|
$inventoryIndex,
|
||||||
|
$inventoryImport,
|
||||||
$inventoryCreate,
|
$inventoryCreate,
|
||||||
$inventoryEdit,
|
$inventoryEdit,
|
||||||
$inventoryDestroy,
|
$inventoryDestroy,
|
||||||
@ -190,8 +191,11 @@ public function run(): void
|
|||||||
$salesIndex, // Ver historial de ventas
|
$salesIndex, // Ver historial de ventas
|
||||||
$salesCreate, // Crear ventas
|
$salesCreate, // Crear ventas
|
||||||
// Inventario (solo lectura)
|
// Inventario (solo lectura)
|
||||||
$inventoryIndex, // Listar productos
|
$inventoryIndex,
|
||||||
$inventoryImport, // Importar productos
|
$inventoryImport, // Importar productos
|
||||||
|
$inventoryCreate,
|
||||||
|
$inventoryEdit,
|
||||||
|
$inventoryDestroy,
|
||||||
// Clientes
|
// Clientes
|
||||||
$clientIndex, // Buscar clientes
|
$clientIndex, // Buscar clientes
|
||||||
);
|
);
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user