Factorizer/Cluster ERP WikiCluster ERP Türkçe
Home / Business modules

Module

Parties module (parties)

Module page for parties, the single card for every person and organisation, with addresses, channels, spoken languages, and country reference data.

The parties module in src/cluster_erp/modules/parties/ keeps one record, the party (Party, a person or an organisation the company deals with), for everyone the business knows. Customers, suppliers, employees, and owned organisations are roles of a party, not separate cards; that model is explained on party unification. The module also holds addresses, communication channels, spoken languages, and the country, address-level, and channel-type reference data. This page is the module overview; each sub-module has its own reference page.

At a glance

Item Value Source
Package src/cluster_erp/modules/parties/ folder
Module class Module src/cluster_erp/modules/parties/module.py:22
name / version parties / 0.1.0 src/cluster_erp/modules/parties/module.py:23-29
API prefix /api/v1/parties (ModuleBase.api_prefix) src/cluster_erp/core/module_base.py:37-38
Sub-modules 5: parties, addresses, communication_channels, person_languages, settings folder listing
Tables 11 (__tablename__ count in the package) src/cluster_erp/modules/parties/models.py:1-33
Entities in metadata 8: party, address, communication_channel, person_language, country, address_level, address_level_value, channel_type src/cluster_erp/modules/parties/module.py:642-651
Routes 53 route decorators in the package, plus 4 in server/routes/party_composite.py and server/routes/party_roles.py grep for @router.
Web app presence Catalogue app parties, which covers the modules parties, owned_organisations, and crm src/cluster_erp/modules/app_store/catalog.json (entry parties)
Desktop presence Generic widgets only; no folder in src/cluster_erp/desktop/modules/ folder

What the module does

  • Keeps one party card per person or organisation, with a yearly business code, a type, a display name, tax fields, notes, and an active flag (src/cluster_erp/modules/parties/parties/models.py:18-55).
  • Records the roles a party plays as three flags, is_customer, is_supplier, and is_employee, which other modules keep in step over the EventBus (src/cluster_erp/modules/parties/module.py:168-195).
  • Stores structured addresses whose levels come from country reference data; see addresses.
  • Stores communication channels such as e-mail and phone; see communication channels.
  • Stores the languages a person speaks; see person languages.
  • Seeds the ISO country list and the default channel types at start-up (src/cluster_erp/modules/parties/module.py:37-74); see settings and reference data.
  • Holds a profile photo per party in the shared attachment store (src/cluster_erp/modules/parties/parties/routes.py:153-249).

Sub-modules

Sub-module Purpose Main entities Router Source
parties Party card, individual and organisation details, photo Party, Individual, OrganisationInfo /api/v1/parties (module root) src/cluster_erp/modules/parties/parties/routes.py:28
addresses Structured addresses of a party Address, AddressComponent /api/v1/parties/{party_id}/addresses, /api/v1/parties/addresses/... src/cluster_erp/modules/parties/addresses/routes.py:21
communication_channels Channel types and a party's channels ChannelType, CommunicationChannel /api/v1/parties/{party_id}/channels, /api/v1/parties/settings/channel-types/ src/cluster_erp/modules/parties/communication_channels/routes.py:27
person_languages Languages a party speaks PersonLanguage /api/v1/parties/{party_id}/languages src/cluster_erp/modules/parties/person_languages/routes.py:19
settings Countries, address levels, address-level values Country, AddressLevel, AddressLevelValue /api/v1/parties/settings src/cluster_erp/modules/parties/settings/routes.py:30

All five routers are included under one module router, settings first, and the whole router depends on the parties app entitlement (src/cluster_erp/modules/parties/module.py:96-103). Two more routers with the same prefix live in the server layer: guided creation (POST /api/v1/parties/composite) and role enabling (POST /api/v1/parties/{party_id}/roles/...); both are described on party unification.

Data model

The diagram shows the eleven tables of the module and their foreign keys.

erDiagram
 Party ||--o| Individual : "party_id"
 Party ||--o| OrganisationInfo : "party_id"
 Party ||--o{ Address : "party_id"
 Party ||--o{ CommunicationChannel : "party_id"
 Party ||--o{ PersonLanguage : "party_id"
 Address ||--o{ AddressComponent : "address_id"
 Country ||--o{ Address : "country_id"
 Country ||--o{ AddressLevel : "country_id"
 AddressLevel ||--o{ AddressLevelValue : "level_id"
 AddressLevelValue ||--o{ AddressComponent : "level_value_id"
 ChannelType ||--o{ CommunicationChannel : "channel_type_id"

In prose: a Party has at most one live Individual row and at most one live OrganisationInfo row, and any number of addresses, channels, and spoken languages. An Address belongs to a Country and is made of AddressComponent rows, each pointing at an AddressLevel and an AddressLevelValue of that country. A CommunicationChannel has a ChannelType.

Entity Table Key fields Notes Source
Party parties_parties code, party_type, display_name, tax_id, tax_office, is_customer, is_supplier, is_employee, photo_attachment_id, extra code unique; extra holds tenant-defined fields src/cluster_erp/modules/parties/parties/models.py:18-55
Individual parties_individuals party_id, first_name, last_name, middle_name, title, date_of_birth, gender one live row per party src/cluster_erp/modules/parties/parties/models.py:58-82
OrganisationInfo parties_organisation_info party_id, legal_name, trade_name, registration_number, industry one live row per party src/cluster_erp/modules/parties/parties/models.py:85-105
Address parties_addresses code, party_id, country_id, address_type, full_text, is_primary see addresses src/cluster_erp/modules/parties/addresses/models.py:16-41
AddressComponent parties_address_components address_id, address_level_id, level_value_id src/cluster_erp/modules/parties/addresses/models.py:44-65
ChannelType parties_channel_types code, name, translations, icon, validation_pattern code and name unique among live rows src/cluster_erp/modules/parties/communication_channels/models.py:15-38
CommunicationChannel parties_communication_channels code, party_id, channel_type_id, value, is_primary src/cluster_erp/modules/parties/communication_channels/models.py:41-59
PersonLanguage parties_person_languages party_id, language, proficiency_level src/cluster_erp/modules/parties/person_languages/models.py:15-29
Country parties_countries code, code_alpha3, numeric_code, name, translations, phone_code three codes unique among live rows src/cluster_erp/modules/parties/settings/models.py:12-49
AddressLevel parties_address_levels code, country_id, level_order, name, is_required level_order unique per country among live rows src/cluster_erp/modules/parties/settings/models.py:52-80
AddressLevelValue parties_address_level_values code, level_id, parent_id, value, postal_code unique per level, value, and parent among live rows src/cluster_erp/modules/parties/settings/models.py:83-112

Every entity derives from BaseModel, so rows carry a ULID primary key, audit columns, and soft-delete columns; see base model and ids and soft delete and deactivation.

Screens and metadata

get_metadata declares one sidebar group Parties (Turkish Taraflar) with four sections (src/cluster_erp/modules/parties/module.py:557-641):

  • Parties, a tabbed list with two entity tabs: the party list and the organisation list of owned_organisations (Turkish Kuruluşlar) (src/cluster_erp/modules/parties/module.py:570-599).
  • Addresses and Communication Channels, two lists that use the list_all endpoints and are hidden from the tab bar (src/cluster_erp/modules/parties/module.py:603-626).
  • Settings, with the tabs country, address_level, and channel_type (src/cluster_erp/modules/parties/module.py:627-637).

The party list has the columns code, name, type, tax id, active, and created, and two filters, Type and Role (src/cluster_erp/modules/parties/parties/metadata.py:440-508). The party detail has the tabs General, Addresses, Communication Channels, Spoken Languages, and Working Calendar; the last one is a custom widget of the calendars module (src/cluster_erp/modules/parties/parties/metadata.py:509-544). Role sections appear on the same card through five FacetMeta entries (src/cluster_erp/modules/parties/parties/metadata.py:550-763). The party card also declares guided creation, documents on create, tenant-field buckets, the quick actions call, message, and mail, and a photo (src/cluster_erp/modules/parties/parties/metadata.py:313-378). The web app renders these generically; see generic detail and generic form.

Status and actions

A party has no status field; it has an is_active flag (src/cluster_erp/modules/parties/parties/models.py:32). The module declares six ActionMeta entries (counted with grep "ActionMeta(" in the package).

Action Label Condition Endpoint Permission Source
enable_customer_role Enable Customer Role is_customer is false POST /{id}/roles/customer customer.create src/cluster_erp/modules/parties/parties/metadata.py:394-408, src/cluster_erp/server/routes/party_roles.py:58-77
enable_supplier_role Enable Supplier Role is_supplier is false POST /{id}/roles/supplier supplier.create src/cluster_erp/modules/parties/parties/metadata.py:409-423, src/cluster_erp/server/routes/party_roles.py:80-99
enable_employee_role Enable Employee Role is_employee is false POST /{id}/roles/employee employee.create src/cluster_erp/modules/parties/parties/metadata.py:424-438, src/cluster_erp/server/routes/party_roles.py:102-123
update_from_internet (country) Update from Internet none (global) POST /settings/countries/update-from-internet country.create src/cluster_erp/modules/parties/settings/metadata.py:34-43, src/cluster_erp/modules/parties/settings/routes.py:55-62
seed_address_levels (country) Seed Address Levels none (single record) POST /settings/countries/{id}/seed-address-levels country.seed src/cluster_erp/modules/parties/settings/metadata.py:44-53, src/cluster_erp/modules/parties/settings/routes.py:133-146
seed_defaults (channel type) Seed Defaults none (global) POST /settings/channel-types/seed-defaults channel_type.seed src/cluster_erp/modules/parties/settings/metadata.py:383-392, src/cluster_erp/modules/parties/communication_channels/routes.py:35-41

Business rules

  • A new party gets its code from the yearly sequence party (src/cluster_erp/modules/parties/parties/services.py:116); see base model and ids.
  • The list search matches the display name, the code, and searchable tenant fields (src/cluster_erp/modules/parties/parties/services.py:64-73).
  • The role filter reads the three role flags (src/cluster_erp/modules/parties/parties/services.py:55-61).
  • Create does not copy is_customer, is_supplier, or is_employee from the payload into the row (src/cluster_erp/modules/parties/parties/services.py:117-126). The flags are set by the role routes, by PartyRoleSet, and by a start-up reconciliation (src/cluster_erp/server/app.py:1002-1055).
  • An update raises the row version only when a field changed, and emits PartyUpdated with the new display name and tax id (src/cluster_erp/modules/parties/parties/services.py:197-212).
  • Deleting a party sets deleted_at and emits PartyDeleted; bulk delete emits one PartyDeleted per id (src/cluster_erp/modules/parties/parties/services.py:216-233).
  • A photo must be JPEG, PNG, WebP, or GIF, not empty, and at most 5 MB (src/cluster_erp/modules/parties/parties/routes.py:153-154, src/cluster_erp/modules/parties/parties/routes.py:196-203).

Events and queries

The module consumes 14 contracts and produces 3. Consumed means passed as the first argument of subscribe( or register_query_handler( in the package; produced means a contract class name followed by ( in the package. Producers and consumers across modules are listed on the contracts reference.

Direction Contract class Handler or emitter Source
emits PartyCreated, PartyUpdated, PartyDeleted PartyService.create, .update, .delete, .bulk_delete src/cluster_erp/modules/parties/parties/services.py:156-163, src/cluster_erp/modules/parties/parties/services.py:201-212, src/cluster_erp/modules/parties/parties/services.py:222-232
answers query GetPartyById _handle_get_party src/cluster_erp/modules/parties/module.py:117, src/cluster_erp/modules/parties/module.py:359-402
answers query GetAddressById, GetPartyPrimaryAddress _handle_get_address, _handle_get_primary_address src/cluster_erp/modules/parties/module.py:118-121
answers query GetCountryByCode _handle_get_country_by_code src/cluster_erp/modules/parties/module.py:124
answers query SearchParties _handle_search_parties src/cluster_erp/modules/parties/module.py:125
answers query EnsurePartyForOrganisation _handle_ensure_party_for_org src/cluster_erp/modules/parties/module.py:126, src/cluster_erp/modules/parties/module.py:324-357
answers query CountPartyChannels _handle_count_party_channels src/cluster_erp/modules/parties/module.py:127
answers query GetPartyContactValues party_contact_values src/cluster_erp/modules/parties/module.py:154-157
subscribes ResolveEntityEmails _handle_resolve_emails src/cluster_erp/modules/parties/module.py:128, src/cluster_erp/modules/parties/module.py:489-536
subscribes CustomerCreated _handle_customer_created src/cluster_erp/modules/parties/module.py:129, src/cluster_erp/modules/parties/module.py:445-487
subscribes PartyRoleSet _handle_party_role_set src/cluster_erp/modules/parties/module.py:130
subscribes DescribeAnalyticsFacts describe_analytics_facts src/cluster_erp/modules/parties/module.py:134-139
subscribes CollectSubjectData, AnonymiseSubject collect_subject_data, anonymise_subject src/cluster_erp/modules/parties/module.py:159-166

Permissions

Permission key Used by Source
party.read, party.create, party.update, party.delete, party.bulk_delete party routes and photo routes src/cluster_erp/modules/parties/parties/routes.py:46-237
address.read, .create, .update, .delete, .bulk_delete address routes src/cluster_erp/modules/parties/addresses/routes.py:36-160
channel.read, .create, .update, .delete, .bulk_delete channel routes src/cluster_erp/modules/parties/communication_channels/routes.py:118-228
channel_type.read, .create, .update, .delete, .bulk_delete, .seed channel-type routes src/cluster_erp/modules/parties/communication_channels/routes.py:37-100
person_language.read, .create, .update, .delete, .bulk_delete language routes src/cluster_erp/modules/parties/person_languages/routes.py:25-86
country.read, .create, .update, .delete, .bulk_delete, .seed country routes src/cluster_erp/modules/parties/settings/routes.py:41-136
address_level.*, address_level_value.* address-level routes src/cluster_erp/modules/parties/settings/routes.py:157-280
party.create; customer.create, supplier.create, employee.create guided creation; role enabling src/cluster_erp/server/routes/party_composite.py:57, src/cluster_erp/server/routes/party_roles.py:62-106

How permission codes are seeded and checked is explained on roles and permissions.

Privacy, retention, and history

privacy_handlers.py answers the privacy module's two fan-out events for this module's tables (src/cluster_erp/modules/parties/privacy_handlers.py:1-10). collect_subject_data returns a copy of the party, its individual and organisation details, addresses, channels, and languages (src/cluster_erp/modules/parties/privacy_handlers.py:69-100). anonymise_subject overwrites identifying values with the request's marker, clears tax fields and notes, scrubs personal tenant fields, deactivates the rows with the request's reason, and reports the photo attachment so that the privacy module removes the file (src/cluster_erp/modules/parties/privacy_handlers.py:234-291). GetPartyContactValues returns the e-mail addresses and phone numbers of the party's live channels (src/cluster_erp/modules/parties/privacy_handlers.py:35-66). The overall flow is on privacy and data-subject requests. Changes are captured by change history.

Analytics facts

analytics_facts.py declares one fact set, party, over parties_parties, with the dimensions party type, the three role flags, active, and created date, and one measure, party_count (src/cluster_erp/modules/parties/analytics_facts.py:17-72). The module answers DescribeAnalyticsFacts with it (src/cluster_erp/modules/parties/analytics_facts.py:75-77).

Settings and reference data

Countries, address levels, address-level values, and channel types are reference data in the database. Countries come from the ISO 3166 list of the pycountry package and are seeded at start-up; existing rows are not overwritten (src/cluster_erp/modules/parties/settings/services.py:38-86). The details are on settings and reference data.

Tests

Found by file name in web-client/ and by a grep for modules.parties in tests/.

Kind File Covers
pytest tests/test_party_form_contract.py party form metadata, schemas, error catalogue, and module wiring (8 tests)
pytest tests/test_tenant_fields.py, tests/test_tenant_field_catalog.py, tests/test_fresh_install_contract.py import party models and metadata as part of wider contracts
e2e web-client/_e2e_parties.mjs the parties app: lists, CRUD, detail sections, organisation detail
e2e web-client/_e2e_parties_supplier.mjs a supplier party created through the composite route and found by the role filter
e2e web-client/_e2e_party_form_fixes.mjs the party form against the live server
e2e web-client/_e2e_party_photo.mjs upload, change, and removal of a party photo

Discrepancies

Terms introduced

Term Code identifier Definition Turkish term Source
party Party A person or an organisation the company deals with, kept as one card. Taraf src/cluster_erp/modules/parties/parties/models.py:18
party type party_type Whether a party is an individual or an organisation. Taraf türü src/cluster_erp/modules/parties/parties/schemas.py:17-19
role flag is_customer, is_supplier, is_employee A boolean on the party that says it plays a role, kept in step with the role record. Rol src/cluster_erp/modules/parties/parties/models.py:33-35

Verified against commit 92f8051 on 2026-11-13.

Verified against commit 92f8051 · 2026-11-13