A commercial party role — marks an existing CRM company or contact as a
supplier, client, or partner (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 client has two
rows).
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()]