TunoCommerce

Comercio

Clientes, cotizaciones (RFQ), roles de compradores y direcciones

El módulo de comercio gestiona toda la relación con los compradores: desde el registro y autenticación de clientes, hasta un sistema completo de cotizaciones (RFQ) con negociación bidireccional, roles y permisos granulares, y gestión de direcciones.

Clientes (Customers)

Los clientes son los usuarios compradores que interactúan con la plataforma a través del portal de comprador o la API.

Gestión de clientes

  • CRUD completo: Crear, listar, ver, actualizar y eliminar (soft delete) con restauración.
  • Campos: Nombre, apellido, email (único global), teléfono, idioma (es-MX o en-US).
  • Estados: pendingactivesuspended / inactive. Solo clientes activos pueden autenticarse.
  • Auditoría: Todas las operaciones quedan registradas.

Autenticación

Sistema de autenticación seguro con tokens JWT y sesiones con refresh token:

OperaciónDescripción
ChallengeGenera un par de claves RSA-2048 (válido 2 minutos) para encriptar credenciales
Sign InAutenticación con email + contraseña (encriptada o legacy). Devuelve access token (15 min) + refresh token (30 días)
RefreshRenueva tokens con rotación automática (el refresh token anterior se invalida)
LogoutRevoca la sesión actual

Seguridad:

  • Refresh tokens almacenados como hash SHA-256 (nunca en texto plano).
  • Máximo 10 sesiones activas por cliente; al exceder, se revoca la más antigua.
  • Registro de IP y dispositivo por sesión.

Roles y permisos

Sistema de RBAC independiente para compradores, separado del sistema de permisos del staff administrativo.

4 roles predefinidos:

RolCapacidades
AdminAcceso total: cotizaciones, direcciones, catálogo
AprobadorVer y aprobar/rechazar cotizaciones, negociar
CompradorCrear y enviar cotizaciones, negociar, cancelar
VisorSolo lectura en cotizaciones, direcciones y catálogo

11 permisos granulares organizados en tres categorías:

  • Cotizaciones (7): ver, crear, enviar, aprobar, rechazar, negociar, cancelar.
  • Direcciones (4): ver, crear, editar, eliminar.
  • Catálogo (1): navegar productos.

Los roles y permisos son configurables por empresa desde el dashboard administrativo.


Cotizaciones (Quotes / RFQ)

Sistema completo de solicitud de cotización (Request for Quote) con soporte para negociación iterativa entre vendedor y comprador.

Flujo de estados

                    ┌─────────────────────────────────────────────────────────┐
                    │               VENDEDOR responde                         │
                    ▼                                                         │
draft ──► submitted ──► negotiating ──────────────────────────────────────── ┘
               │              │
               │              └──► cancelled / expired

               ├──► approved ──► converted
               ├──► partially_approved ──► converted
               ├──► declined  (vendedor rechaza → comprador puede reenviar)
               ├──► rejected  (comprador rechaza la propuesta del vendedor)
               ├──► expired
               └──► cancelled

Estados terminales: approved, partially_approved, declined, rejected, expired, cancelled (salvo que el comprador reenvíe tras declined).

Las cotizaciones soportan múltiples rondas de negociación con límites configurables por empresa.

Campo awaitingResponseFrom

Todas las cotizaciones exponen el campo awaitingResponseFrom ("buyer" | "seller" | null) que indica explícitamente de quién se espera la siguiente acción, sin necesidad de inferirlo del estado.

Vista vendedor (staff)

El equipo de ventas gestiona cotizaciones desde el dashboard con las siguientes operaciones:

  • Crear cotización para un cliente, con ítems, notas y fecha de expiración.
  • Responder con precios actualizados, datos financieros (subtotal, descuento, envío, impuesto, total) y notas del vendedor. También se usa para responder a contarofertas del comprador.
  • Aprobar cotizaciones (transición a approved).
  • Rechazar cotizaciones (endpoint /reject, transición a declined).
  • Cancelar cotizaciones.
  • Gestionar ítems: Agregar, actualizar o eliminar líneas de producto.
  • Descargar PDF de la cotización.

Validación financiera: Al responder, el sistema valida que total = subtotal - descuento + envío + impuesto con precisión de centavos.

Permisos requeridos (staff RBAC):

PermisoAcciones que cubre
quotes.viewListar y ver cotizaciones
quotes.createCrear cotizaciones y agregar ítems
quotes.updateEditar cotizaciones e ítems existentes
quotes.resolveResponder, aprobar y rechazar (declined)
quotes.cancelCancelar cotizaciones
quotes.deleteEliminar (soft delete) cotizaciones

Vista comprador (buyer portal)

Los compradores interactúan con cotizaciones a través de la API del portal:

  • Crear y enviar solicitudes de cotización con productos del catálogo.
  • Negociar: Proponer precios y cantidades alternativos con mensaje al vendedor.
  • Aprobar (total o parcial): Aceptar todos los ítems o seleccionar cuáles aceptar/rechazar.
  • Rechazar la propuesta del vendedor con motivo.
  • Reenviar cotizaciones rechazadas (con límite configurable de reenvíos).
  • Cancelar en cualquier momento.

Ítems de cotización

Cada línea de una cotización captura un snapshot del producto al momento de la creación:

  • Producto, variante (opcional), SKU, nombre, imagen, opciones seleccionadas.
  • Precio unitario (unitPrice), cantidad y notas.
  • Campos de negociación: proposedPrice y proposedQuantity — valores propuestos por el comprador en una contraoferta. Son null hasta que el comprador negocia.
  • Estado por ítem: pending, accepted, rejected — para aprobación parcial. Solo el comprador puede hacer aprobación parcial seleccionando qué ítems acepta.

Contadores de seguimiento

CampoQuién lo incrementaPropósito
negotiationRoundVendedor (al responder)Cuenta las rondas de negociación; bloquea nuevas contarofertas al alcanzar el límite
revisionCountComprador (al reenviar tras declined)Cuenta los reenvíos; bloquea nuevos reenvíos al alcanzar el límite

Estos contadores son independientes y tienen límites separados configurables por empresa.

Configuración por empresa

ParámetroClave de configuraciónDefault
Días de expiración de cotizacionesquotes.expirationDays30
Máximo rondas de negociaciónquotes.maxNegotiationRounds10
Máximo reenvíos tras rechazoquotes.maxResubmissions3
Términos y condiciones en PDFpdf_terms_and_conditions

Las claves se configuran desde el dashboard administrativo en la sección de configuración de empresa (CompanyConfig).

Generación de PDF

Las cotizaciones en estado submitted, negotiating, approved, partially_approved o converted pueden descargarse en PDF desde el endpoint GET /v1/quotes/{id}/pdf. El PDF incluye los datos de la cotización, ítems, totales financieros y el texto de términos y condiciones configurado en pdf_terms_and_conditions.

Mensajes

Cada cotización tiene un historial de mensajes entre vendedor y comprador, con tipo de autor (buyer / seller), texto y timestamp.

Expiración automática

Un trabajo en segundo plano (ExpireQuotesTask) revisa periódicamente las cotizaciones con fecha de expiración vencida y las transiciona automáticamente a estado expired.


Direcciones

Direcciones de empresa

Gestión de direcciones de envío y facturación por empresa:

  • Campos: Etiqueta, contacto (nombre, teléfono), dirección completa (calle, número, línea 2, ciudad, estado, país, código postal).
  • Tipos: Cada dirección puede ser de envío, facturación o ambas.
  • Defaults automáticos: La primera dirección de cada tipo se establece como predeterminada. Al cambiar el default, el anterior se desactiva automáticamente en una transacción.
  • Vinculación: Las cotizaciones pueden referenciar una dirección de envío (shippingAddressId) y una dirección de facturación (billingAddressId). Solo el staff puede asignar la dirección de facturación; los compradores solo pueden establecer la dirección de envío.

Direcciones del comprador

Los compradores acceden a las mismas direcciones de su empresa a través de la API del portal, con permisos controlados por su rol:

  • Listar, crear, ver, actualizar y eliminar direcciones de su empresa.
  • El acceso está limitado estrictamente a la empresa del comprador autenticado.

On this page