Mostrando entradas con la etiqueta presupuesto. Mostrar todas las entradas
Mostrando entradas con la etiqueta presupuesto. Mostrar todas las entradas

martes, 7 de julio de 2026

Módulo presupuesto de odonto-app

 ¿Cómo sería una funcionalidad de presupuesto basada en tratamientos apuntados en un odontograma?

En un software odontológico, una función de presupuesto suele ser la consecuencia natural del odontograma. El odontograma registra el estado clínico; el presupuesto traduce ese diagnóstico en un plan económico.

Una arquitectura típica sería:

  1. El odontograma contiene los dientes, caras dentarias y tratamientos indicados.

  2. Cada tratamiento indicado referencia un tipo de prestación (obturación, endodoncia, extracción, corona, etc.).

  3. Al generar un presupuesto, el sistema recorre esos tratamientos y busca el precio vigente de cada prestación.

  4. Se genera un documento de presupuesto independiente del odontograma.

Por ejemplo:

Odontograma
 ├── Tratamiento: Obturación simple (pieza 16)
 ├── Tratamiento: Endodoncia (pieza 26)
 └── Tratamiento: Corona de porcelana (pieza 11)

↓

Presupuesto

Obturación simple .......... $45.000
Endodoncia ................. $95.000
Corona porcelana .......... $280.000

Total ..................... $420.000

¿Por qué no calcularlo directamente desde el odontograma?

Porque los precios cambian.

Si mañana la corona pasa de $280.000 a $320.000, un presupuesto emitido hace dos meses debe seguir mostrando $280.000.

Por eso normalmente existen dos entidades:

  • Odontograma → información clínica.

  • Presupuesto → fotografía comercial en un momento determinado.

Qué tablas tendría

prestaciones
------------
id
codigo
descripcion
precio_actual
...

presupuestos
------------
id
paciente_id
fecha
estado
subtotal
descuento
total
...

presupuesto_items
-----------------
id
presupuesto_id
prestacion_id
pieza
cantidad
precio_unitario
importe

Observá que precio_unitario queda copiado en el presupuesto aunque luego cambie el precio de la prestación.

Flujo de trabajo

  1. El odontólogo marca tratamientos en el odontograma.

  2. Presiona Generar presupuesto.

  3. El sistema propone automáticamente todos los tratamientos pendientes.

  4. El profesional puede quitar algunos, agregar otros o modificar cantidades.

  5. Se guarda el presupuesto.

  6. Más adelante pueden generarse nuevos presupuestos sin modificar el odontograma.

Una mejora interesante

En lugar de guardar en el odontograma un texto como:

{
    "tratamiento": "Obturación"
}

conviene guardar el id de la prestación:

{
    "prestacionId": 17
}

Así el presupuesto puede obtener automáticamente:

  • descripción,

  • precio vigente,

  • duración estimada,

  • color para el dibujo,

  • código interno,

  • cobertura de obra social, etc.

De esa manera, el odontograma permanece como un documento clínico, mientras que el presupuesto se convierte en una "instantánea" económica generada a partir de él, manteniendo ambos conceptos desacoplados y permitiendo que evolucionen de forma independiente.


Quiero una narración cronológica de cómo va pasando de una instancia a la otra.

Una forma bastante natural de verlo es pensar que cada instancia representa una etapa distinta del trabajo del odontólogo, y que cada una congela cierta información para no depender de cambios posteriores.

1. Odontograma (estado clínico)

El paciente llega al consultorio. El odontólogo examina la boca y registra el estado de cada pieza dental.

Por ejemplo:

  • Pieza 11: caries.

  • Pieza 16: restauración en mal estado.

  • Pieza 26: endodoncia indicada.

En esta etapa no hay decisión terapéutica ni precios. Sólo existe el diagnóstico y el estado de la boca.

Pregunta que responde: ¿Qué tiene el paciente?


2. Treatment Plan (plan de tratamiento)

A partir del diagnóstico, el odontólogo decide qué propone hacer.

Por ejemplo:

  • Pieza 11 → Restauración con resina.

  • Pieza 16 → Reemplazar restauración.

  • Pieza 26 → Endodoncia y luego corona.

Todavía no se habla de dinero. Incluso pueden existir varios planes alternativos.

Por ejemplo:

  • Plan A: conservar la pieza mediante endodoncia.

  • Plan B: extraer la pieza e implantar un implante.

Pregunta que responde: ¿Qué tratamiento se propone?


3. Treatment Estimate (presupuesto)

Una vez elegido un plan, el sistema toma cada procedimiento y busca su precio vigente.

El presupuesto queda, por ejemplo:

PrestaciónPrecio
Restauración$45.000
Endodoncia$95.000
Corona$280.000
Total$420.000

En este momento el presupuesto se congela.

Aunque dentro de un mes la corona aumente a $320.000, este presupuesto seguirá mostrando $280.000.

También puede registrar:

  • descuentos,

  • financiación,

  • obra social,

  • impuestos,

  • vigencia del presupuesto.

Pregunta que responde: ¿Cuánto costará?


4. Invoice (factura)

Cuando el paciente acepta el presupuesto y comienzan los tratamientos, llega el momento de facturar.

La factura representa una operación económica real.

Puede ocurrir que:

  • el presupuesto era por $420.000;

  • el paciente decidió postergar la corona;

  • hoy sólo se facturan la restauración y la endodoncia.

La factura queda por $140.000.

Más adelante podrá emitirse otra factura por la corona.

Pregunta que responde: ¿Qué se cobró realmente?


El flujo completo

Paciente llega

        │
        ▼
 Odontograma
 "¿Qué tiene?"

        │
        ▼
 Treatment Plan
 "¿Qué proponemos hacer?"

        │
        ▼
 Treatment Estimate
 "¿Cuánto costará?"

        │
Paciente acepta

        │
        ▼
Se realizan prestaciones

        │
        ▼
 Invoice
 "¿Qué se cobró?"

¿Es obligatorio tener las cuatro entidades?

No necesariamente.

Para un software odontológico pequeño o mediano, una arquitectura muy razonable sería:

Odontograma
      │
      ▼
Presupuesto
      │
      ▼
Factura

En ese diseño, el plan de tratamiento no existe como entidad independiente: el propio odontograma contiene los tratamientos indicados, y el presupuesto se genera seleccionando algunos o todos ellos.

De hecho, muchos sistemas odontológicos funcionan así. Separar Treatment Plan como entidad propia cobra más sentido cuando se necesita soportar planes alternativos, revisiones de planes o flujos clínicos más complejos. Si tu objetivo es mantener Dentalia simple pero bien diseñado, podrías empezar con Odontograma → Presupuesto → Factura y extraer un TreatmentPlan más adelante sólo si aparecen requisitos que realmente lo justifiquen.


¿Esto que estoy haciendo de presupuesto se llama funcionalidad, módulo, o cómo?

Depende del nivel del que estés hablando en la arquitectura del sistema.

  • Funcionalidad (feature): es el término más general. Desde el punto de vista del usuario, "hacer un presupuesto" es una funcionalidad.

  • Módulo (module): es un conjunto de funcionalidades relacionadas que forman una parte identificable del sistema. Si tu sistema tiene menú lateral con "Pacientes", "Turnos", "Odontograma", "Presupuestos", "Facturación", entonces Presupuestos es un módulo.

  • Submódulo: si el módulo de Presupuestos luego incluye, por ejemplo, "Plantillas", "Listas de precios", "Presupuestos" y "Aprobaciones", cada uno podría considerarse un submódulo.

  • Caso de uso (use case): desde el análisis de requisitos, "Generar presupuesto" o "Aceptar presupuesto" son casos de uso.

En tu proyecto Dentalia, yo lo describiría así:

Módulo: Presupuestos

Funcionalidades:
- Generar presupuesto desde el odontograma.
- Editar presupuesto.
- Recalcular precios.
- Imprimir presupuesto.
- Enviar presupuesto por e-mail.
- Registrar aceptación o rechazo.
- Convertir presupuesto en factura.

Así mantenés una terminología consistente:

  • Odontograma → módulo.

  • Presupuestos → módulo.

  • Facturación → módulo.

  • Pacientes → módulo.

Y dentro de cada uno, sus respectivas funcionalidades.

Es una forma de organizar el sistema que resulta clara tanto para la documentación como para la planificación del desarrollo.

miércoles, 29 de octubre de 2025

Conexión entre odontograma y presupuesto

 Quiero que en el odontograma cuando marco que un diente tiene un problema, me siguiera los posibles tratamientos o dispositivos que se le pueden aplicar. Por ejemplo, si no me equivoco, para caries me sugeriría obturación y tratamiento de conducto. Después quiero que al seleccionar un correctivo específico se pueda indicar si está en estado para realizar o realizado. Y que dé la opción de cargar el correctivo en el presupuesto. Esto efectivamente conecta con la función presupuesto.


¡Absolutamente! Este es el flujo de trabajo central de cualquier sistema de gestión clínica u odontológica: Conectar el diagnóstico con el plan de tratamiento y la cotización (presupuesto).

Para implementar esta funcionalidad con React y Firestore (para la persistencia de datos), necesitarás un componente central que gestione el estado del diente, los posibles tratamientos y la fase de ejecución.

Voy a generar un único archivo React (OdontogramaApp.jsx) que simulará un solo diente (para simplificar la lógica) y un panel lateral. Este archivo contendrá:

  1. La Lógica de Sugerencia: Un mapeo de condiciones a tratamientos sugeridos.

  2. El Componente del Diente: Donde se selecciona el problema.

  3. El Panel de Tratamiento: Donde se elige la fase (Para Realizar / Realizado).

  4. La Integración con Firestore: Para guardar la información del plan de tratamiento y el estado.

Dado que esta es una aplicación compleja con gestión de estado y persistencia, usaré React con hooks y Tailwind CSS para la estética.

Mapeo de Problemas a Sugerencias

Usaremos un mapeo base para las sugerencias que mencionaste:

Problema (Diagnóstico)Sugerencias de Tratamiento
CariesEmpaste / Obturación, Tratamiento de Conducto, Corona
FracturaEmpaste / Obturación, Corona, Extracción
AusenciaImplante, Prótesis Fija, Prótesis Removible

Aquí tienes el código completo en un solo archivo React:

Voy a generar el archivo OdontogramaApp.jsx.

Previsualización (con audio):


 

Explicación del Funcionamiento

  1. Firebase Setup: El componente se inicializa con Firebase y se suscribe al estado del usuario.

  2. SUGGESTIONS_MAP: Define la lógica central que conecta un problem (ej. 'Caries') con un array de posibles treatment (ej. ['Empaste / Obturación', ...]).

  3. updateToothPlan (Persistencia): Esta función central encapsula la lógica para guardar cualquier cambio (problem, treatment, status, inBudget) en Firestore. Usa setDoc({ merge: true }) para actualizar solo los campos cambiados, manteniendo el resto de los datos.

  4. Flujo del Diente (Columna 1):

    • El usuario selecciona un Diagnóstico (ej. "Caries").

    • handleProblemSelect se llama, guarda el diagnóstico en Firestore y resetea los campos treatment y status.

  5. Sugerencias (Columna 2):

    • Al seleccionar un diagnóstico, el componente muestra automáticamente los botones de suggestedTreatments del mapa.

    • Al hacer clic en un tratamiento, se establece toothPlan.treatment y se inicializa el estado a "Para Realizar".

  6. Carga al Presupuesto (Columna 3):

    • El botón de presupuesto (CARGAR al Presupuesto) solo se activa si se ha seleccionado un tratamiento y un estado.

    • handleBudgetToggle invierte el valor de la propiedad inBudget en Firestore.

  7. Cálculo del Presupuesto:

    • Se utiliza un segundo onSnapshot (dentro del useEffect principal) que consulta la colección dental_plans filtrando solo por los documentos donde inBudget sea true.

    • Cada vez que un usuario añade o quita un tratamiento del presupuesto, Firestore actualiza esa consulta, y el budgetTotal se recalcula y se muestra al instante.


Perdón, no entiendo cuándo se actualiza toothPlan.

¡Esa es una excelente pregunta! En las aplicaciones de React que utilizan una base de datos en tiempo real como Firestore, la actualización del estado puede ser un poco diferente a la actualización de estado local tradicional.

Aquí te explico exactamente cuándo y cómo se actualiza toothPlan en el código:

El estado toothPlan se actualiza a través de dos mecanismos principales:

1. Actualización por Interacción del Usuario (Función updateToothPlan)

Esta es la forma en que los cambios se envían desde la aplicación a la base de datos (Firestore).

  • ¿Qué la dispara? La función updateToothPlan se llama cada vez que el usuario realiza una acción en la interfaz que debe guardarse:

    • Seleccionar un problema (handleProblemSelect).

    • Elegir un tratamiento (handleTreatmentSelect).

    • Cambiar el estado (handleStatusChange).

    • Cargar o remover del presupuesto (handleBudgetToggle).

  • ¿Cómo funciona?

    1. Cuando, por ejemplo, llamas updateToothPlan({ status: 'Realizado' }), la función envía una solicitud a Firestore para actualizar el documento de ese diente.

    2. ¡Espera! Aunque el código localmente ya sabe el nuevo estado, la variable de React toothPlan no se actualiza directamente en ese momento.

2. Actualización por Sincronización de Firestore (onSnapshot)

Esta es la forma en que los cambios confirmados en la base de datos regresan a la aplicación, garantizando que el estado local sea siempre el reflejo fiel del estado persistente (incluso si otro usuario o dispositivo lo hubiera cambiado).

  • ¿Qué la dispara? La función onSnapshot que definimos en el segundo useEffect:

    JavaScript
    // Dentro del useEffect (Se ejecuta al inicializar la DB y el usuario)
    const unsubscribePlan = onSnapshot(planRef, (docSnap) => {
        if (docSnap.exists()) {
            // ¡AQUÍ ESTÁ LA ACTUALIZACIÓN!
            setToothPlan(docSnap.data()); 
        } else {
            setToothPlan(INITIAL_TOOTH_DATA);
        }
    });
    // ...
    
  • ¿Cómo funciona?

    1. Cuando la aplicación inicia, onSnapshot se ejecuta y carga el estado inicial del diente.

    2. Cada vez que la base de datos (Firestore) detecta un cambio en el documento del diente (Tooth_14), automáticamente notifica a la aplicación.

    3. El callback de onSnapshot se ejecuta, toma los datos (docSnap.data()), y llama a setToothPlan(docSnap.data()).

    4. Este setToothPlan es lo que realmente actualiza el estado de React y provoca que todo el componente se re-renderice con el nuevo plan.

En Resumen (El Ciclo de Vida del Dato)

El ciclo de actualización es un circuito cerrado y asíncrono:

  1. Usuario Clic: Llama a updateToothPlan({...}).

  2. Base de Datos: El cambio se envía y se guarda en Firestore.

  3. Sincronización: Firestore notifica a onSnapshot que el documento ha cambiado.

  4. React Actualiza: onSnapshot llama a setToothPlan(), actualizando la interfaz.

Este patrón garantiza que tu estado local siempre esté "grounded" (arraigado) en lo que realmente está guardado en la base de datos.