MediRec docs Index Appointment lifecycle Gap analysis Migration plan Clinic questions

Internal review draft

MediRec vs. Odoo gap analysis

What the clinic's live Odoo install actually does, what MediRec already does, and the distance between them. Read from a live instance using aggregate queries only.

15,488 Consultations in Odoo, 7,795 of them this year System of record
0 Appointments and invoices in Odoo Not in use
1,585 Lab results with no MediRec equivalent Critical gap
~5,100 Scanned documents (~14 GB) with nowhere to land Critical gap
82,477 CIE-10 codes already loaded — shipped under MED-93, not a gap Corrected 02 Aug

Method and caveats

Read this before trusting any number below.

No patient data was read

The Odoo side was read live through the web client's own RPC endpoints, using only schema introspection, aggregate counts, and configuration tables. Every figure in this document is an aggregate.

The account used is a plain member of the single Medical Group, without Administration/Access Rights. That blocked three things:

  • ir.model and ir.model.fields — the model inventory was rebuilt by resolving menu actions through /web/action/load instead. A model with no menu entry and no report template would not appear in this analysis.
  • ir.module.module — the installed-app list is inferred from the menu tree, not read directly.
  • Per-group record rules — so "who can see what" in Odoo is known only at group granularity.

If an admin login becomes available, the one query worth re-running is a full ir.model sweep, to confirm nothing menu-less is in active use.

Headline findings

Ranked by how much each one changes the scope of the project.

01

Odoo is not doing scheduling

medical.appointment and calendar.event both sit at zero rows. The clinic schedules in TeamUp. MediRec's appointment system — the single largest body of work in the repo — replaces TeamUp, not Odoo, and has no Odoo counterpart to reconcile against.

02

Odoo is not doing billing either

Accounting, Sales, and Inventory are installed and visible in the menus but hold zero invoices, zero payments, zero sales orders, and zero stock moves. There is no billing behaviour to replicate, which removes what had looked like the largest gap in the project.

03

The real workload is one very fat model

consulta.medica is a custom 236-field table covering general, gynecologic, nutrition, pediatric, and physiotherapy visits all at once. At 15,488 rows and 7,795 created in 2026 alone, it is the system of record and it is very much alive.

04

The lab module is live, growing, and absent from MediRec

1,585 results backed by 1,492 structured result lines, against a catalog of 44 test types and 106 units. 1,003 of those results were created in 2026 — it is the fastest-growing area of the entire Odoo install, and MediRec has nothing at all.

05

Thousands of scanned documents have nowhere to go

I counted 3,167 in ir.attachment — 2,876 on patients, 291 on consultations. MED-111 puts Erik's actual extract at ~5,100 documents, ~14 GB, so treat my figure as a floor: the read-only account may have been subject to record rules. Nothing in MediRec's nineteen tables can hold a file.

When each system came alive

Consultations created per year

consulta.medica · peak 7,795

263
1
7,429
7,795
2023202420252026

Lab results created per year

medical.lab · peak 1,003

92
5
485
1,003
2023202420252026

Each chart is scaled to its own maximum — the two are not directly comparable. Both tell the same story: a false start in 2023, a dormant 2024, and real adoption from 2025 onward. 2026 is a partial year and already the highest on both.

What is actually live in Odoo

Installed is not the same as used. Sorted by real activity.

Model Rows Relative volume 2025 2026 Status
consulta.medica15,4887,4297,795Core system of record
medical.patient12,4271,498931Live — 8,590 were a 2023 import
medical.pathology12,423CIE-10 catalog
ir.attachment (patients)2,876Live
medical.pathology.category2,035CIE-10 categories
medical.lab1,5854851,003Live, accelerating
medical_test.critearea1,492Structured lab result lines
ir.attachment (consultations)291Live
medical.lab.test.units106Reference
medical.diagnostic91MINSAL notifiable-disease list
tipo.consulta71Consultation-type catalog
medical.test_type44Lab test catalog
medical.physician3429 appear on consultations
medical.procedures30Free text, badly polluted
medical.patient.lab.test8Abandoned request workflow

Bar length is relative to the largest model. Grey bars are reference or catalog data rather than clinical activity.

Installed but empty — do not build these

medical.appointment calendar.event medical.insurance medical.vaccination medical.prescription.order medical.prescription.line medical.medicament medical.patient.disease medical.patient.medication1 medical.family.disease medical.patient.psc medical.patient.pregnency medical.patient.menstrual.history medical.patient.mammography.history medical.patient.pap.history medical.patient.colposcopy.history medical.patient.cage medical.preinatal account.move account.payment sale.order stock.picking stock.quant helpdesk.ticket

The pattern worth noticing

Every structured clinical sub-model that shipped with the base medical module sits at zero. The clinic does not use any of them. Instead, allergies, chronic conditions, prior surgeries, and medications are re-typed as free text into consulta.medica on every single visit. There is no longitudinal patient record for any of it.

That makes MediRec's normalized patient_allergies, patient_chronic_diagnoses, and patient_history_events tables a genuine clinical-safety improvement over current practice — not a port of it.

Capability matrix

Odoo as actually used, against MediRec as built.

CapabilityOdoo (as used)MediRecVerdict
Patient demographics170 fields, ~12.4k patients40 fields, full CRUDParity
Socioeconomic surveydui, posee_vehiculo, tipo_vivienda1:1 equivalentsParity
Consultation records236 fields, 15.5k rows5 specialty formsNear parity
Specialty coverageGeneral, Gyn, Nutrition, Pediatric, PhysioThe same fiveParity
Lab results1,585 results, ranges, PDFNoneCritical gap
Document attachments≥3,167 observed; ~5,100 in Erik's extractNoneCritical gap
CIE-10 / ICD catalog12,423 + 2,035 categories12,687 ES + 74,719 EN, two importers (MED-93)Parity — unreconciled
Epidemiological reporting91-item MINSAL listNoneCritical gap
Reporting / dashboardsPivot and graph viewsPlaceholder page onlyMajor gap
PrescriptionsHTML blobStructured tableAhead
Allergies / chronic / historyFree text, re-typed per visitNormalized tablesAhead
Appointments / scheduling0 rows — uses TeamUpFull 14-state systemAhead
Patient flow trackingState field stuck, no historyStage timer + audit logAhead
Role-based accessOne group, 25 users11 roles, ~25 capability methodsAhead
Audit trailChatter only4 tables, field-level diffsAhead
Bilingual UIMixed EN/ES, inconsistentEnforced EN + ES parityAhead
Billing0 recordsNoneOut of scope

Gaps to close

Grouped by whether they block a cutover, slow daily work, or can wait.

Critical — blocks any cutover

G1

Lab results module

Critical

1,585 results and climbing fastest of anything in the install. Needs a result record (patient, test type, requesting physician, pathologist, analysis date, narrative results and diagnosis, status), structured result lines with parameter, value, unit, limits, normal range and an out-of-range flag, plus catalogs for the 44 test types and 106 units. Odoo also stores a generated PDF per result.

The laboratory_technician role and AppointmentType::LAB already exist in MediRec with nothing behind them.

G2

Document attachments

Critical

3,167 files against patients and consultations. Nothing in MediRec's nineteen tables can hold a file. Needs a polymorphic attachment model, storage configuration, upload UI on the patient and consultation views, and a migration path for the existing binaries.

Confirmed 2026-08-02: the files are scanned medical visit forms, lab results, X-rays and other documents. All of them carry over, with no exclusion by type, and they must live inside MediRec — Odoo is being decommissioned, so there is no read-only fallback. The X-rays are ordinary image files rather than DICOM studies, so this stays a file-handling feature and needs no medical imaging viewer.

Rescoped against MED-111: Erik has already extracted the documents — ~5,100 files, ~14 GB — and they are bound for Laravel Cloud, not the local private disk. This is not a "pull the binaries out of Odoo" problem; it is a secure-intake, storage-layout and record-linkage problem, with an encrypted transfer path and a verification count against Odoo. The ticket flags it as real patient data needing a human at every step.

Treat the PHI rules in CLAUDE.md as binding on both storage location and access logging.

G4

Epidemiological notifiable-disease reporting

Critical

medical.diagnostic is the 91-entry El Salvador MINSAL list — dengue, tuberculosis, chagas, maternal and infant deaths, intento de suicidio, violación sexual — attached many-to-many to every consultation. This looks like a regulatory reporting obligation rather than a convenience feature, and MediRec has no way to produce the return.

Confirm the reporting cadence with the clinic before scoping this one.

Correction — G3 was already built

An earlier version of this document claimed the CIE-10 catalog had no seeder and needed building from Odoo. That was wrong. It shipped under MED-93 (Doctor Visit v1.1, currently READY FOR REVIEW).

PieceState
app:import-icd10Spanish CIE-10 importer, idempotent upsert on code
app:import-icd10-enEnglish ICD-10-CM importer, independent of the above
ingest/cie10/catalogo_cie10.csvMexican SSA/DGE catalog — 12,687 terminal codes
ingest/icd10-en/…txtCDC ICD-10-CM — 74,719 codes
Dev databaseAlready populated: 82,477 rows (12,687 ES, 74,719 EN)

What remains is much smaller than "build the catalog":

  • Not wired into DatabaseSeeder. migrate:fresh --seed — the reset command documented in CLAUDE.md — leaves icd_codes empty, so fresh environments and CI silently get no catalog.
  • Not discoverable. The only documentation lives in ingest/*/README.md.
  • Not reconciled against Odoo. This is the one with teeth — see Migration below.

Major — needed for daily work to feel complete

G5

Reporting and dashboards

Major

The admin reports page is a placeholder paragraph. If the clinic's mental model of Odoo is "the dashboard", this is the most visible gap of all. Scope it from what they actually open rather than guessing.

G6

Consultation-type catalog

Major

Odoo has 71 free-text types against MediRec's six-value enum. The top five map cleanly — General 5,843, Pediátrica 3,200, Ginecológica 2,129, Nutricional 1,364, Fisioterapia 814 — but the tail does not: CONTROL PRENATAL (326), CONTROL INFANTIL (343), USG (149 across variants), CITOLOGIA, TERAPIA DE LENGUAJE. Decision needed: extend the enum, or add a lookup table alongside it.

The Odoo catalog is dirty — duplicates such as CONSULTA GINECOLOGICA against CONSULTA GINECOLOGIA, and typos like NUTRIION. Migrating it needs a cleanup pass, not a straight copy.

G7

Prenatal and obstetric follow-up

Major

Around 370 prenatal consultations. Odoo's structured obstetric models are all empty, so today this is free text — but the volume is real, and MediRec has only a last-menstrual-period date and a pregnancy-history text field.

G8

Ultrasound (USG)

Major

Around 149 consultations, plus two report templates. The medical.ultrasound model itself no longer exists in the database, so the reports are orphaned. This is a live workflow with no working storage on either side — worth scoping properly rather than porting.

G9

Patient category a / b / c / d

Blocks migration

Actively populated across all four tiers — a=4,324, b=6,958, c=793, d=349. MediRec computes only a two-tier fee code from family-abroad, vehicle, and remittance answers. These do not reconcile.

Confirm what the Odoo categories mean before migrating. If they drive what a patient pays, the MediRec fee logic is wrong for the c and d tiers at minimum.

Minor

G10

Insurance status on consultations

677 ISSS and 3,669 explicit "no". MediRec carries insurance status only on exam reports, not consultations.

G11

COVID dose tracking

Three dose booleans and three dates per consultation. Probably declining in relevance — confirm before building.

G12

Photo, blood type, deceased flag, critical-info banner

Schema exists in Odoo, but blood type is populated on 5 patients out of 12,427. Effectively unused — build only on request.

G13

Telemedicine flag

4 records out of 15,488. Skip.

Where MediRec is already ahead

Stated explicitly so none of this gets re-added "to match Odoo".

  • SchedulingNo Odoo equivalent in use at all.
  • Longitudinal clinical dataNormalized allergy, chronic-diagnosis and history tables replace re-typing the same free text on every visit.
  • Structured prescriptionsA real table, against an HTML blob.
  • Access control11 roles against a single shared group for 25 users. There is no Odoo permission model to migrate — it has to be designed from how the clinic actually works.
  • Audit trailField-level diffs with actor, IP and user agent, versus Odoo's chatter.
  • Bilingual UIEnforced parity between English and Spanish on every key.

Data migration

12,427 patients · 15,488 consultations · 1,585 lab results · ~5,100 attachments (~14 GB).

Field mapping is unusually clean on the patient record — the Odoo custom fields were clearly the template for MediRec's schema.

OdooMediRec
name ("ID")expediente_id
duidui_or_chart_number
lastname / last_namelast_names
numero_hijosnumber_of_children
familiar_extrangerofamily_abroad
posee_vehiculoowns_vehicle
alquila_viviendahousing_ownership
tipo_viviendahousing_type
iglesia_asistechurch_attended
escuela_asisteschool_attended
lugar_empleoplace_of_employment
vocacion_paciente / vocacion_conyuguepatient_occupation / spouse_occupation
numero_personas_viviendapeople_in_household
posee_refrigerador, television, water, electricityhas_refrigerator, has_tv, has_potable_water, has_electricity
responsable_idresponsible_adult_minor

Issues to resolve before writing any importer

  • No family_abroad_sends_help equivalent exists in Odoo. MediRec's fee calculation reads it, so it will be null for every migrated patient — silently forcing the lower tier. See G9.
  • Sex is unset on 5,417 of 12,427 patients (44%). The MediRec column is nullable so this imports cleanly, but any sex-dependent form logic needs a null path.
  • 8,590 patients arrived in a 2023 bulk import. Worth sampling for duplicates and test records before carrying them across.
  • One Odoo table covers five specialties. MediRec splits by form type, so the importer must route on consultation type — and the 613 consultations with no type set need a rule.
  • Two different CIE-10 catalogs are in play, and nobody has compared them. MediRec's Spanish set is the Mexican SSA/DGE catalog (12,687 terminal codes, already loaded); Odoo's medical.pathology holds 12,423. Historical consultations reference Odoo's codes, so any code present in Odoo but absent from ours produces a migrated diagnosis pointing at nothing. Similar counts are not evidence the sets match — diff them before the consultation import, not after.

Suggested backlog

Ordered by what blocks a cutover, not by effort.

#ItemGapNotes
1Reconcile CIE-10 against Odoo's medical.pathologyG3Cheap, and it de-risks the consultation import
2Lab results moduleG1Largest single build — four new tables
3Document attachmentsG2PHI-sensitive; storage and access-log design needed
4Epidemiological reportingG4Confirm the regulatory requirement first
5Reporting and dashboardsG5Scope from what the clinic actually opens
6Consultation-type catalogG6Decide enum versus lookup table
7Reconcile patient category vs. fee codeG9Blocks patient migration correctness
8Prenatal and obstetric follow-upG7~370 consultations a year
9Insurance status on consultationsG10Small
10Ultrasound workflowG8Needs discovery — broken on both sides

Items 1, 7 and 4 are worth resolving before the others: the first de-risks the consultation import for very little effort, the second can invalidate a migration already run, and the third may be a compliance deadline rather than a feature request.

Open questions for the clinic

Three answered on 2026-08-02. Only the patient categories still block anything.

Still open

  • Patient categories UrgentWhat do a, b, c and d mean — and do they set what a patient pays? Blocks correctness of the patient migration.
  • Daily Odoo useWhat do staff actually open day to day? Drives G5, and may deprioritize half the minor gaps.
  • MINSAL returnIs it a legal obligation, and on what cadence?

Answered

  • Odoo after cutoverFull retirement. Confirms accounting, sales and inventory are permanently out of scope, and that nothing can be left behind in Odoo.
  • AttachmentsAll of them migrate. Scanned visit forms, lab results, X-rays and other documents, with no exclusion by type. See G2.
  • X-ray formatOrdinary images, not DICOM. G2 needs no imaging viewer and its estimate stands.