Download Latest Version OpenConstructionERP_12.2.0_x64_en-US.msi (375.0 MB)
Email in envelope

Get an email when there's a new version of OpenConstructionERP

Home / v2.9.17
Name Modified Size InfoDownloads / Week
Parent folder
README.md 2026-05-06 2.7 kB
v2.9.17 -- Procurement-Finance commitments + CO budget delta + PO retry + tasks i18n source code.tar.gz 2026-05-06 458.7 MB
v2.9.17 -- Procurement-Finance commitments + CO budget delta + PO retry + tasks i18n source code.zip 2026-05-06 460.4 MB
Totals: 3 Items   919.1 MB 0

Wires two missing publisher→subscriber connections that left financial dashboards lying. Plus a concurrency fix to PO numbering and a 9-locale backfill on the tasks importer.

Procurement → Finance commitment

procurement.po.issued was published in procurement/service.py but had zero subscribersProjectBudget.committed stayed permanently 0 even when POs totalled millions. New subscriber in finance/events.py opens an isolated session, picks the budget row by (project_id, wbs_id) against the PO's first line item (falls back to oldest budget by created_at), and increments committed.

procurement.gr.confirmed now flips committed → actual: decrements committed (clamped) and increments actual by the GR value. The GR publisher now actually computes the receipt amount as Σ(quantity_received × matched po_item.unit_rate) instead of emitting only the IDs.

Change Order → Budget delta line

Approved COs previously wrote cost_impact to the single string field project.budget_estimate; ProjectBudget was never touched and EVM BAC didn't reflect approved COs. Now changeorders/service._write_budget_delta_row keys off metadata_->>'change_order_id' == co.id, sets original_budget=0, revised_budget=delta, currency from co.currency → project default → EUR. Idempotent on re-approve. Wrapped in try/except so a budget-write failure logs a warning but doesn't roll back the CO approval.

PO numbering race

procurement/service.create_po previously picked MAX(po_number) LIKE 'PO-%' and inserted; concurrent creates collided with HTTP 500. Now mirrors the change-order retry pattern: 5 attempts, refetch MAX + retry on IntegrityError. Auto-generated numbers loop; user-supplied numbers bubble up as 409 instead of looping. Backed by a new (project_id, po_number) unique constraint; migration v2917_po_number_unique.py is inspector-guarded and de-duplicates pre-existing collisions before applying.

Tasks importer foreign-language headers

tasks/router.py:_TASK_COLUMN_MAP previously mapped only EN/DE Excel/CSV column headers. Russian "Название", Spanish "Título", Japanese "タイトル" etc. silently dropped on import. Added 81 entries across 9 locales (ru/fr/es/it/ja/zh/pt/nl/ko) for 8 target fields. Map grew 19 → 100. Lookup is case-insensitive; CJK headers match verbatim.

See [CHANGELOG.md](https://github.com/datadrivenconstruction/OpenConstructionERP/blob/v2.9.17/CHANGELOG.md#2917 for the full list.

Source: README.md, updated 2026-05-06