dodil/erp-brick-timesheets

DODIL ERP brick: timesheets

README.md

erp-brick-timesheets - Timesheets

Everyone fills in one week at a time against the projects and tasks they worked on, with their contracted hours and approved holidays already in it. The line manager approves with one click, the project's cost centre carries the real labour cost at the standard rate, billable hours reach the customer's order, and a correction after approval moves everything downstream by the difference.

A brick on erp-platform (erp-platform>=0.9.13,<0.10), built from the signed timesheets module spec (erp-method, version 1). Slice A: the timesheet workflow (open, book, submit, approve or return, finance's reopen as a new revision) and the cost posted to gl after approval through an outbox, plus the delivery of billable hours on the sales order's service line. Slice B (0.2.0): the billing run (a contract or manual project's month, priced from product, released to ar as one draft invoice, a correction billed as its difference), the project-hours report, the reminders (through the mail capability), and the Odoo migration (a reader port, load, reconcile, sign, discard). The permission-matrix probes and scenarios are still to come (AGENTS.md lists them).

src/brick_timesheets/
  domain/          the rules, plain Python: sheet.py (state machine, gates, approver, cost and delivery arithmetic), billing.py (the run's arithmetic), hours.py,
                   reminders.py, odoo.py (the migration's mapping), values.py, money.py
  application/     the use cases - each declared once, served as an API route AND an MCP tool (use_cases.py the timesheet; billing.py, reports.py,
                   migration.py); process.yaml = the signed workflows
  infrastructure/  the tables and repositories (tables.py), the neighbours behind one adapter (seams.py), the Odoo reader port (odoo.py)
  schema.sql, migrations/   the tables; 00002 seeds default activities and rates, 00003 the billing run, 00004 the Odoo migration
  roles.yaml       the default roles
tests/             stories, invariants, doors, seams, statement budget, process pin, schema, composition (neighbours are in-memory fakes checked against their signed specs)

Run it.

pip install -e '.[test]'
ERP_METHOD_DIR=../erp-method pytest -q       # no bucket needed; needs an erp-method checkout (the signed spec and BPMN)
BUCKET=my-bucket erp-migrate --schema src/brick_timesheets/schema.sql --brick timesheets=0.2.0
BUCKET=my-bucket HR_BASE_URL=... PROJECTS_BASE_URL=... TIME_OFF_BASE_URL=... GL_BASE_URL=... SALES_ORDER_BASE_URL=... PRODUCT_BASE_URL=... AR_BASE_URL=... uvicorn brick_timesheets.app:app

API at /docs, agents at /mcp, the process at GET /process/bpmn. hr, projects, time-off, gl and sales-order are required neighbours; product and ar are needed to bill a contract project, a mail provider (capability mail.send) to send reminders (without one they are tasks for a person), and ODOO_URL/ODOO_USER/ODOO_PASSWORD for the migration (read-only). The worker's ticks (no server-side scheduler): POST /outbox/drain, /deliveries/report, /billing-runs/tick, /billing-runs/invoices/send, /reminders/tick. Business time follows business_timezone (default Europe/London).