Internal · file-level plan

What happens to every file

Every .py, .xml, .csv and asset in both modules, with a verdict and a destination. Counts taken with wc -l on 2026-09-19 and they add up — the totals at the bottom of each tree are arithmetic, not vibes.

Companion to the goal overview · diagrams · R1
Verdicts: stays untouched de-brand vendor strings out, logic unchanged fix a known defect, in place moves to a different module rewrite substantial change delete gone frozen historical, never touch new did not exist
Files in scope
57

text files across both modules

Lines untouched or frozen
3 654

43% of 8 588 — tests 3 389, migrations 265

Lines rewritten
1 262

two Egeko files, and that is the whole hard part

Shipped weight dropped
7.6 MB

two vendor PDFs, plus the DTD and 3 XML fixtures

8 588 PYTHON LINES ACROSS BOTH MODULES — WHAT ACTUALLY HAPPENS TO THEM 3 389 · tests kept verbatim, import paths only 265 mig 1 070 dev tools · not shipped 1 262 rewritten — both Egeko files 849 dropped from ship 1 753 edited — mostly strings ◼ 43% never moves ◼ 12% is tooling Odoo never loads ◼ 15% is the actual rewrite ◼ 10% leaves the repo ◼ 20% string work AND WITHIN THE 3 834 RUNTIME LINES IN SCOPE, THE WORK IS FOUR FILES provider_base/maptara_provider.py · 819 egeko/maptara_provider.py · 687 egeko_request.py · 575 base/sale_order.py · 508 everything else — 1 245 lines of labels, one CSV row, one dead model 2 589 lines = 68% of everything being edited, in four files. Which is why the plan puts one developer on two of them and the other on net-new code — the overlap is structurally small, not optimistically small. The 849 dropped lines are not ours: opta data's DTD (686, copyright 2007–2015), three reference XMLs, and a competitor's captured production payload. Plus 7.6 MB of vendor PDFs, not counted here because they are not lines.
The shape of the refactor. Reading the three tables below gives you the same numbers; this gives you the proportion. The single most useful thing on it: 43% of what looks like "the modules" is test code nothing in this plan edits — and the part that is genuinely rewritten is narrower than the file count suggests.

maptara_san_provider_base — 4 658 py lines, 30 text files

Runtime 2 386 · tests 2 007 · migrations 265. Two thirds of this module is not changing.

FileLinesVerdictWhat happens
__manifest__.py50de-brand Drop "post_init_hook": "post_init_hook_egeko" (:18). Author/licence at :44, :49. Version bump must be monotonic or the migration never runs.
__init__.py4de-brand Imports post_init_hook_egeko (:2).
hooks.py74de-brand Creates the cron literally named 'Egeko: Poll Cost Estimate Statuses' (:54) on install of the base. noupdate at :70-71, so renaming it is a migration, not an edit.
models/1 452
├─ __init__.py4stays
├─ maptara_provider.py819rewrite The centre of the work. Keep provider + activity + routing. Add the driver contract. Strip the chatter vocabulary (:739-776). Delete maptara.provider.uom (:133) — read by nothing. Relabel request_data/response_data from "XML File" (:531, :538) so a §302 flat file can live there.
├─ maptara_provider_ref_burn.py121de-brand Label only: 'eGeKo KV-Nr' at :63. The separate-cursor ledger mechanism is excellent and untouched — do not rename the columns; a lost row means a reissued KV-Nr.
└─ sale_order.py508de-brand 17 log lines prefixed "Egeko cron:"; the poll-then-fetch sequencing at :418-502 is Egeko's three-call protocol living in the base; _auto_init re-creates the cron on every -u (:328-330) so deleting it is not a supported state.
wizard/806
├─ __init__.py3stays
├─ maptara_send_ekv_wizard.py784de-brand "sent as X01 (Sonstige)" / "A01 for a prescription" — opta data's code list in base's warning text (:177-180). action_new_egeko_code is a public button name (:498). _get_ref_family (:434-496) is built around opta data's German refusal string.
└─ maptara_confirm_send_ekv_wizard.py19fix Calls _send_ekv directly (:19-20), bypassing _materialise_uploads — a file on the confirm path silently never becomes a document.
migrations/265frozen 4 scripts (19.0.0.3, .7, .8, .14). They reason about Egeko and MIP by name and that is fine — they are history. Any DB that has passed them stays passed. Never rewrite a shipped migration.
views/313
├─ maptara_provider_views.xml218de-brand 6 column labels reading eGeKo KV-Nr / Egekonummer. Also drops the maptara.provider.uom section.
└─ sale_order_views.xml95de-brand 2 labels, plus :25 — a comment in the base's XML citing maptara_san_provider_egeko/models/maptara_provider.py:211 by file and line. 🫠
wizard/maptara_send_ekv_wizard_views.xml154de-brand Binds action_new_egeko_code at :44.
wizard/maptara_confirm_..._views.xml19stays
security/ir.model.access.csv13fix Line 9: base.group_user holds 1,1,1,1 on the model storing password and client_key. Keep readcodexa_api/models/provider_site.py:20 is a non-sudo Many2one and breaks without it. Remove write/create/unlink; put groups= on the secrets. Also drops the 2 uom rows.
static/src/js/password_manager_ignore.js91stays
i18n/de.po665regen Every relabelled string changes its msgid. Regenerate, do not hand-edit, or the translations silently detach.
tests/  8 files, 112 test methods2 007keep Do not rewrite these. Import paths only. Their docstrings cite real incident dates and row counts — test_ekv_internal_ref.py (428) alone guards "a spent KV-Nr is never reissued" across 23 tests. They are the only thing making this refactor verifiable.
TOTAL4 6582 007 untouched · 265 frozen · 2 386 edited, of which most is string work

maptara_san_provider_egeko — 3 930 py lines, 27 text files + 7.6 MB of PDFs

Addon runtime 1 448 · manifest 30 · tests 1 382 · dev tools 1 070. Only 37% of the "module" is the module.

FileLinesVerdictWhat happens
__manifest__.py30rewrite Author/licence at :25, :30. Declare zeep — it is imported and appears in no requirements file anywhere. Add the driver dependency. Declare maptara_base and maptara_document_manager_api, both used and neither listed.
__init__.py3fix Imports a wizard package that contains nothing.
wizard/__init__.py1delete An empty package. One line, a coding cookie, zero purpose.
models/1 444
├─ __init__.py4stays
├─ egeko_request.py575split 185–230 lines become maptara_driver_soap: cached Transport/Client (:272-275), the module-scope WSDL cache (:102, 8 GETs → 1), require_auth, the logging plugin. The rest is Egeko protocol and stays. Fix on the way: Transport() gets no timeout (:273) while Client() does (:274); zero retries anywhere; no HTTP status code is inspected in the whole module.
├─ maptara_provider.py687rewrite The hard one. generate_document_template is one 263-line method (:180-442) mixing ORM reads, VAT arithmetic, MDM downloads over a different transport, and wire vocabulary, with no intermediate representation. Six copy-pasted credential blocks (:450, 471, 526, 595, 629, 676) collapse to one. Keep verbatim: the four status buckets, de_decimal/de_price, and dhpIdentNumer — opta data's own typo, which must not be "fixed".
├─ res_config_settings.py130mostly moves The endpoint-resolution pattern (env var → ir.config_parameterrefuse, never default) is promoted to the driver layer for everyone. The three named hosts stay here — they are Egeko's.
└─ sale_order.py48stays One override, _get_ekv_position_lines.
views/res_config_settings_views.xml68adapt Four mutually exclusive banners incl. the one shouting about the dead test host. Keep the behaviour; the picker is an @api.onchange and not a button, deliberately — a button reloads the settings record and silently discards the assignment.
i18n/de.po140regen
tests/  10 files, 83 test methods1 382keep + extend Strong on semantics: status buckets (15), wire number format (17), endpoint config (15), connection probe (17). Zero coverage of payload assembly or transport — exactly backwards for this refactor. New tests come first, before the rewrite.
tools/1 070
├─ ekv_body_diff.py630promote Diffs a captured payload against opta data's reference XML and exits 1 on mismatch. Explicitly written to gate a pipeline, and wired into nothing. This becomes the format oracle in CI.
└─ ekv_doctor.py440fix Hardcodes another developer's worktree (:21) and two container paths (:44-45).
tools/fixtures/849drop from ship
├─ Egeko.dtd686drop Line 5: copyright (c)2007 - 2015 by optadata.com. The only explicit third-party copyright notice in the repo.
├─ ref-125 / ref-128 / ref-129 .xml71drop opta data's reference documents, lifted from a support ticket. ref-129 is Microsoft BC's real production payload — a third party's output, in our repo.
└─ ours-S07001-20260813.xml92review Our own capture, "verbatim from the odoo log". Ours to keep — grep it for patient names and insurance numbers before it moves anywhere.
docs/guides/*.pdf  2 files7.6 MBdrop from ship opta data's technical spec (1.16 MB, filename still carrying the browser's (1)) and a 6.4 MB machine translation of it — a derivative work of a third party's document. Move both to an internal reference repo.
docs/**.md  10 files~80 KBkeep Our own writing. Update, don't discard.
TOTAL3 9301 382 tests kept · 1 262 rewritten · ~200 moved to a driver · 849 dropped from the shipped module

New modules

Three drivers, identical shape, each depending on base and nothing else. Small on purpose — if a driver file starts growing, something domain-shaped has leaked into it.

FileEst.VerdictContents
maptara_driver_soap/~260new 1 consumer. Earns its place on the test seam, not on reuse — constructing the client today fetches a WSDL, which is why nothing tests payload assembly.
├─ __manifest__.py~20newdepends: ['base'] · external_dependencies: {'python': ['zeep']} — declared honestly for once
├─ services/connection.py~60newConnectionConfig — plain Python. host · user · secret · timeout · retries · endpoint resolution (env beats DB param, never defaults)
├─ services/soap_driver.py~130liftedFrom egeko_request.py: WSDL cache, client/transport construction, session lifecycle, logging plugin. Plus the timeout and retry fixes.
└─ tests/test_soap_driver.py~50newOffline. No WSDL fetch, no database.
maptara_driver_sftp/~230new 2 consumers. Net new — paramiko, pysftp and sftp appear nowhere in the repo today. connect · put · list · get · archive, plus a local-directory dry run: azhDirekt has no test environment, so that dry run is the only pre-production test it will ever have.
maptara_driver_rest/~200new 3–4 consumers — the common case, and the one to get right. Generalised from maptara_vdms_connector/services/client.py, which already has a token cache with a 60 s refresh margin, 3 retries with exponential backoff on 5xx, one re-login on 401, fail-fast on 429, and generator pagination. Do not write a third HTTP client.
provider_base/models/provider_driver.py~200new The contract itself: an AbstractModel with typed operations, capability flags and NotImplementedError defaults — the pattern already proven 12× in this repo. Shaped on request/response/status/retry, not on SOAP.

Three things this map makes obvious

1 — most of it does not move

3 389 lines of tests across both modules stay as they are. With the 265 lines of frozen migrations that is 3 654 lines — 43% of the 8 588. Add Egeko's 1 070 lines of dev tools, which are not shipped code, and 55% of what looks like "the modules" is not in the refactor at all.

2 — the work is in four files

provider_base/models/maptara_provider.py (819), egeko/models/maptara_provider.py (687), egeko_request.py (575), provider_base/models/sale_order.py (508). 2 589 lines — 68% of the 3 834 runtime lines in scope. Everything else is string work.

3 — the licence risk is not code

Two manifest lines carry baotnp. 7.6 MB of a vendor's copyrighted PDFs, their 686-line DTD and a competitor's production XML carry the actual exposure — none of it Python. Flipping a licence string fixes nothing about that. And repo-wide it is 9 modules on baotnp, not 2.

The count that should decide the test strategy

Across both modules there are 195 test methods and 3 389 lines of test code, and not one of them asserts what goes on the wire. Every Egeko suite patches above the transport because constructing the client fetches a WSDL.

Meanwhile tools/ekv_body_diff.py — 630 lines that diff a captured payload against opta data's own reference documents and exit 1 on mismatch, written explicitly to gate a pipeline — is called by nothing.

So the first commit of the Egeko rewrite is not code. It is wiring that 630-line oracle into the suite and watching a deliberately misspelled wire key turn it red. Today, nothing does.

Line counts: wc -l, 2026-09-19, both module trees, excluding __pycache__. Asset sizes from find -printf. Every file:line reference is re-derivable from the surveys in .agent-work/provider-refactor/.

Internal planning document. Nothing here has been implemented.