Skip to content

Diseño de negocio: inventario, colaboración y offline

Documento migrado desde franmc01/ninaku-core-api.

Estado: propuesta de contratos para el refinamiento. No implementa funcionalidad nueva. El objetivo de producto es crecer desde un restaurante pequeño sin obligarlo a configurar una suite ERP completa.

1. Complejidad progresiva con el mismo modelo

EscenarioExperiencia inicialCapacidad adicional cuando haga falta
Restaurante pequeñoProducto, venta, cobro e impresión desde teléfonoRecetas, lotes, cocina, conteos y compras
Restaurante con varias ubicacionesStock por ubicación y traslados visiblesTránsito, diferencias de recepción, compras centralizadas
RetailVariantes, códigos, stock directo, venta y devoluciónLotes, serialización si el caso lo exige, abastecimiento
Hotel con restauranteUn tenant con capacidades combinadasEstadías/folios propios; cargo de consumo mediante contrato explícito

El usuario puede ver una sola sucursal y una ubicación predeterminada. Internamente el contexto legal, moneda, unidad y propiedad sigue siendo explícito. No exigir al pequeño comercio nómina, contabilidad completa, créditos o lotes si su operación no los requiere. No definir precios, demanda ni promesas comerciales sin validación con clientes.

2. Inventario profesional

Propietarios

Catalog representa lo comercial. Inventory representa el recurso físico y su custodia. Production explica transformaciones. Procurement conserva el compromiso y los documentos de compra. Accounting representa consecuencias económicas. La botella vendida puede tener un enlace directo a stock; una hamburguesa requiere receta/configuración congelada y consumo explicado.

Conservar del baseline items, packages, locations, lots, stock_movements, stock_ledger_entries, reservas, transferencias, conteos y valoración. Antes de añadir tablas, comprobar qué garantía falta en esas estructuras.

Contratos que hay que demostrar

ÁreaReglaEjemplo de aceptación
Identidad físicaUnidad base e incremento explícitos; significado congelado tras primer usoUn borrador persistido impide reinterpretar kg como g; rollback no fabrica historial
ConversionesConversión dimensional y presentación comercial separadasUna caja contiene 12 unidades; factor, precio y cantidad física tienen contratos distintos
LotesCantidad, origen y caducidad trazables cuando aplicaIdentificar qué recepciones abastecieron un consumo
DisponibilidadCantidad utilizable separada de reservada, bloqueada y en tránsitoNo descontar dos veces cuarentena y reservas solapadas; definir conjuntos/estados disjuntos
SaldoFuente histórica y lectura operativa coherentesReconstrucción produce el mismo saldo; admisión concurrente usa estado actualizado bajo bloqueo
ReservasCrear, consumir, liberar y expirar sin perder capacidadDos compradores no reservan la misma última unidad bajo política estricta
TransferenciaDespacho, tránsito, recepción y diferencia separadosDe 4 despachadas, 3 recibidas y 1 pendiente; no crear pérdida hasta resolverla
ConteoPunto de corte y movimientos posteriores definidosContar mientras se vende produce un ajuste explicado, no sobrescribe ventas
ValoraciónMétodo y vigencia separados de movimiento físicoCorrección de costo modifica valor con trazabilidad, no cantidad
ReversosConsecuencias históricas conservadasCorregir un consumo no borra qué ocurrió ni reinterpreta una receta anterior

FEFO para selección por caducidad y FIFO para valoración son conceptos distintos. Definir método de costo por entidad/política antes de publicar movimientos; no escoger un método contable por conveniencia técnica. Consignación, seriales, landed cost y múltiples propietarios de stock son extensiones a justificar con clientes concretos; no afirmar que el baseline ya las cubre.

El bloqueo debe proteger el ámbito que comparte capacidad (producto/ubicación/lote y reservas aplicables). Orden consistente de adquisición, reintentos limitados de la operación completa y clave idempotente. Un saldo de dashboard eventualmente actualizado no autoriza una salida estricta. PostgreSQL documenta que Read Committed no impide por sí solo anomalías de serialización: aislamiento.

3. Conectar negocios sin compartir su verdad

Tres casos distintos

CasoContrato
Dos ubicaciones de la misma entidad legalTransferencia interna con tránsito
Dos entidades legales del mismo tenantHechos de venta/compra y consecuencias por entidad según el proceso aplicable
Dos tenants independientesAcuerdo autorizado de intercambio, documentos locales y mensajes correlacionados

El baseline ya restringe transferencias ordinarias a una entidad legal. No relajarlo para resolver B2B. Una empresa en Party del comprador no es automáticamente el tenant del vendedor, ni un RUC coincidente prueba consentimiento o autoriza vinculación.

Contrato mínimo de colaboración propuesto

  • Acuerdo entre participantes autenticados, aceptación de ambas partes, alcance, vigencia y revocación.
  • Correlación de solicitud/confirmación/expedición; versión del mensaje y clave de entrega.
  • Cada módulo conserva puentes tipados a sus documentos locales; no una tabla universal entity_type/entity_id.
  • Mapeo aceptado entre producto del vendedor y recurso del comprador, presentación/unidad y lote externo si corresponde. No compartir el mismo item_id entre tenants.
  • Snapshot de lo intercambiado; cambios del catálogo del vendedor no alteran la compra aceptada.
  • Bandejas de envío/recepción durables, reintentos, rechazo, mensajes fuera de orden y conciliación visible.
  • Cancelación posterior a despacho produce un proceso compensatorio; no elimina documentos del otro participante.
  • Recepción parcial, faltante, exceso y rechazo registrados por quien recibe. Despacho no confirma recepción.
  • Compartir solo campos consentidos: no revelar margen, costo interno, clientes ni stock completo por defecto.

El intercambio interno usa una autoridad de servicio estrecha y entrega cada mensaje en el contexto autorizado del destinatario; el tenant emisor nunca obtiene capacidad de ejecutar SQL como el receptor. Revocación impide nuevos intercambios pero conserva la evidencia histórica necesaria. No se implementa un proveedor ni un motor B2B en este PR.

4. Offline como contrato de producto

Persistencia local y servidor

SQLite es la propuesta para clientes móviles/escritorio. Un cliente web requiere seleccionar y probar almacenamiento durable compatible; no asumir que el navegador ejecuta el mismo SQLite nativo. Solo se sincroniza el subconjunto autorizado por dispositivo/scope. No replicar los 800 objetos de PostgreSQL ni ejecutar triggers PostgreSQL en el cliente.

Cada operación local conserva command_id, dispositivo, tenant, contrato/versiones, identidad autorizada, datos del comando y estado local de resultado. El cambio local y su cola deben persistirse atómicamente. La hora del cliente sirve como evidencia, no como orden global confiable.

Online y replay convergen en el mismo caso de uso del servidor. Las validaciones locales ayudan a operar; no sustituyen seguridad e invariantes servidor. Versiones de catálogo/precios/receta usadas se conservan para explicar lo sucedido; un cambio posterior puede producir aceptación según política o conciliación, nunca modificación silenciosa del cobro histórico.

Matriz inicial de admisión propuesta

OperaciónOffline propuestoReconciliación/condición
Venta directa y efectivoPermitido con configuración sincronizadaPreservar hecho físico/cobro; discrepancias se resuelven, no se borran
Comanda e impresión localPermitido en dispositivos habilitadosNo reimprimir por replay; resultado incierto requiere decisión explícita
Stock no estrictoPermitido bajo política visibleRegistrar discrepancias/faltantes al reconectar sin alterar hechos
Stock estrictamente limitadoCapacidad asignada previamente o coordinación localNo permitir gasto concurrente del mismo saldo global
Crédito y puntos globalesOnline inicialmente; offline solo con asignación explícitaEvitar que dos terminales gasten el mismo límite/saldo
TarjetaDepende de contrato y hardware del proveedorPendiente no equivale a capturado; no guardar datos sensibles de tarjeta en Ninaku
Recepción físicaRegistro local permitido según autorizaciónVincular a pedido/recepción al reconectar, conservar diferencias
ConteoCaptura localAprobación/ajuste necesita punto de corte y conciliación con movimientos
Transferencia entre ubicaciones aisladasRegistro de cada hecho localNo inferir recepción del despacho; resolver correlación al reconectar
Nueva relación B2B o cambio de permisosOnlineRequiere aceptación y autoridad actual
Emisión fiscalSolo bajo contrato regulatorio/proveedor implementadoNúmero reservado no demuestra autorización fiscal; validar jurisdicción por separado

Capacidad exclusiva

Si quedan 10 unidades, asignar 6 a A y 4 a B consume esa capacidad del pool compartido. Cada uno gasta como máximo su asignación. Una expiración en el servidor no permite reasignar sin saber si el dispositivo desconectado gastó: hace falta cierre/reconciliación o una prueba de revocación efectiva. De lo contrario se recupera capacidad ficticia. El contrato debe incluir reinicio de dispositivo, duplicación de archivos y recuperación de sesión.

No imponer coordinador local a un negocio que opera con un teléfono. Para varios terminales, distinguir internet caído con LAN disponible de partición entre terminales. Un coordinador opcional necesita autoridad/fencing y no puede permitir dos líderes gastar el mismo saldo. Es una etapa posterior, no un requisito del primer cliente.

Sincronización y seguridad

Bootstrap necesita snapshot coherente + cursor compatible; no usar MAX(id), UUIDv7 o la secuencia asignada antes de commit como prueba de orden de publicación. Procesar cambios según posición de publicación estable y estrategia comprobada contra commits fuera de orden. Ack solo después de aplicar durablemente. Retención y expiración del cursor requieren rebootstrap seguro sin perder comandos pendientes.

La identidad offline requiere concesión acotada y almacenamiento protegido. La revocación inmediata no es posible sin comunicación. Distinguir rechazo de nuevas intenciones de revisión de efectivo/mercadería ya entregados. Toda decisión queda atribuida; nunca ampliar scope por haber aceptado un payload local.

La impresión física tiene una ventana entre enviar bytes y persistir confirmación. Un fallo allí puede dejar resultado desconocido: no prometer exactly-once físico. Registrar intentos, confirmaciones y reimpresiones explícitas. La deduplicación de comandos reduce duplicados lógicos, no prueba que el papel salió una sola vez.

5. Referencias de producto y límites de las inferencias

Revisión pública al 2026-09-12, fuentes primarias. Se toman patrones de operación; no se afirma disponibilidad de proveedores en Ecuador, precios, liderazgo de mercado ni paridad de producto.

FuenteEvidencia acotadaInferencia para Ninaku
Odoo: multi-companyLa documentación de la función describe compraventa entre compañías de una baseSeparar intercompany de un traslado ordinario. Consulta mediante resultado indexado; apertura completa no disponible
Odoo: inventory managementDocumenta ubicaciones de tránsito para operaciones entre compañías/almacenesHacer visible mercancía despachada pendiente de recepción. Consulta mediante resultado indexado
Shopify: POS offline featuresDistingue funciones disponibles offline, sincronización posterior, captura de tarjeta y conectividad local de impresorasDefinir una matriz por operación; desacoplar falta de internet de impresión por Bluetooth/LAN
Square: pagos offlineLa función depende de configuración/dispositivo y posterior carga de pagosUn cobro pendiente del proveedor necesita estado explícito; no copiar límites horarios o compatibilidad sin contrato local

Estas referencias no justifican reconstruir un ERP completo. La prioridad comercial propuesta es continuidad de caja e impresión, stock explicable y recepción/traslado sin pérdidas. B2B requiere validar un proveedor y comprador reales antes de generalizar una red comercial. La validación de mercado pendiente debe observar operaciones actuales, costo de errores y disposición a usar/pagar, sin inventar métricas.

Application Foundation in progress. Tracked in issue #13.