Saltar a contenido

Compulandia CRM · Gestión de Oportunidades de Venta

Documento de contexto y análisis · v0.3

Propósito: captura del estado del análisis desarrollado hasta la fecha. Usar como punto de partida para continuar la iteración desde cualquier entorno. Última actualización: febrero 2026.


Índice

  1. Problema y propuesta
  2. Actores del sistema
  3. Entidades SAP involucradas
  4. Módulo de comentarios Firebase
  5. Flujo operativo — Ciclo completo
  6. Quotation draft con líneas de texto
  7. Flujo de la Activity
  8. Timeline unificado
  9. Reglas operativas
  10. Meta-plan de documentación
  11. Prompts UI generados
  12. Puntos abiertos

1. Problema y propuesta

Situación actual

  • La comunicación vendedor↔comprador vive en Notion (chat con imágenes)
  • Los documentos formales viven en SAP B1
  • No hay trazabilidad entre ambos
  • El módulo de comentarios Firebase existe pero solo se usa en Activities
  • El vendedor arma cotizaciones con precios no validados formalmente

Solución propuesta — tres niveles

Nivel 1 — Flujo operativo Proceso guiado que ancla cada conversación al documento SAP correcto. No reemplaza herramientas — modela el proceso sobre las entidades existentes.

Nivel 2 — Entidades SAP SalesOpportunities (OOPR) como nodo central. Todos los documentos generados durante el ciclo vinculados mediante SalesOpportunityLines.

Nivel 3 — Arquitectura de implementación Backend NestJS orquesta SAP Service Layer + Firebase. El módulo de comentarios Firebase se extiende a OQUT y ORDR sin refactorizar.

Principio rector

No reemplazar herramientas. Modelar el proceso. SAP tiene las entidades correctas. Firebase tiene la infraestructura de comunicación. Lo que falta es el flujo explícito que guíe a vendedor y comprador a operar sobre las entidades correctas, en el orden correcto, con las conversaciones ancladas a los documentos correspondientes.


2. Actores del sistema

Código Actor Rol en el flujo
VEND Vendedor Gestiona la oportunidad de inicio a fin. Genera cotizaciones. Interlocutor con el cliente.
COMP Compras Interviene cuando el producto cotizado es nuevo y no existe en SAP. Crea el ítem y habilita el Quotation formal post-aceptación.
CLI Cliente (externo) Recibe cotizaciones, negocia, decide. Opera vía comentarios en el hilo del Quotation.
GER Gerencia Consulta pipeline y forecast. No opera en el ciclo salvo aprobaciones de excepción.

3. Entidades SAP involucradas

Mapa de entidades

SalesOpportunity (OOPR)
    │
    ├── SalesOpportunityLines[]
    │       ├── LineNum
    │       ├── StageKey → SalesStages
    │       ├── PercentageRate
    │       ├── DocumentType  (bodt_Quotation / bodt_Order / bodt_MinusOne)
    │       └── DocumentNumber → OQUT.DocEntry / ORDR.DocEntry
    │
    ├── Activities (OACT)
    │       ├── SalesOpportunityId  ← vínculo a OOPR
    │       ├── SalesOpportunityLine
    │       └── HandledBy
    │
    ├── Quotations (OQUT)          ← cotización al cliente
    │       └── BaseEntry → OOPR (si se crea desde la oportunidad)
    │
    └── Orders (ORDR)              ← confirmación de venta
            └── BaseEntry → OQUT.DocEntry

Campos clave por entidad

OOPR — SalesOpportunities

Campo Tipo Quién lo llena Cuándo
OpportunityName string Vendedor Alta
CardCode string Vendedor Alta
SalesPerson int Sistema (usuario logueado) Alta automática
StartDate date Sistema Alta automática (hoy)
PredictedClosingDate date Sistema / Vendedor Alta (+30d), editable
MaxLocalTotal decimal Vendedor Alta
CurrentStageNo int Sistema Al avanzar etapa
ClosingPercentage decimal Sistema Calculado por etapa
Status enum Sistema sos_Open → sos_Won / sos_Missed
ReasonForClosing string Vendedor Solo al cerrar como perdida
WeightedSumLC decimal SAP (calculado) Automático

OQUT — Quotations (draft con texto libre)

{
  "CardCode": "C01048",
  "DocObjectCode": "oQuotations",
  "DocumentSpecialLines": [
    {
      "LineNum": 0,
      "AfterLineNumber": -1,
      "OrderNumber": 1,
      "LineType": "dslt_Text",
      "LineText": "NOTEBOOK ACER ASPIRE 15 BXT i7 2990GHz - 255GB - NEGRO. PRECIO GS 5370000"
    }
  ]
}

Nota: el Quotation draft usa DocumentSpecialLines con LineType: dslt_Text. No tiene totales calculados por SAP — el precio está embebido en el texto. Es una propuesta orientativa, no un documento financiero formal. El Quotation con ítems reales se genera después de que el cliente acepta.

OACT — Activities

Campo Tipo Descripción
SalesOpportunityId int Vínculo a la oportunidad — obligatorio para que aparezca en el timeline
SalesOpportunityLine int Línea de etapa específica
ActivityType enum Reunión / Llamada / Tarea / Email
HandledBy int Empleado responsable
ActivityDate date Fecha de la actividad
Status enum open / closed
DocType + DocEntry int Si genera un documento vinculado

Estados de la oportunidad (OOPR.Status)

Estado SAP Descripción Quién lo activa
sos_Open Oportunidad activa Sistema al crear
sos_Won Cerrada ganada Sistema al convertir OQUT → ORDR
sos_Missed Cerrada perdida Vendedor al registrar rechazo

4. Módulo de comentarios Firebase

Esquema de rutas (no modificar)

comments/
  {entity_code}/          ← OOPR / OACT / OQUT / ORDR
    {record_id}/
      {comment_id}
        body: string
        author_id: string
        author_type: "internal" | "customer"
        created_at: timestamp
        attachments: []
        parent_id: string | null   ← para replies

Contextos de uso por paso del flujo

Paso Entidad donde se comenta Quién comenta
1 — Apertura OOPR/{opp_id} Vendedor
2 — Reunión OACT/{act_id} Vendedor + Cliente
2B — Tarea Compras OACT/{tarea_id} Vendedor + Compras
3 — Negociación OQUT/{quot_id} Vendedor + Cliente
5 — Confirmación OQUT/{quot_id} o OOPR/{opp_id} Vendedor
6 — Rechazo OOPR/{opp_id} Vendedor

Construcción del timeline (backend NestJS)

1. GET SalesOpportunities(id)?$expand=SalesOpportunitiesLines,Activities
2. Construir índice de nodos: { entity_code, record_id } por cada entidad vinculada
3. Promise.all → consultas Firebase paralelas por cada nodo
4. Merge cronológico por fecha del documento SAP padre
5. Push notificaciones al actor correspondiente

5. Flujo operativo — Ciclo completo

Diagrama de flujo (Mermaid — pendiente de generar en A1)

INICIO
  │
  ▼
[1] VEND: Alta de oportunidad (OOPR)
  │  → OpportunityName + CardCode + MaxLocalTotal + StageKey=Lead
  │
  ▼
[2] ¿El ítem existe en SAP?
  │
  ├── SÍ ──▶ [2A] VEND: Genera Quotation draft (OQUT con dslt_Text)
  │                    → Sin intervención de Compras
  │                    → Editable libremente durante la negociación
  │
  └── NO ──▶ [2B] VEND: Crea tarea (OACT) → asigna a COMP
                   │     → Lista de ítems + specs + fecha límite
                   │
                   ▼
                  COMP: Crea ítem en SAP
                   │     → Código + precio de costo + descripción
                   │
                   ▼
                  VEND: Genera Quotation draft con el ítem habilitado
  │
  ▼
[3] VEND: Envía cotización al cliente
  │  → PDF adjunto en comentario del hilo OQUT
  │
  ▼
[3-loop] CLI: Revisa y responde en el hilo
  │  → ¿Cambios? → VEND edita líneas de texto del Quotation → vuelve a enviar
  │  → Este loop se repite sin límite sin necesidad de Compras
  │
  ▼
[4] ¿El cliente decide?
  │
  ├── ACEPTA ──▶ [5] VEND: Formaliza el Quotation
  │                   │  → Reemplaza líneas de texto por ítems reales (si había draft)
  │                   │  → COMP crea ítems nuevos si es necesario (solo aquí)
  │                   │  → Convierte OQUT → ORDR
  │                   │  → Oportunidad: Status = sos_Won
  │                   └──▶ FIN (ganado)
  │
  └── RECHAZA ──▶ [6] VEND: Registra motivo (ReasonForClosing)
                       │  → Oportunidad: Status = sos_Missed
                       └──▶ FIN (perdido)

Quién hace qué — tabla completa

Acción Responsable Condición
Abrir la oportunidad Vendedor Siempre
Generar Quotation draft (líneas de texto) Vendedor Siempre — ítem exista o no en SAP
Crear tarea a Compras Vendedor Solo si necesita ítem nuevo para el Quotation formal
Crear ítem nuevo en SAP Compras Solo cuando hay ítems nuevos y el cliente ya aceptó
Enviar cotización al cliente Vendedor Siempre
Editar líneas del Quotation draft Vendedor Cada vez que el cliente pide cambios
Responder y negociar Cliente En el hilo del OQUT
Formalizar Quotation (ítems reales) Vendedor + Compras Solo al confirmar aceptación
Convertir OQUT → ORDR Vendedor Al confirmar aceptación
Registrar motivo de rechazo Vendedor Al confirmar rechazo

Estados de la oportunidad

sos_Open
  ├── [avanza etapa]     → sigue en sos_Open con StageKey actualizado
  ├── [convierte a ORDR] → sos_Won
  └── [registra rechazo] → sos_Missed

6. Quotation draft con líneas de texto

Por qué resuelve el problema de negociación

El flujo sin líneas de texto tenía el problema de que cada ítem nuevo requería un ciclo completo hacia Compras, lo que hacía la negociación lenta e impráctica.

Con DocumentSpecialLines + dslt_Text: - El vendedor genera el Quotation inmediatamente, con descripción y precio en texto libre - El cliente negocia sobre ese draft - Los cambios se hacen editando líneas de texto — sin Compras, sin espera - Compras solo entra después de que el cliente acepta, para formalizar los ítems

Limitación conocida

El Quotation draft no tiene totales calculados por SAP. El precio está en el texto de la línea. Política a comunicar al equipo:

El Quotation draft es una propuesta orientativa. El documento con valor formal es el Quotation con ítems reales generado después de la aceptación.

Formato del payload

{
  "CardCode": "C01048",
  "DocObjectCode": "oQuotations",
  "DocumentSpecialLines": [
    {
      "LineNum": 0,
      "AfterLineNumber": -1,
      "OrderNumber": 1,
      "LineType": "dslt_Text",
      "LineText": "NOTEBOOK ACER ASPIRE 15 i7 - 16GB - 512GB SSD - PRECIO GS 5.370.000"
    },
    {
      "LineNum": 1,
      "AfterLineNumber": -1,
      "OrderNumber": 2,
      "LineType": "dslt_Text",
      "LineText": "ADAPTADOR DISPLAY PORT A HDMI - PRECIO GS 209.000"
    }
  ]
}

7. Flujo de la Activity

⚠️ Este bloque está pendiente de desarrollo detallado (Bloque B del meta-plan). Lo siguiente es el estado actual del análisis.

Tipos de Activity en el flujo

Tipo Quién la crea Vinculada a Propósito
Reunión / Llamada Vendedor Oportunidad Registro de contacto con el cliente
Tarea interna Vendedor Oportunidad Solicitud a Compras para ítems nuevos

Vínculo Activity ↔ Oportunidad (campos clave)

{
  "SalesOpportunityId": 142,    // vínculo a OOPR — obligatorio
  "SalesOpportunityLine": 1,    // línea de etapa específica
  "HandledBy": 115,             // empleado asignado
  "ActivityType": "task",       // meeting / call / task / email
  "Status": "open"              // open / closed
}

Regla crítica

Si SalesOpportunityId no está seteado, la Activity no aparece en el timeline de la oportunidad. Toda Activity relacionada con una oportunidad debe crearse desde dentro de la oportunidad.


8. Timeline unificado

Estructura de nodos por ciclo completo

OOPR/142   ← nota inicial del vendedor al abrir
OACT/365   ← reunión con el cliente + archivos compartidos
OACT/366   ← tarea interna a Compras (solo si hay ítems nuevos)
OQUT/90    ← cotización draft + toda la negociación
ORDR/201   ← orden de venta (solo si ganado)

Cómo se ve en la UI

Cada nodo es un grupo en el timeline con: - Badge de entidad (código + número, color por tipo) - Título descriptivo - Hilo de comentarios Firebase anclado a esa entidad - Link "Ver documento →" que abre el documento SAP

Arquitectura de construcción (NestJS)

// OpportunityLinksService
async getLinkedEntities(opportunityId: number) {
  const opp = await sapClient.get(
    `SalesOpportunities(${opportunityId})?$expand=SalesOpportunitiesLines,Activities`
  );
  return buildNodeIndex(opp); // { OOPR, OACT[], OQUT[], ORDR[] }
}

// TimelineService
async buildTimeline(opportunityId: number) {
  const nodes = await this.getLinkedEntities(opportunityId);
  const comments = await Promise.all(
    nodes.map(n => firebase.get(`comments/${n.entityCode}/${n.recordId}`))
  );
  return mergeChronological(nodes, comments);
}

9. Reglas operativas

  1. Todo documento se crea desde la oportunidad. No se generan Quotations ni Activities por fuera de OOPR. Un documento creado por fuera no aparece en el timeline.

  2. La negociación ocurre en el hilo del Quotation. No en Notion, no en WhatsApp. El hilo del OQUT es la fuente de verdad.

  3. Cada paso requiere al menos un comentario. No es válido avanzar sin registrar qué ocurrió y cuál es el próximo paso.

  4. El motivo de rechazo es obligatorio al cerrar como perdida. Sin ReasonForClosing el sistema no permite cambiar Status = sos_Missed.

  5. Una oportunidad perdida nunca se elimina. Queda como historial del cliente para futuras oportunidades.

  6. El Quotation draft (líneas de texto) es orientativo, no formal. El documento con valor financiero formal es el Quotation con ítems reales, generado solo después de la aceptación del cliente.


10. Meta-plan de documentación

Bloque A — Oportunidad

# Artefacto Formato Contenido Estado
A1 Diagrama de flujo principal Mermaid flowchart Pasos 1→6, bifurcaciones, responsable por paso ⏳ pendiente
A2 Diagrama de estados Mermaid stateDiagram Estados OOPR: Open → Won / Missed ⏳ pendiente
A3 Diagrama de entidades Mermaid erDiagram OOPR + OQUT + ORDR + OACT. Campos clave ⏳ pendiente
A4 Tabla de campos SAP MD table Por entidad: campo, tipo, quién, cuándo, default ✅ en este doc (sección 3)
A5 Reglas y restricciones MD lista Qué bloquea avanzar, qué es obligatorio ✅ en este doc (sección 9)

Bloque B — Activity

# Artefacto Formato Contenido Estado
B1 Diagrama de flujo Activity Mermaid flowchart Creación → asignación → ejecución → cierre ⏳ pendiente
B2 Diagrama de estados Mermaid stateDiagram Open / In Progress / Closed / Cancelled ⏳ pendiente
B3 Tabla de tipos de Activity MD table Reunión, Llamada, Tarea. Campos por tipo ⏳ pendiente
B4 Vínculo Activity ↔ Oportunidad MD + snippet SalesOpportunityId + Line, qué rompe el vínculo ✅ en este doc (sección 7)

Bloque C — Comentarios (transversal)

# Artefacto Formato Contenido Estado
C1 Diagrama estructura Firebase Mermaid graph Esquema de rutas por entidad ⏳ pendiente
C2 Tabla de contextos de comentario MD table Entidad + quién comenta + en qué paso ✅ en este doc (sección 4)

Orden sugerido de producción

A1 → A2   (flujo y estados — base conceptual)
A3 → A4   (entidades — base técnica)        ← A4 ya está
A5        (restricciones)                   ← A5 ya está

B1 → B2   (flujo y estados de Activity)
B3 → B4   (detalle técnico y vínculo)       ← B4 ya está

C1 → C2   (comentarios)                     ← C2 ya está

11. Prompts UI generados

Los siguientes prompts están listos para pasar a un agente de UI (v0, Bolt, Cursor, Lovable):

# Pantalla Descripción
P1 Pipeline Gerencial Dashboard con KPIs, kanban 3 columnas, tabla y feed de actividad
P2 Detalle de Oportunidad + Timeline Header SAP, barra de etapas, timeline unificado con hilos Firebase
P3 Cotización + Panel de Negociación Documento OQUT izquierda + hilo de comentarios derecha
P4 Vista Móvil del Vendedor Frame iPhone, oportunidad activa, timeline compacto, acciones rápidas
P5 Alta de Oportunidad (simplificada) Card único, 5 campos, alta en < 60 segundos
P6 Tarea de Compras Solicitud del vendedor + carga de precios + margen en tiempo real

Los textos completos de los prompts están en la conversación original. Pendiente: exportarlos a archivos .txt individuales para uso offline.


12. Puntos abiertos

# Pregunta Bloquea
1 ¿Cuáles son las etapas definitivas y sus % de cierre? A1, A2, P1
2 ¿Cómo se notifica a Compras al crear la tarea? ¿Push, email o ambos? B1, P6
3 ¿El vendedor ve el precio de costo al generar el Quotation? Regla de margen
4 ¿Existe margen mínimo requerido? ¿Quién aprueba excepciones? A5
5 ¿Cuáles son los motivos de pérdida definitivos a configurar en SAP? A1, A5
6 ¿Cómo accede el cliente al portal de comentarios? ¿Login o token? C1, P3
7 ¿Qué pasa con el Quotation draft al formalizar post-aceptación? ¿Se cancela o se reemplaza? A1
8 ¿Hay umbral de días sin actividad que marque una oportunidad como inactiva en el dashboard? P1

Compulandia · Análisis interno · No distribuir · v0.3