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.
text files across both modules
43% of 8 588 — tests 3 389, migrations 265
two Egeko files, and that is the whole hard part
two vendor PDFs, plus the DTD and 3 XML fixtures
Runtime 2 386 · tests 2 007 · migrations 265. Two thirds of this module is not changing.
| File | Lines | Verdict | What happens |
|---|---|---|---|
| __manifest__.py | 50 | de-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__.py | 4 | de-brand | Imports post_init_hook_egeko (:2). |
| hooks.py | 74 | de-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__.py | 4 | stays | |
| ├─ maptara_provider.py | 819 | rewrite | 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.py | 121 | de-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.py | 508 | de-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__.py | 3 | stays | |
| ├─ maptara_send_ekv_wizard.py | 784 | de-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.py | 19 | fix | Calls _send_ekv directly (:19-20), bypassing _materialise_uploads — a file on the confirm path silently never becomes a document. |
| migrations/ | 265 | frozen | 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.xml | 218 | de-brand | 6 column labels reading eGeKo KV-Nr / Egekonummer. Also drops the maptara.provider.uom section. |
| └─ sale_order_views.xml | 95 | de-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.xml | 154 | de-brand | Binds action_new_egeko_code at :44. |
| wizard/maptara_confirm_..._views.xml | 19 | stays | |
| security/ir.model.access.csv | 13 | fix | Line 9: base.group_user holds 1,1,1,1 on the model storing password and client_key. Keep read — codexa_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.js | 91 | stays | |
| i18n/de.po | 665 | regen | Every relabelled string changes its msgid. Regenerate, do not hand-edit, or the translations silently detach. |
| tests/ 8 files, 112 test methods | 2 007 | keep | 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. |
| TOTAL | 4 658 | 2 007 untouched · 265 frozen · 2 386 edited, of which most is string work |
Addon runtime 1 448 · manifest 30 · tests 1 382 · dev tools 1 070. Only 37% of the "module" is the module.
| File | Lines | Verdict | What happens |
|---|---|---|---|
| __manifest__.py | 30 | rewrite | 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__.py | 3 | fix | Imports a wizard package that contains nothing. |
| wizard/__init__.py | 1 | delete | An empty package. One line, a coding cookie, zero purpose. |
| models/ | 1 444 | ||
| ├─ __init__.py | 4 | stays | |
| ├─ egeko_request.py | 575 | split | 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.py | 687 | rewrite | 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.py | 130 | mostly moves | The endpoint-resolution pattern (env var → ir.config_parameter → refuse, never default) is promoted to the driver layer for everyone. The three named hosts stay here — they are Egeko's. |
| └─ sale_order.py | 48 | stays | One override, _get_ekv_position_lines. |
| views/res_config_settings_views.xml | 68 | adapt | 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.po | 140 | regen | |
| tests/ 10 files, 83 test methods | 1 382 | keep + 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.py | 630 | promote | 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.py | 440 | fix | Hardcodes another developer's worktree (:21) and two container paths (:44-45). |
| tools/fixtures/ | 849 | drop from ship | |
| ├─ Egeko.dtd | 686 | drop | 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 .xml | 71 | drop | 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.xml | 92 | review | 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 files | 7.6 MB | drop 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 KB | keep | Our own writing. Update, don't discard. |
| TOTAL | 3 930 | 1 382 tests kept · 1 262 rewritten · ~200 moved to a driver · 849 dropped from the shipped module |
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.
| File | Est. | Verdict | Contents |
|---|---|---|---|
| maptara_driver_soap/ | ~260 | new | 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 | ~20 | new | depends: ['base'] · external_dependencies: {'python': ['zeep']} — declared honestly for once |
| ├─ services/connection.py | ~60 | new | ConnectionConfig — plain Python. host · user · secret · timeout · retries · endpoint resolution (env beats DB param, never defaults) |
| ├─ services/soap_driver.py | ~130 | lifted | From egeko_request.py: WSDL cache, client/transport construction, session lifecycle, logging plugin. Plus the timeout and retry fixes. |
| └─ tests/test_soap_driver.py | ~50 | new | Offline. No WSDL fetch, no database. |
| maptara_driver_sftp/ | ~230 | new | 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/ | ~200 | new | 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 | ~200 | new | 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. |
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.
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.
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.
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.