Skip to main content

Documentation Index

Fetch the complete documentation index at: https://mintlify.com/Magus-Technologies/facturacion_ilidesava/llms.txt

Use this file to discover all available pages before exploring further.

Descripción General

El módulo de inventario permite gestionar productos con control de stock en múltiples almacenes, seguimiento de movimientos y soporte para diferentes precios y unidades de medida.

Gestión de Productos

Listar Productos

Filtra productos por empresa, almacén y búsqueda de texto.
public function index(Request $request)
{
    try {
        $user = $request->user();
        
        // Obtener empresa activa del header o empresa del usuario
        $idEmpresa = $user->id_empresa;
        if ($request->header('X-Empresa-Activa')) {
            $idEmpresa = $request->header('X-Empresa-Activa');
        }
        
        $productos = $this->productoService->listar(
            $idEmpresa,
            $request->get('almacen', '1'),
            $request->get('search'),
            $request->boolean('solo_con_stock', false)
        );

        return response()->json(['success' => true, 'data' => $productos]);
    } catch (\Exception $e) {
        return response()->json([
            'success' => false,
            'message' => 'Error al obtener productos: ' . $e->getMessage()
        ], 500);
    }
}
Empresa ActivaEl sistema soporta multi-empresa. Se puede especificar la empresa activa mediante:
  • Header HTTP: X-Empresa-Activa: {id_empresa}
  • Por defecto usa $user->id_empresa

Crear Producto

Crea un producto con opción de imagen y sincronización entre almacenes.
public function store(ProductoRequest $request)
{
    try {
        $user = $request->user();
        $data = $request->validated();

        $idEmpresa = $user->id_empresa;
        if ($request->header('X-Empresa-Activa')) {
            $idEmpresa = $request->header('X-Empresa-Activa');
        }

        if ($request->hasFile('imagen')) {
            $data['imagen'] = $this->productoService->subirImagen($request->file('imagen'));
        }

        $producto = $this->productoService->crear($data, $idEmpresa);

        return response()->json([
            'success' => true,
            'message' => 'Producto creado exitosamente en ambos almacenes',
            'data' => $producto,
        ], 201);
    } catch (\Exception $e) {
        return response()->json([
            'success' => false,
            'message' => 'Error al crear producto: ' . $e->getMessage()
        ], 500);
    }
}
Creación en Ambos AlmacenesAl crear un producto, se genera automáticamente en ambos almacenes (virtual y real) con el mismo código para facilitar la sincronización.

Actualizar Producto

public function update(ProductoRequest $request, $id)
{
    try {
        $producto = Producto::findOrFail($id);
        $data = $request->except(['imagen']);

        if ($request->hasFile('imagen')) {
            $data['imagen'] = $this->productoService->subirImagen(
                $request->file('imagen'),
                $producto->imagen
            );
        }

        $resultado = $this->productoService->actualizar($producto, $data);

        return response()->json([
            'success' => true,
            'message' => 'Producto actualizado exitosamente' . ($resultado['sincronizado'] ? ' (sincronizado en ambos almacenes)' : ''),
            'data' => $resultado['producto'],
            'sincronizado' => $resultado['sincronizado'],
        ]);
    } catch (\Exception $e) {
        return response()->json([
            'success' => false,
            'message' => 'Error al actualizar producto: ' . $e->getMessage()
        ], 500);
    }
}

Modelo de Datos

Producto Model

protected $table = 'productos';
protected $primaryKey = 'id_producto';

protected $fillable = [
    'codigo',
    'cod_barra',
    'nombre',
    'descripcion',
    'precio',
    'costo',
    'precio_mayor',
    'precio_menor',
    'precio_unidad',
    'cantidad',
    'stock_minimo',
    'stock_maximo',
    'id_empresa',
    'categoria_id',
    'unidad_id',
    'almacen',
    'codsunat',
    'usar_barra',
    'usar_multiprecio',
    'moneda',
    'estado',
    'imagen',
    'ultima_salida',
    'fecha_ultimo_ingreso',
];

protected $casts = [
    'precio' => 'decimal:2',
    'costo' => 'decimal:2',
    'precio_mayor' => 'decimal:2',
    'precio_menor' => 'decimal:2',
    'precio_unidad' => 'decimal:2',
    'cantidad' => 'integer',
    'stock_minimo' => 'integer',
    'stock_maximo' => 'integer',
    'ultima_salida' => 'date',
    'fecha_ultimo_ingreso' => 'datetime',
];

Relaciones

public function empresa()
{
    return $this->belongsTo(Empresa::class, 'id_empresa', 'id_empresa');
}

public function categoria()
{
    return $this->belongsTo(Categoria::class, 'categoria_id');
}

public function unidad()
{
    return $this->belongsTo(Unidad::class, 'unidad_id');
}

// Scopes
public function scopeAlmacen($query, $almacen)
{
    return $query->where('almacen', $almacen);
}

public function scopeActivo($query)
{
    return $query->where('estado', '1');
}

public function scopeEmpresa($query, $idEmpresa)
{
    return $query->where('id_empresa', $idEmpresa);
}

Sistema de Almacenes

El sistema maneja dos almacenes principales:

Almacén 1 - Virtual

Stock virtual o de exhibiciónUsado para ventas y control interno

Almacén 2 - Real

Stock físico realInventario real en bodega

Movimientos de Stock

Modelo MovimientoStock

protected $table = 'movimientos_stock';
protected $primaryKey = 'id_movimiento';

protected $fillable = [
    'id_producto',
    'tipo_movimiento',
    'cantidad',
    'stock_anterior',
    'stock_nuevo',
    'tipo_documento',
    'id_documento',
    'documento_referencia',
    'motivo',
    'observaciones',
    'id_almacen',
    'id_empresa',
    'id_usuario',
    'fecha_movimiento'
];

protected $casts = [
    'cantidad' => 'decimal:2',
    'stock_anterior' => 'decimal:2',
    'stock_nuevo' => 'decimal:2',
    'fecha_movimiento' => 'datetime',
];

Tipos de Movimiento

Aumenta el stock
  • Compras
  • Ajustes de inventario positivos
  • Devoluciones de clientes
  • Anulación de ventas

Registro Automático de Movimientos

Cada operación que afecta stock genera un movimiento:
if ($afectaStock) {
    $productoModel = Producto::find($producto['id_producto']);
    if ($productoModel) {
        $stockAnterior = $productoModel->cantidad;
        $productoModel->decrement('cantidad', $producto['cantidad']);
        $stockNuevo = $stockAnterior - $producto['cantidad'];

        MovimientoStock::create([
            'id_producto' => $productoModel->id_producto,
            'tipo_movimiento' => 'salida',
            'cantidad' => $producto['cantidad'],
            'stock_anterior' => $stockAnterior,
            'stock_nuevo' => $stockNuevo,
            'tipo_documento' => 'venta',
            'id_documento' => $venta->id_venta,
            'documento_referencia' => $venta->serie . '-' . str_pad($venta->numero, 6, '0', STR_PAD_LEFT),
            'motivo' => 'Venta realizada',
            'id_almacen' => $productoModel->almacen,
            'id_empresa' => $user->id_empresa,
            'id_usuario' => $user->id,
            'fecha_movimiento' => now(),
        ]);
    }
}

Precios Múltiples

Cada producto puede tener diferentes niveles de precio:

Precio Regular

precioPrecio de venta al público

Precio Mayor

precio_mayorPrecio para venta al por mayor

Precio Menor

precio_menorPrecio con descuento o promoción

Precio Unidad

precio_unidadPrecio por unidad individual
Activar usar_multiprecio = true para habilitar la selección de precio en ventas.

Código de Barras

'cod_barra',
'usar_barra',
Si usar_barra = true, el sistema puede buscar productos por código de barras en las ventas.

Categorías y Unidades

Categorías

Permiten organizar productos en grupos:
  • Electrónicos
  • Alimentos
  • Textiles
  • etc.

Unidades de Medida

Basado en catálogo SUNAT:
  • NIU: Unidad
  • KGM: Kilogramo
  • MTR: Metro
  • LTR: Litro
  • etc.

Control de Stock

Stock Mínimo y Máximo

'stock_minimo',
'stock_maximo',
Estos campos permiten:
  • Alertas de stock bajo
  • Control de reabastecimiento
  • Optimización de inventario
El sistema puede configurarse para alertar cuando cantidad < stock_minimo.

Imagen de Producto

Soporte para imágenes de productos:
if ($request->hasFile('imagen')) {
    $data['imagen'] = $this->productoService->subirImagen($request->file('imagen'));
}
Las imágenes deben ser:
  • Formato: JPEG, PNG, JPG, WEBP
  • Tamaño máximo: 2MB

Moneda

Los productos pueden tener precios en:
  • PEN: Soles peruanos
  • USD: Dólares americanos

Código SUNAT

Campo codsunat para el código de producto según catálogo SUNAT (opcional).

Filtros Disponibles

Por Almacén

$request->get('almacen', '1')

Por Búsqueda

Busca en:
  • Código
  • Código de barras
  • Nombre
  • Descripción

Solo con Stock

$request->boolean('solo_con_stock', false)
Filtra productos con cantidad > 0.

Scopes Útiles

public function scopeAlmacen($query, $almacen)
{
    return $query->where('almacen', $almacen);
}

public function scopeActivo($query)
{
    return $query->where('estado', '1');
}

public function scopeEmpresa($query, $idEmpresa)
{
    return $query->where('id_empresa', $idEmpresa);
}

Ejemplo de Uso

// Productos activos del almacén 1
$productos = Producto::activo()
    ->almacen('1')
    ->empresa($idEmpresa)
    ->get();

// Productos con stock
$conStock = Producto::where('cantidad', '>', 0)
    ->activo()
    ->get();

Fechas de Control

Última Salida

ultima_salidaFecha de la última venta del producto

Último Ingreso

fecha_ultimo_ingresoFecha del último ingreso por compra
Estas fechas se actualizan automáticamente en cada movimiento.

Build docs developers (and LLMs) love