- Python 95.7%
- Shell 3.5%
- Dockerfile 0.8%
| Filename | Latest commit message | Latest commit date |
|---|---|---|
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).
|
||
| addons | ||
| docs | ||
| mariadb-init | ||
| scripts | ||
| .gitignore | ||
| ACCESS.md | ||
| compose.yml | ||
| Dockerfile | ||
| README.md | ||
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_integrationis 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 theodoo-eebuild — seeACCESS.md§3c).db_access_logis verified end-to-end against a live PostgreSQL and a live MariaDB. Seedocs/.
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(andwrite:repo_issueto 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 intores.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
modifiedunix-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_dateis applied; an older one is skipped (only the TANSS id +modifiedtimestamp 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_statementson PostgreSQL,performance_schema.events_statements_summary_by_digeston 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'sdbservice does both). - MariaDB: needs
--performance-schema=ONandGRANT SELECT ON performance_schema.*for the querying user (both set up in the dev stack). - Driver: the app image installs
python3-pymysql(seeDockerfile).
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
$VARin compose files — escape shell variables in inline commands as$$var. - Odoo 19: no
numbercallfield onir.cron; search-view<group>takes nostring/expandattributes; domain python may only reference whitelisted names (time,datetime,relativedelta,now, …) — prefer relative date strings like'now -24H'. - MariaDB 11 client binary is
mariadb(nomysqlalias);/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).