Access control is usually bought as a security product and then attached to human resources with a CSV of badge numbers. In an Odoo estate, the same integration can be a controlled authorization pipeline with an audit trail, or a nightly export that quietly keeps a contractor authorised for six weeks after his contract ended. The difference is design, not hardware.
Access control is an authorization process that ends at a door
The lock answers whether a credential is valid this second; the ERP answers whether the person should be here at all.
- Badge issuance, zone entitlement and revocation are master-data processes with owners.
- Every manual spreadsheet step between HR and the door is a silent privilege escalation.
- Security needs evidence after an incident, and operations need speed during a shift.
- Odoo is often the only place where employee, contractor and project data meet.
- Decide explicitly which system is authoritative for each field, and write it down.
Split responsibilities along the latency line
A door decision cannot wait for a web request, and a payroll record should not be edited by a door.
- The controller owns millisecond decisions, anti-passback and offline fallback.
- Odoo owns the roster, the zone matrix, validity dates and the audit query.
- Push entitlements outward; do not ask Odoo to open doors in real time.
- Design the cached policy so the site stays secure and usable when Odoo is unreachable.
- Log the divergence: local overrides are legitimate only when they are visible later.
Model persons, credentials and zones separately
Most integrations collapse three objects into one row, and then cannot answer simple questions.
- A person - employee, contractor or visitor - may hold several credentials over time.
- A credential is a physical object with a lifecycle: issued, active, lost, revoked, replaced.
- A zone is a logical area with a policy; doors are hardware attached to it, not the policy itself.
- An entitlement links a person to a zone for a period, with a reason and an approver.
- Never store a single access flag; store the grant with its dates, or revocation becomes guesswork.
What belongs in Odoo, and what does not
The ERP is a good system of record for authorisation, and a poor place to store secrets.
- hr.employee plus a contractor model gives identity, manager and contract end date.
- A small custom entitlement model is enough: person, zone, valid from, valid to, approver, state.
- Maintenance and project records tell you who is expected on site and when.
- Avoid mirroring raw card numbers; store a token or a hashed reference instead.
- Keep photographs and biometric templates in the access system, with its own retention rules.
Push entitlements, pull events
Two directions, two different contracts, and neither should be a synchronous coupling.
- Outbound: Odoo computes the desired state per person and pushes deltas to the controller.
- Inbound: the controller streams granted, denied, held-open and forced events into a queue.
- Both directions need a stable person key that survives reorganisations and rehires.
- Batch the outbound sync every few minutes; per-click propagation is neither needed nor reliable.
- Alert on drift, especially entitlements present in the controller but absent in Odoo.
Make the event stream idempotent and replayable
Access events are the audit trail, so they must survive retries, restarts and bad afternoons.
- Give each event a controller-generated identifier and deduplicate on ingest.
- Land raw events in a staging table before projecting them into Odoo models.
- Retain raw events for the policy period, then delete on schedule rather than by accident.
- Replays must not duplicate attendance, timesheets or work-order records.
- Report lag: the age of the newest event is a better health signal than a green dashboard.
Least privilege with time, escort and expiry
Permanent access should be the exception, and every exception needs a named owner.
- Grants expire by default; a permanent grant requires an approval and a review date.
- Contractor entitlements should end with the contract, not with someone's memory.
- Time windows and escort rules belong in the policy, not on a sticky note beside the door.
- Separate can-enter from can-operate: a plant room is not an office corridor.
- Review the zone matrix quarterly; the review report is the deliverable, not the door.
The failure modes that actually cause incidents
Most access incidents are integration failures that look like human failures.
- A revoked badge still works because the controller cached it and the sync silently stopped.
- Clock drift between controller and server makes the order of events unprovable.
- Anti-passback set too strictly locks people out during a fire evacuation and re-entry.
- Tailgating is treated as a software problem when it is physical and cultural.
- A contractor whose contract expired stays in the roster because nobody closed the HR record.
Audit, privacy and the questions you will be asked
After an incident, the question is never whether the door worked; it is who was allowed in.
- Be able to answer who was entitled to zone X on a given date, from stored grants.
- Apply purpose limitation: access data serves security and safety, not performance scoring.
- Define retention per data class, and automate deletion instead of promising it.
- Access to the access system is itself privileged; log administrator changes separately.
- If biometrics are used, document the legal basis and keep templates out of the ERP.
Rollout: shadow first, then enforce
Sequence the integration so the first denials happen where they are cheap.
- Run in shadow mode: Odoo computes entitlements, the controller keeps its own list, compare daily.
- Clean the roster before enforcing, because bad identity data produces false denials.
- Enforce one zone at a time, starting with the lowest-risk door and a small population.
- Rehearse the offline scenario and the evacuation scenario explicitly, with the safety team.
- Publish a one-page exception process, or supervisors will invent their own.






