The owned_organisations module in src/cluster_erp/modules/owned_organisations/ holds the organisations that the company itself owns, such as a head office and branches, with their department trees. It also holds the company-level employee record of each person and the assignments that place a person in an organisation, a department, and a position. Every organisation and every employee is a role of a party; see party unification.
At a glance¶
| Item | Value | Source |
|---|---|---|
| Package | src/cluster_erp/modules/owned_organisations/ |
folder |
| Module class | Module |
src/cluster_erp/modules/owned_organisations/module.py:18 |
name / version |
owned_organisations / 0.1.0 |
src/cluster_erp/modules/owned_organisations/module.py:19-25 |
| API prefix | /api/v1/owned_organisations (ModuleBase.api_prefix) |
src/cluster_erp/core/module_base.py:37-38 |
| Sub-modules | 3: organisations, departments, employees |
folder listing |
| Tables | 4: owned_orgs_organisations, owned_orgs_departments, owned_orgs_employees, owned_orgs_assignments |
src/cluster_erp/modules/owned_organisations/models.py:1-17 |
| Entities in metadata | 4: organisation, department, employee, assignment |
src/cluster_erp/modules/owned_organisations/module.py:443-448 |
| Routes | 28 route decorators in the package | grep for @router. |
| Web app presence | Part of the catalogue app parties, as the Organisations tab of the parties list |
src/cluster_erp/modules/app_store/catalog.json (entry parties), src/cluster_erp/modules/parties/module.py:589-597 |
| Desktop presence | Generic widgets only; no folder in src/cluster_erp/desktop/modules/ |
folder |
What the module does¶
- Records each owned organisation with a name, a description, a founding date, a head-office flag, and a default IANA time zone (
src/cluster_erp/modules/owned_organisations/organisations/models.py:21-51). - Records departments as a tree inside an organisation (
src/cluster_erp/modules/owned_organisations/departments/models.py:16-39). - Keeps one company-level employee record per person, with employment, statutory, diet, emergency-contact, and manager fields (
src/cluster_erp/modules/owned_organisations/employees/models.py:18-66). - Places an employee in one or more organisations through assignments with a position, an employment type, and dates (
src/cluster_erp/modules/owned_organisations/employees/models.py:69-108). - Answers other modules' questions about the head office, the company time zone, the directory, and a manager's team (
src/cluster_erp/modules/owned_organisations/module.py:90-99).
Sub-modules¶
| Sub-module | Purpose | Main entities | Router | Source |
|---|---|---|---|---|
organisations |
Owned organisations | OwnedOrganisation |
/api/v1/owned_organisations/organisations |
src/cluster_erp/modules/owned_organisations/organisations/routes.py:28 |
departments |
Department trees | Department |
/api/v1/owned_organisations/departments |
src/cluster_erp/modules/owned_organisations/departments/routes.py:21 |
employees |
Employees and assignments | Employee, Assignment |
/api/v1/owned_organisations/employees/, /api/v1/owned_organisations/assignments/ |
src/cluster_erp/modules/owned_organisations/employees/routes.py:35 |
The three routers sit under one module router that depends on the app entitlement (src/cluster_erp/modules/owned_organisations/module.py:49-54). All four metadata entities are declared in organisations/metadata.py (src/cluster_erp/modules/owned_organisations/module.py:427-432).
Data model¶
| Entity | Table | Key fields | Notes | Source |
|---|---|---|---|---|
OwnedOrganisation |
owned_orgs_organisations |
code, party_id, name, description, is_headquarters, founded_date, is_active, default_timezone, extra |
one live organisation per party (partial unique index) | src/cluster_erp/modules/owned_organisations/organisations/models.py:21-60 |
Department |
owned_orgs_departments |
code, organisation_id, name, description, parent_id, is_active, extra |
parent_id points at another department |
src/cluster_erp/modules/owned_organisations/departments/models.py:16-39 |
Employee |
owned_orgs_employees |
code, party_id, employee_number, hire_date, tax_no, national_id_no, social_security_no, blood_group, diet_preferences, diet_note, emergency contact fields, manager_party_id, is_active, extra |
one live employee per party | src/cluster_erp/modules/owned_organisations/employees/models.py:18-66 |
Assignment |
owned_orgs_assignments |
code, employee_id, party_id, organisation_id, department_id, position, employment_type, start_date, end_date, is_active, extra |
party_id copies the employee's party |
src/cluster_erp/modules/owned_organisations/employees/models.py:69-108 |
party_id and manager_party_id are plain UUID columns, not foreign keys into the parties tables (src/cluster_erp/modules/owned_organisations/organisations/models.py:41, src/cluster_erp/modules/owned_organisations/employees/models.py:59-61). The model comment of OwnedOrganisation states that the partial unique index lets a user deactivate an organisation and open a new one for the same party (src/cluster_erp/modules/owned_organisations/organisations/models.py:38-40).
Screens and metadata¶
The module declares no sidebar group of its own; its organisations are a tab of the parties list (src/cluster_erp/modules/owned_organisations/module.py:440-442, src/cluster_erp/modules/parties/module.py:589-597). Organisation, employee, and assignment declare IdentityMeta, so opening one opens the party card (src/cluster_erp/modules/owned_organisations/organisations/metadata.py:53, src/cluster_erp/modules/owned_organisations/organisations/metadata.py:355, src/cluster_erp/modules/owned_organisations/organisations/metadata.py:590). The organisation detail has the tabs General, Departments (a tree), and Employees (the organisation's assignments) (src/cluster_erp/modules/owned_organisations/organisations/metadata.py:90-110). Departments use a tree view under their organisation (src/cluster_erp/modules/owned_organisations/organisations/metadata.py:252-281). Six employee fields carry permission="employee.read_sensitive": tax number, national id, social security number, blood group, diet preferences, and diet note (src/cluster_erp/modules/owned_organisations/organisations/metadata.py:469-549).
Status and actions¶
The module declares no ActionMeta (a grep for ActionMeta( in the package finds none). Records carry an is_active flag and no status field (src/cluster_erp/modules/owned_organisations/organisations/models.py:46, src/cluster_erp/modules/owned_organisations/employees/models.py:62, src/cluster_erp/modules/owned_organisations/employees/models.py:102).
| Action | Label | Condition | Endpoint | Permission | Source |
|---|---|---|---|---|---|
| none | none | none | none | none | src/cluster_erp/modules/owned_organisations/organisations/metadata.py |
Business rules¶
- An organisation created without a
party_idgets one throughEnsurePartyForOrganisation; if no party comes back, the create fails (src/cluster_erp/modules/owned_organisations/organisations/services.py:74-94). default_timezonemust be a known IANA zone name or empty (src/cluster_erp/modules/owned_organisations/organisations/schemas.py:13-19).- Creating an employee for a party that already has a live employee record returns the existing record (
src/cluster_erp/modules/owned_organisations/employees/services.py:63-66). - An employee needs an emergency contact name and phone on create (
src/cluster_erp/modules/owned_organisations/employees/schemas.py:47-49). - An assignment may name the party instead of the employee; the service then finds or creates the person's employee record (
src/cluster_erp/modules/owned_organisations/employees/services.py:194-203,src/cluster_erp/modules/owned_organisations/employees/services.py:78-86). - Employment types are
full_time,part_time,contract,intern, andfreelance; blood groups are the eight ABO and Rh groups (src/cluster_erp/modules/owned_organisations/employees/schemas.py:11-29). - Fields gated by
employee.read_sensitiveare removed from responses and ignored on input for a caller without the code (src/cluster_erp/modules/owned_organisations/employees/routes.py:57-78); see field and row access. - Codes come from the yearly sequences
owned_organisation,department,employee, andassignment(src/cluster_erp/modules/owned_organisations/organisations/services.py:71,src/cluster_erp/modules/owned_organisations/departments/services.py:46,src/cluster_erp/modules/owned_organisations/employees/services.py:89,src/cluster_erp/modules/owned_organisations/employees/services.py:214).
Events and queries¶
The module consumes 10 contracts and produces 5, counted as on the parties module page.
| Direction | Contract class | Handler or emitter | Source |
|---|---|---|---|
| emits | OrganisationCreated, OrganisationUpdated |
OwnedOrganisationService.create, .update |
src/cluster_erp/modules/owned_organisations/organisations/services.py:103-110, src/cluster_erp/modules/owned_organisations/organisations/services.py:138-145 |
| emits | PartyRoleSet |
EmployeeService._insert, .delete |
src/cluster_erp/modules/owned_organisations/employees/services.py:93-100, src/cluster_erp/modules/owned_organisations/employees/services.py:132-139 |
| emits | EmployeeAdded |
AssignmentService.create |
src/cluster_erp/modules/owned_organisations/employees/services.py:232-239 |
| queries | EnsurePartyForOrganisation |
OwnedOrganisationService.create |
src/cluster_erp/modules/owned_organisations/organisations/services.py:77-84 |
| answers query | GetOrganisationById |
_handle_get_org |
src/cluster_erp/modules/owned_organisations/module.py:90, src/cluster_erp/modules/owned_organisations/module.py:228-249 |
| answers query | GetHeadquartersOrganisation |
_handle_get_headquarters |
src/cluster_erp/modules/owned_organisations/module.py:93, src/cluster_erp/modules/owned_organisations/module.py:251-277 |
| answers query | GetCompanyDefaultTimezone |
_handle_get_company_default_timezone |
src/cluster_erp/modules/owned_organisations/module.py:94-96, src/cluster_erp/modules/owned_organisations/module.py:279-343 |
| answers query | GetPartyForEmployee |
_handle_get_party_for_employee |
src/cluster_erp/modules/owned_organisations/module.py:97, src/cluster_erp/modules/owned_organisations/module.py:101-126 |
| answers query | ListDirectoryEmployees |
_handle_list_directory_employees |
src/cluster_erp/modules/owned_organisations/module.py:98, src/cluster_erp/modules/owned_organisations/module.py:128-195 |
| answers query | GetTeamPartyIds |
_handle_get_team_party_ids |
src/cluster_erp/modules/owned_organisations/module.py:99, src/cluster_erp/modules/owned_organisations/module.py:197-226 |
| subscribes | PartyDeleted, RecordActivated |
_on_party_deleted, _on_record_activated |
src/cluster_erp/modules/owned_organisations/module.py:70-71, src/cluster_erp/modules/owned_organisations/module.py:348-420 |
| subscribes | CollectSubjectData, AnonymiseSubject |
collect_subject_data, anonymise_subject |
src/cluster_erp/modules/owned_organisations/module.py:81-88 |
Three answers carry rules worth knowing:
- The head office is the organisation flagged
is_headquarters, else the oldest live one (src/cluster_erp/modules/owned_organisations/module.py:251-277). - The company time zone is the given organisation's own zone, then the head office's, then any active organisation's, ordered by head-office flag and id. A warning is logged when several organisations are flagged as head office (
src/cluster_erp/modules/owned_organisations/module.py:279-343). The working time page explains where the zone is used. - A manager's team is every live, active employee below the manager in the
manager_party_idchain, found with a recursive query that stops on cycles (src/cluster_erp/modules/owned_organisations/module.py:197-226).
Permissions¶
| Permission key | Used by | Source |
|---|---|---|
organisation.read, .create, .update, .delete, .bulk_delete |
organisation routes | src/cluster_erp/modules/owned_organisations/organisations/routes.py:49-125 |
department.read, .create, .update, .delete, .bulk_delete |
department routes | src/cluster_erp/modules/owned_organisations/departments/routes.py:39-127 |
employee.read, .create, .update, .delete, .bulk_delete |
employee routes | src/cluster_erp/modules/owned_organisations/employees/routes.py:48-132 |
employee.read_sensitive |
field gate on six employee fields | src/cluster_erp/modules/owned_organisations/organisations/metadata.py:469-549 |
assignment.read, .create, .update, .delete, .bulk_delete |
assignment routes | src/cluster_erp/modules/owned_organisations/employees/routes.py:149-268 |
Privacy, retention, and history¶
privacy_handlers.py reports the employment records a person holds. It anonymises identifiers, health data, and emergency-contact fields only when the request carries include_employment_records, because employment records have statutory retention duties, as its docstring states (src/cluster_erp/modules/owned_organisations/privacy_handlers.py:1-9). When a party is deactivated, its employee records are soft-deleted with the reason party_deactivated; reactivating the party restores exactly those rows (src/cluster_erp/modules/owned_organisations/module.py:348-420). See privacy and data-subject requests and change history.
Analytics facts¶
This module has no analytics_facts.py.
Settings and reference data¶
The module has no settings section and seeds nothing at start-up (src/cluster_erp/modules/owned_organisations/module.py:31-33). Organisations, departments, employees, and assignments accept tenant-defined fields in extra (src/cluster_erp/modules/owned_organisations/organisations/metadata.py:36-48); see tenant fields.
Tests¶
Found by a grep for modules.owned_organisations in tests/ and by file name in web-client/.
| Kind | File | Covers |
|---|---|---|
| pytest | tests/test_party_form_contract.py |
the employee metadata used by the party form |
| pytest | tests/test_data_map_package2.py |
the sensitive-field gate on the employee card |
| e2e | web-client/_e2e_employee_field_gate.mjs |
the field gate against the live server |
| e2e | web-client/_e2e_parties.mjs |
the organisation detail inside the parties app |
Discrepancies¶
Terms introduced¶
| Term | Code identifier | Definition | Turkish term | Source |
|---|---|---|---|---|
| owned organisation | OwnedOrganisation |
An organisation the company itself owns, such as a head office or a branch. | Kuruluş | src/cluster_erp/modules/owned_organisations/organisations/models.py:21 |
| employee record | Employee |
The company-level personnel record of a person. | Çalışan kaydı | src/cluster_erp/modules/owned_organisations/employees/models.py:18 |
| assignment | Assignment |
A placement of an employee in an organisation, department, and position for a period. | Görevlendirme | src/cluster_erp/modules/owned_organisations/employees/models.py:69 |
| head office | is_headquarters |
The organisation flagged as the company's head office. | Merkez | src/cluster_erp/modules/owned_organisations/organisations/models.py:44 |
Related pages¶
- Modules index
- Parties module
- Party unification
- Working time
- API reference for this module
- Related material, historical, not verified: the in-tree note
src/cluster_erp/modules/owned_organisations/docs/how-to.md. It describes employee routes per organisation and department and anorganisation_idon the employee, which the code no longer has (src/cluster_erp/modules/owned_organisations/employees/routes.py:146-198).
Verified against commit 92f8051 on 2026-11-13.