Odoo dev repository for module development with Hermes
  • Python 95.7%
  • Shell 3.5%
  • Dockerfile 0.8%
Find a file
Repository files (latest commit first)
Filename Latest commit message Latest commit date
Simon Huber 55ed84c109 tanss: one-way sync (TANSS -> Odoo) — v19.0.2.0.0
Decision (2026-09-29): the TANSS integration is now strictly one-way,
TANSS -> Odoo. TANSS leads on existence (field staff create companies and
contacts in the field); Odoo stays authoritative for any master-data field
it edited more recently (newer-wins conflict policy on the pull side).
There is no push back into TANSS.

Changes:
- Remove the whole push direction: push_customers(), _partner_to_customer(),
  _partner_to_employee(), _resolve_by_number(), MASTER_FIELDS, the
  push_cursor / last_push fields, push UI fields, tests/test_push.py, and
  the push endpoints in the test fake.
- sync() now runs the pull only; the 15-min cron is pull-only
  ("TANSS: Pull customers/contacts").
- Employee (contact person) pull: keep adoption + merge + conflict policy;
  the merge path now (re)records tanss_employee_id on both the TANSS-newer
  and the Odoo-newer paths (it is metadata, not master data); a deployment
  whose list carries no record id updates the already-adopted partner
  instead of creating a duplicate.
- Build compatibility (odoo-ee 19.0+e-20260924): that build's res.partner
  has no mobile / fax / first_name / last_name fields — map only phone +
  email + standard address fields and keep the unmapped TANSS values in the
  tanss_raw Json field. Field surface verified via ir.model.fields.
- Tests: 16 unit tests (was 22 with the push suite), all green on a fresh
  install run against the odoo-ee build itself (scratch DB, then dropped).
- Docs: README, ACCESS.md (new section 3c: odoo-ee deployment, URLs,
  credentials pointers, build quirks), docs/TANSS_INTEGRATION.md (decision
  banner, one-way sync strategy, updated roadmap/status), cron + sync-log
  wording.

Deployed: installed in db `odoo` on odoo-ee (dj-forge-01, container
odoo-ee-testing-app-1, /mnt/extra-addons); 15-min pull cron scheduled.
Live sync is pending a fresh ERP-role TANSS apiToken (all locally stored
JWTs are 403/expired — ~25 h validity).
2026-09-29 09:44:57 +02:00
addons tanss: one-way sync (TANSS -> Odoo) — v19.0.2.0.0 2026-09-29 09:44:57 +02:00
docs tanss: one-way sync (TANSS -> Odoo) — v19.0.2.0.0 2026-09-29 09:44:57 +02:00
mariadb-init Add db_access_log module (Postgres+MariaDB access logs) + test stack & docs 2026-09-08 20:16:09 +02:00
scripts tanss: add contacts sync engine + product plan 2026-09-01 19:17:43 +00:00
.gitignore forgejo: fix sync correctness (upsert/prune by external_id/sha, pagination, open count), add release+commit views 2026-09-01 18:04:52 +00:00
ACCESS.md tanss: one-way sync (TANSS -> Odoo) — v19.0.2.0.0 2026-09-29 09:44:57 +02:00
compose.yml Add db_access_log module (Postgres+MariaDB access logs) + test stack & docs 2026-09-08 20:16:09 +02:00
Dockerfile Add db_access_log module (Postgres+MariaDB access logs) + test stack & docs 2026-09-08 20:16:09 +02:00
README.md tanss: one-way sync (TANSS -> Odoo) — v19.0.2.0.0 2026-09-29 09:44:57 +02:00

Odoo Development Workspace

Odoo 19 application modules for DataJob, developed against an in-house Forgejo instance and the TANSS field-service system. Runs as a local Docker dev stack; a bare (no-Docker) development setup is described in docs/DEVELOPMENT.md.

For access details, credentials and test steps see ACCESS.md.

Addon Purpose
addons/forgejo_integration View Forgejo repositories, releases, commits and issues inside Odoo; create / close / reopen issues.
addons/tanss_integration One-way (TANSS → Odoo) sync of customer & contact data from TANSS into Odoo (TANSS ERP API).
addons/db_access_log Database access logs for PostgreSQL + MariaDB: live sessions + statement history, filterable views with CSV export, 5-min auto-sync cron.
addons/datahr Placeholder HR module (mostly scaffolded).

Status: Integration modules are installed, unit-tested and verified. forgejo_integration is end-to-end verified against the live Forgejo server (46 tests, 0 failures); tanss_integration (one-way, TANSS → Odoo since v19.0.2.0.0) is verified with a mocked TANSS ERP API (16 tests, 0 failures on a fresh install, including on the odoo-ee build — see ACCESS.md §3c). db_access_log is verified end-to-end against a live PostgreSQL and a live MariaDB. See docs/.


The Forgejo Integration

Lets non-developer users follow development status inside Odoo:

  • Overview of all repositories on the connected Forgejo server(s)
  • Current version (latest release) and its changelog, per repository
  • Recent commits per repository
  • Issue board (open / closed) synced from Forgejo
  • "Ask a question" wizard: create an issue on Forgejo directly from Odoo
  • Close / reopen issues from Odoo (mirrored to Forgejo)
  • Releases and Commits as first-class menus

A cron job synchronizes everything every 15 minutes; manual "Synchronize Now" buttons are available in the UI.

Data model

forgejo.server      1──<  forgejo.repo   1──<  forgejo.release
        (connection)          │  └──────<  forgejo.issue
                              │  └──────<  forgejo.commit
forgejo.issue.wizard  (transient, "Ask a question")

Each child record is keyed to its remote source by an identity field (external_id for releases/issues, sha for commits) and is scoped to its repository, so two repositories that happen to reuse the same remote id never collide.

Sync model

  • Direction: Forgejo → Odoo (read-mostly mirror). Odoo writes back issues (create / close / reopen) via the Forgejo REST API.
  • Mechanics: for every repo, releases / issues / commits are fetched and upserted (create if new, update if present) and pruned (records whose key is no longer present remotely are deleted). Commits are upserted by sha and capped at the 20 most recent (pruning disabled, since a repo may hold more than 20).
  • Pagination: issue and release listings are fully paginated (Forgejo returns ≤50 per page); the 15-minute cron keeps everything current.

Configuration

  • Settings → Forgejo Servers (manager only): base URL, an API token (preferred) or a username + password, a Test Connection button and Synchronize Now.
  • The token needs read:repo (and write:repo_issue to create / close issues). Use a dedicated service account, e.g. hermes.

Security

  • Forgejo / User – read repositories, releases, commits and issues; create and close issues.
  • Forgejo / Manager – manage server connections and force a sync.

tanss_integration

One-way customers/contacts synchronisation from TANSS into Odoo, using TANSS's purpose-built ERP API (GET /api/erp/v1/customers, apiToken authentication). A full product plan — entity mapping, leading-system choice, conflict policy, edge cases — lives in docs/TANSS_INTEGRATION.md.

Decision 2026-09-29: the sync is intentionally one-way (TANSS → Odoo, pull only). The former push direction (Odoo → TANSS) was removed in v19.0.2.0.0 — nothing is ever written back into TANSS from this module.

Sync model (contacts + contact persons)

  • Direction: pull only — customers (Customer) and contact persons (CustomerEmployee) are read from TANSS and upserted into res.partner.
  • Join key: customer_number / external_id ⇄ res.partner.id. Adopted (field-created) records get the new partner's id assigned as their join key immediately, so subsequent pulls merge in place instead of duplicating.
  • Incremental: a modified unix-timestamp cursor — only records newer than the last sync are transferred (first run: full pull).
  • Conflict policy: newer side wins per record. A TANSS change newer than the partner's write_date is applied; an older one is skipped (only the TANSS id + modified timestamp are recorded) and the decision is written to the sync log.
  • Automation: a 15-minute cron pulls over all enabled servers.

Configuration & security

  • Settings → TANSS Servers (manager): base URL + ERP token, Test Connection, Sync now (runs the pull).
  • TANSS / User – read; TANSS / Manager – manage servers, run syncs, read the sync log.

db_access_log

View database access logs for PostgreSQL and MariaDB servers directly in Odoo. Configure one or more server connections; the module captures:

  • Live sessions — who is connected right now and what they are running (pg_stat_activity / information_schema.processlist)
  • Statement history — per-query statistics: calls, rows, mean/total execution time (pg_stat_statements on PostgreSQL, performance_schema.events_statements_summary_by_digest on MariaDB)

Every capture is stored as Odoo records you can filter, group, sort and export to CSV. A built-in cron re-syncs all servers every 5 minutes. Two demo connections (local Postgres, local MariaDB) are preconfigured in the dev DB.

  • PostgreSQL: for statement history the server must load pg_stat_statements (shared_preload_libraries) and the extension must be created (the dev stack's db service does both).
  • MariaDB: needs --performance-schema=ON and GRANT SELECT ON performance_schema.* for the querying user (both set up in the dev stack).
  • Driver: the app image installs python3-pymysql (see Dockerfile).

The dev stack (compose.yml)

Service Image Purpose
app odoo:19 (Dockerfile: + python3-pymysql) Odoo server, DB odoo (admin/admin), master pw master — http://localhost:8069
db postgres:18 Odoo's PostgreSQL, pg_stat_statements preloaded
adminer adminer Visual DB browser (both DBs) — http://localhost:9080
forgejo forgejo Local git forge (repo shuber/odoo-dev) — http://localhost:3000
mariadb mariadb:11 Test MariaDB (demo db, demo/demo, root/odoo), --performance-schema=ON
mariadb-load mariadb:11 Load generator: INSERT tick into demo.load_log every 2 s

Custom addons live in ./addons, mounted at /mnt/extra-addons (matches addons_path in the image odoo.conf).

Quick start (Docker)

docker compose up -d                 # starts the whole stack

# the entrypoint injects --db_host/--db_user/--db_password, so:
docker compose exec -T app /entrypoint.sh odoo -d odoo -i <module> --stop-after-init
docker compose exec -T app /entrypoint.sh odoo -d odoo -u <module> --stop-after-init

# scaffold a new module
docker compose exec -T app /entrypoint.sh odoo scaffold <module> /mnt/extra-addons/

# interactive ORM shell (pipe a script in)
cat /tmp/script.py | docker compose exec -T app /entrypoint.sh odoo shell -d odoo

Admin login: admin / admin (see compose.yml / ACCESS.md).

Quick start (bare, no Docker)

Run Odoo 19 directly as a Python app. Full, reproducible steps for a minimal Debian 13 container (non-root, no apt) are in docs/DEVELOPMENT.md. In short:

source env.sh                        # sets PATH / LD_LIBRARY_PATH / venv
# start postgres (see docs/DEVELOPMENT.md), then:
.venv/bin/python odoo-source/odoo-bin -c odoo-dev.conf -d mydb \
    -i forgejo_integration --stop-after-init

Running the tests

Both integration modules' tests mock their HTTP layer (Forgejo / TANSS), so they need no network and run in ~1 s:

source env.sh
bash scripts/run_tests.sh all                 # both modules
bash scripts/run_tests.sh forgejo_integration # or one
bash scripts/run_tests.sh tanss_integration

Or run a single module's tests directly:

.venv/bin/python odoo-source/odoo-bin -c odoo-dev.conf -d mydb \
    -u forgejo_integration --test-enable --test-tags=forgejo_integration \
    --stop-after-init

Gotchas (learned the hard way)

  • New module files must be world-readable (chmod 644) — the container runs as uid 100, write_file-created files are 0600. Symptom: invalid module names, ignored: mymodule.
  • Docker compose interpolates $VAR in compose files — escape shell variables in inline commands as $$var.
  • Odoo 19: no numbercall field on ir.cron; search-view <group> takes no string/expand attributes; domain python may only reference whitelisted names (time, datetime, relativedelta, now, …) — prefer relative date strings like 'now -24H'.
  • MariaDB 11 client binary is mariadb (no mysql alias); /docker-entrypoint-initdb.d/ only runs on first (empty) volume init — keep setup idempotent inside the service command.

Repository layout

addons/forgejo_integration/
├── __manifest__.py
├── data/            cron + menu/action definitions
├── models/          server, repo, release, issue, commit
├── security/        groups + access rules
├── views/           server / repo / issue / release+commit views
├── wizards/         "Ask a question" (issue) wizard
└── tests/           unit tests + FakeForgejo test server

addons/tanss_integration/
├── __manifest__.py
├── data/            cron (pull only, 15 min)
├── models/          tanss_server (pull engine), tanss_sync_log, res.partner (ext.)
├── security/        groups + access rules
├── views/           server form + actions, sync-log list/form, partner form (ext.)
└── tests/           unit tests + FakeTanss test server

addons/db_access_log/
├── __manifest__.py
├── data/            sync cron (5 min)
├── models/          db_server (connection + sync engine), db_entry (log rows)
├── security/        access rules
└── views/           server list/form + entry list/form/search views

docs/
├── DEVELOPMENT.md       bare (no-Docker) dev environment
└── TANSS_INTEGRATION.md TANSS ↔ Odoo product plan (entities, leading system, sync)

scripts/
├── setup_local_pg.sh    non-root PostgreSQL from .debs
└── run_tests.sh         run the (network-free) test suites

License

LGPL-3 (per addon manifest).