A commercial party role — marks an existing CRM company or contact as a
supplier, customer, partner, or manufacturer (Odoo's
supplier_rank/customer_rank, SAP's Business-Partner roles, expressed as
rows). One party can hold several roles at once (a company that's both
supplier and customer has two rows).
manufacturer is deliberately the odd one out: in the catalogue a
"manufacturer" is usually a brand — a product-master attribute — and the
brand owner, the legal manufacturer and the supplier you actually buy from
are frequently three different companies. So the role is granted only when
a real party is known (the catalogue's link action), never by bulk-promoting
every phoenix_kit_cat_manufacturers row. Holding both supplier and
manufacturer on one party is the case this shared table exists for.
roleable_type + roleable_uuid point at phoenix_kit_crm_companies or
phoenix_kit_crm_contacts — a soft ref, no FK (a single FK can't
express the polymorphic target; integrity lives here in the changeset,
mirroring the staff_person_uuid precedent on InteractionParty).
metadata is never cast from raw UI params — the Roles checkboxes in the
company/contact forms only ever toggle role membership via
PhoenixKitCRM.PartyRoles.grant_role/3 and revoke_role/2, which don't
accept caller-supplied metadata either. Role-scoped commercial attributes
land here only through a future dedicated context function.
Summary
Functions
Changeset for controlled lifecycle transitions (revoke / reactivate) driven
by the context, not user input. Deliberately skips validate_date_range/1:
stamping valid_to = today when revoking a role whose valid_from is in the
future would otherwise fail the ordering check and turn revoke into a silent
no-op. Only is_active and valid_to are castable here.
Types
@type t() :: %PhoenixKitCRM.Schemas.PartyRole{ __meta__: term(), inserted_at: DateTime.t() | nil, is_active: boolean(), metadata: map(), role: String.t() | nil, roleable_type: String.t() | nil, roleable_uuid: UUIDv7.t() | nil, updated_at: DateTime.t() | nil, uuid: UUIDv7.t() | nil, valid_from: Date.t() | nil, valid_to: Date.t() | nil }
Functions
@spec changeset(t() | Ecto.Changeset.t(t()), map()) :: Ecto.Changeset.t(t())
@spec lifecycle_changeset(t() | Ecto.Changeset.t(t()), map()) :: Ecto.Changeset.t(t())
Changeset for controlled lifecycle transitions (revoke / reactivate) driven
by the context, not user input. Deliberately skips validate_date_range/1:
stamping valid_to = today when revoking a role whose valid_from is in the
future would otherwise fail the ordering check and turn revoke into a silent
no-op. Only is_active and valid_to are castable here.
@spec roleable_types() :: [String.t()]
@spec roles() :: [String.t()]