📌 Contexto
Imaginate que sos el encargado de logística de la Flota Estelar Imperial. Miles de unidades de equipo —blásters, droides de combate, transmisores, motores hiperimpulsores— vuelven todos los días de misiones de campo. Algunas con raspones de batalla, otras con un par de rayos bláster mal dados, y unas cuantas... bueno, digamos que pasaron por un campo de asteroides sin escudo deflector.
Tu problema no es lo que vuelve roto — eso va directo a reciclaje. El problema es lo que vuelve usado pero funcional. Un cañón láser con la pintura rayada. Un droide protocolo que perdió un dedo pero habla 6 millones de formas de comunicación impecablemente. Un sable de luz de entrenamiento con la empuñadura gastada.
El Almirante (tu jefe) te dijo: "No quiero destruir equipo que todavía sirve. Pero tampoco quiero venderlo al mismo precio que uno nuevo. Necesito un sistema para clasificar cada unidad por su estado físico y aplicar un descuento automático según esa clasificación".
Y acá es donde entrás vos, el héroe de esta historia: el implementador de Odoo.
En este artículo te voy a contar cómo resolvimos este problema para la Flota Estelar (que obviamente no es una empresa real, pero sí representa un caso que vimos mil veces en implementaciones de Odoo). Sin código. Sin módulos imposibles. Desde la trinchera operativa.
¿Para quién es este artículo? Usuarios funcionales de Odoo, jefes de logística, gerentes de operaciones, y cualquier alma valiente que tenga que gestionar productos devueltos, refurbished, segunda selección o "remate" en su inventario.
🎯 El Desafío
La historia de usuario (versión Tatooine)
Como jefe de almacén del Imperio Galáctico, necesito que cada pieza de equipo devuelto tenga una clasificación por su estado físico, con su propio descuento, para que el personal de ventas pueda ofrecerla al precio correcto y el almacén sepa exactamente qué entregar.
— Moff Gideon, Jefe de Logística, Sector Mandalore
Cómo era la vida antes (el lado oscuro)
La Flota Estelar tenía un proceso bastante primitivo:
- Llega una devolución de equipo —un drode astromecánico, por ejemplo— con signos evidentes de haber chocado contra un Destructor Estelar.
- El recepcionista lo inspecciona: "Está usado, pero funciona". Lo mete en la estantería de "usados".
- Semanas después, alguien en ventas lo vende al mismo precio que uno nuevo.
- El cliente se queja: "¡Pagué precio completo por un droide con abolladuras!"
- El equipo de atención al cliente (los pobres oficiales de comunicaciones) tiene que procesar una devolución o un descuento retroactivo.
- Repeat.
El caos era total. No había trazabilidad entre el estado físico del producto y el precio de venta. Cada departamento operaba con su propia lógica: recepción clasificaba como se le ocurría, ventas no sabía qué había en la ubicación de "usados" más que "algo hay", y el almacén entregaba cualquier serial disponible sin distinguir calidad.
El impacto (medible en créditos imperiales)
- 15% de los productos de remate vendidos generaban una queja del cliente.
- 8 horas semanales perdidas entre reclamos y descuentos manuales.
- Productos acumulados en "usados" por hasta 90 días sin venderse porque nadie sabía cómo comercializarlos.
- Pérdida de confianza del cliente: "Compré al Imperio y me mandaron una pieza hecha polvo".
¿Qué probaron y no funcionó?
Opción 1: El precio fijo rebajado
Le pusieron un precio más bajo a todos los productos "usados" sin distinción. El problema: un droide con un rasguño microscópico salía al mismo precio que uno al que le faltaba medio panel solar. Injusto para el cliente, pérdida de ingresos para la Flota.
Opción 2: Variantes de producto por estado
Crearon un producto distinto por cada grado: "Blaster E-11 (Como Nuevo)", "Blaster E-11 (Bueno)", "Blaster E-11 (Aceptable)", etc. Funcionaba... hasta que un mismo blaster pasaba de "Bueno" a "Aceptable" después de una caída. Adivina qué: en Odoo son productos diferentes. No podés cambiarle el grado al mismo serial sin hacer una transformación completa. Y si un cliente preguntaba "¿qué pasó con el blaster número 8472?" no había forma de seguirlo si cambiaba de variante.
Opción 3: Notas en la línea de venta
El vendedor agregaba un texto: "Este producto está usado, 30% descuento por favor". Y después se acordaban de aplicarlo. O no. Dependía de la memoria del oficial de ventas. No hace falta decir que era un desastre.
🔍 Análisis Técnico (pero sin código, prometido)
Cómo viene Odoo de fábrica (la base estelar sin personalizar)
Odoo tiene todo lo básico para manejar productos con tracking por número de serie (stock.lot). Cuando activás tracking por serie en un producto, Odoo te pide el número de serie al recibirlo y al entregarlo. Eso te da trazabilidad: sabés qué serial le vendiste a quién y de dónde vino.
Pero no tiene un campo "grado de condición" en el número de serie. No hay una forma nativa de decir: "este serial es Grado B, aplicale 25% de descuento". Esa relación no existe en Odoo estándar.
Lo que sí tiene:
stock.lot(el modelo de lotes/series): guarda nombre, producto, ubicación, cantidad disponible.sale.order.line: el campodiscountexiste, pero no se llena automáticamente basado en el serial.- Las rutas y reglas de stock pueden determinar de dónde se abastece un producto, pero no a qué precio según esa ubicación.
Módulos involucrados
| Módulo | ¿Qué hace? |
Stock (stock) | Gestiona inventario, ubicaciones, números de serie, movimientos |
Ventas (sale) | Crea y maneja órdenes de venta |
Sale Stock (sale_stock) | El puente entre ventas e inventario: relaciona líneas de venta con pickings |
| Compras / Recepciones | Para procesar el ingreso de devoluciones |
¿Qué se necesita configurar?
Settings necesarios:
- Tracking por Número de Serie activado en los productos que van a remate.
- Entregas parciales habilitadas (por si un cliente compra mezcla de nuevo y remate).
- Múltiples ubicaciones de almacén activadas.
💡 La Solución (al estilo Alianza Rebelde)
Acá viene lo bueno. Después de analizar todas las opciones, diseñamos un sistema que funciona combinando funcionalidades estándar de Odoo con un concepto simple: la ubicación como clasificador de estado.
La idea central (simple pero poderosa)
En lugar de modificar productos o crear módulos raros, usamos ubicaciones de almacén para representar cada grado de condición. Así:
Almacén Imperial Principal/
├── Productos Nuevos (stock fresco de fábrica)
├── Reparaciones / Garantías
├── Remate/
│ ├── Grado A — Como Nuevo (10% descuento)
│ ├── Grado B — Bueno (25% descuento)
│ ├── Grado C — Aceptable (40% descuento)
│ └── Grado D — Remate Total (60% descuento)
└── Reciclaje / Chatarra
Cada ubicación Remate/Grado-X es una ubicación física real (o virtual, según el almacén). Cuando un producto vuelve de una misión, el recepcionista lo clasifica y lo mueve a la ubicación correspondiente. El número de serie no cambia. El producto es el mismo. Solo cambia dónde está.
Cómo funciona en la práctica (el paso a paso)
#### 🔹 Recepción: el momento de la verdad
- Llega una devolución. Un droide R2 con marcas de batalla.
- El recepcionista (un stormtrooper con iniciativa) lo inspecciona:
- Pintura saltada en un 30% → Grado C
- Funciona perfectamente → no va a reciclaje
- Registra el movimiento: del área de recepción a Remate/Grado-C
- Odoo registra el serial en esa nueva ubicación. El serial sigue siendo el mismo.
- Opcional: agrega una nota interna: "R2-D2, perdió panel lateral izquierdo, reemplazado con chapa genérica. Funcional 100%."
#### 🔹 Reclasificación: cuando el estado cambia
Esto es CLAVE. A diferencia de las variantes, acá podés reclasificar:
- Ese mismo R2-D2, después de 3 meses en el estante de Grado C, alguien lo revisa y ve que oxidación afectó un circuito.
- Hacen un movimiento: Remate/Grado-C → Remate/Grado-D (el descuento pasa de 40% a 60%)
- El producto sigue siendo el mismo R2. El serial no cambia. La historia del producto se mantiene intacta.
O al revés: si después de una revisión el droide tiene mejor estado del que se pensaba, pasa de C a B. El sistema lo permite porque el producto no cambia — cambia su ubicación.
#### 🔹 Ventas: el vendedor y el precio
¿Y cómo hace el vendedor para saber que este droide va con descuento? Acá entra el truco de la lista de precios por categoría:
- Creás categorías de producto: "Remate-A", "Remate-B", "Remate-C", "Remate-D"
- Asignás los productos de remate a su categoría correspondiente
- Configurás una lista de precios para clientes de remate con reglas por categoría
Ejemplo de reglas de lista de precios:
| Categoría | % Descuento sobre precio base |
| Remate-A | -10% |
| Remate-B | -25% |
| Remate-C | -40% |
| Remate-D | -60% |
Cuando un vendedor elige la lista de precios "Remate" para el cliente, Odoo calcula automáticamente el descuento según la categoría del producto. El vendedor no necesita acordarse de aplicar ningún descuento — el sistema lo hace por él.
#### 🔹 Almacén: el picking y la entrega
La magia operativa: cuando se confirma la orden de venta:
- La línea de venta tiene: Producto: Droide R2-D2 / Cantidad: 1 / Precio: con descuento Grado C
- Odoo crea un picking de entrega con origen: Remate/Grado-C
- El almacenista abre el picking y ve: "Entregar 1x Droide R2-D2 desde Remate/Grado-C"
- Al confirmar el movimiento, Odoo le pide escanear/escribir el número de serie
- El sistema solo muestra los seriales disponibles en Remate/Grado-C
- El almacenista agarra cualquier R2-D2 de esa ubicación — todos son Grado C, todos tienen el descuento correcto
El vendedor nunca eligió un serial específico. Eligió un grado. Y el almacén se aseguró de entregar el producto correcto.
#### 🔹 Devolución post-venta: el círculo virtuoso
Si el cliente devuelve el producto porque "pensé que era Grado B y es Grado C", el proceso es sencillo:
- Se recibe la devolución
- Se inspecciona de nuevo
- Se reclasifica a Grado B (movimiento a Remate/Grado-B)
- Se revende con el nuevo descuento
Sin duplicar productos. Sin crear seriales nuevos. Sin perder trazabilidad.
Cuadro comparativo de opciones (para tu jefe)
| Opción | ¿Forza el serial? | ¿Reclasificación posible? | ¿Descuento automático? | ¿Requiere código? |
| Precio fijo general | ❌ | ❌ | ❌ | ❌ |
| Variantes por grado | ✅ | ❌ | ✅ | ❌ |
| Notas en línea | ❌ | ❌ | ❌ | ❌ |
| Ubicaciones + categorías | ✅ | ✅ | ✅ | ❌ |
Custom condition_grade en stock.lot | ✅ | ✅ | ✅ | ✅ (mínimo) |
La respuesta a la gran pregunta de Ángel
Recordás la pregunta clave: "El vendedor, ¿cómo sabe qué precio poner a cada grado y el almacén cómo sabe qué entregar?"
La respuesta:
- El vendedor no selecciona seriales. Selecciona el producto (que está en la categoría Remate-Grado-C). El precio se calcula automáticamente por la lista de precios vinculada a la categoría. Listo. No tiene que pensar en ubicaciones ni en nada raro.
- El almacén recibe un picking con origen específico:
Remate/Grado-C. Al confirmar, Odoo le pide escanear un número de serie que esté en esa ubicación. Cualquier serial que esté ahí es correcto porque todos fueron clasificados como Grado C.
- El sistema asegura integridad: si no hay seriales disponibles en
Remate/Grado-C, Odoo no permite confirmar la entrega. Punto.
Configuración completa (lo que tenés que hacer en Odoo)
Paso 1: Ubicaciones
- Ir a Inventario → Configuración → Ubicaciones de almacén
- Crear la ubicación padre:
WH/Remate - Crear ubicaciones hijas:
Grado-A,Grado-B,Grado-C,Grado-D
Paso 2: Categorías de producto
- Ir a Ventas → Configuración → Categorías de producto
- Crear categorías:
Remate-A,Remate-B,Remate-C,Remate-D - Configurar categorías hijas de una categoría padre "Remate" para mantener el árbol organizado
Paso 3: Lista de precios
- Ir a Ventas → Configuración → Listas de precios
- Crear una lista "Remate / Segunda selección"
- Agregar reglas por categoría con los porcentajes de descuento correspondientes
Paso 4: Productos
- Para cada producto que vaya a remate, asegurarse de que tenga tracking por Número de Serie activado
- Cuando recibas una devolución con cierto grado, asignar la categoría correspondiente (opcional: podés dejar el producto en la categoría original y usar la ubicación como clasificador — la categoría es para el precio, la ubicación es para la operativa)
Paso 5: Flujo de recepción
- Recibir el producto como devolución (picking de retorno)
- Moverlo a la ubicación
WH/Remate/Grado-Xmediante un movimiento de stock interno - El serial queda asociado a esa ubicación
Paso 6: Venta
- Crear orden de venta para el cliente
- Seleccionar la lista de precios "Remate"
- Agregar el producto → el precio se calcula solo
- Confirmar → se crea picking con origen
WH/Remate/Grado-X - Entregar → Odoo pide serial → solo muestra los de esa ubicación
Verificación funcional
- [ ] Recibir una devolución, clasificarla como Grado C y moverla a la ubicación correcta
- [ ] Crear una venta con lista de precios "Remate" → el precio refleja el descuento
- [ ] Confirmar la venta → el picking se crea con origen
WH/Remate/Grado-C - [ ] Entregar → solo se ven los seriales de Grado C disponibles
- [ ] Reclasificar un serial de Grado C a Grado D → movimiento entre ubicaciones → la venta futura lo refleja
✅ Resultados y Beneficios
Mejoras funcionales (el antes y después)
| Antes (Lado Oscuro) | Después (Alianza Rebelde) |
| Productos usados sin clasificar en una pila genérica | Cada producto clasificado con su grado, en su ubicación |
| Vendedor no sabía qué descuento aplicar | El precio se calcula automáticamente |
| Almacén entregaba cualquier serial | El picking fuerza la ubicación correcta |
| Reclasificar era imposible (variantes) | Solo mover de ubicación — el serial sigue siendo el mismo |
| 15% de quejas post-venta | Cero quejas por precio incorrecto |
| 8 horas semanales perdidas en reclamos | Tiempo liberado para tareas productivas |
Beneficios por rol
| Rol | Qué gana |
| Recepcionista | Clasifica una vez y el sistema se encarga del resto. No más etiquetas adhesivas con "usado" |
| Vendedor | Ve el precio automático. No tiene que calcula descuentos ni explicar por qué algo es más barato |
| Almacén | Sabe exactamente de dónde sacar cada producto. Los pickings le dicen la ubicación exacta |
| Gerencia | Trazabilidad total. Saben cuánto hay en cada grado, qué se vende más, cuánto descuento se aplicó realmente |
| Cliente | Paga el precio justo por el estado del producto. Sin sorpresas |
Lecciones aprendidas (de la trinchera)
- La ubicación como clasificador es más flexible de lo que parece. Cuando entendés que una ubicación en Odoo puede tener semántica de negocio (no solo coordenadas físicas), se abren muchas puertas.
- Las variantes no son para estados transitorios. Si el estado de un producto puede cambiar a lo largo de su vida útil, no usés variantes. Son para atributos permanentes (talle, color, material).
- La clasificación no es un paso burocrático — es el momento de creación de valor. Un producto bien clasificado se vende más rápido y mejor. Un producto mal clasificado genera costos ocultos (reclamos, devoluciones, retrabajo).
- La trazabilidad del número de serie es sagrada. Nunca sacrificar la capacidad de rastrear un serial por simplicidad operativa. Cuando un cliente pregunta "¿qué pasó con este equipo?" la respuesta debe ser inmediata.
Extensiones futuras (para el siguiente episodio de la saga)
- Dashboard de remates: Un tablero Kanban que muestre los productos por grado, con foto del estado físico y días en stock.
- Alertas por tiempo en remate: Si un Grado A lleva más de 60 días sin venderse, sugerir reclasificación o liquidación.
- Workflow de aprobación: Para reclasificaciones de grado inferior (más descuento), que requiera autorización de gerencia.
- Integración con e-commerce: Publicar productos de remate en un sitio web con los descuentos ya aplicados y el stock real disponible.
📚 Para Profundizar
- Documentación oficial: Números de serie y lotes en Odoo — La base de todo lo que vimos acá. En la documentación de Inventario de Odoo.
- Ubicaciones de almacén: guía completa — Odoo tiene un sistema de ubicaciones mucho más potente de lo que parece a simple vista. Vale la pena explorarlo.
- Listas de precios avanzadas — Reglas por categoría, por producto, por cantidad, por cliente. El motor de precios de Odoo es sorprendentemente flexible.
- Foro de Odoo: Refurbished products management — Hay discusiones activas en la comunidad sobre este tema. Siempre aparece alguien con el mismo problema.
💬 ¿Tu experiencia es diferente?
En el Imperio Galáctico resolvimos este desafío con ubicaciones y categorías. ¿Vos lo encaraste de otra forma? ¿Usaste algún módulo de la OCA? ¿O terminaste escribiendo código custom como el Halcón Milenario después de innumerables reparaciones?
Contanos en los comentarios — en la galaxia de Odoo hay más de una forma de resolver un problema, y todas suman.
Este artículo es una colaboración entre el equipo de implementación de la Flota Estelar y el Escuadrón de Consultores de la Alianza Rebelde. Los nombres de personajes y situaciones son ficticios. Cualquier parecido con implementaciones reales es porque... bueno, este problema aparece en todas partes.