PhoenixKitCRM.PartyRoles (PhoenixKitCRM v0.3.3)

Copy Markdown View Source

Context for CRM party roles — marks an existing company or contact as a supplier, client, or partner (see PhoenixKitCRM.Schemas.PartyRole).

Mutations are logged here (not in the LiveViews) because grant_role/3 and revoke_role/2 are called from both the company form and the contact form's Roles section — a single log point keeps the audit trail consistent regardless of caller, mirroring PhoenixKitCRM.Interactions. There is no live-updating tab for roles yet, so unlike interactions this context does not broadcast over PubSub.

Summary

Functions

Active roles for a batch of companies/contacts in one query — for role badges on list pages. Returns %{roleable_uuid => [role, ...]} (uuids with no active roles are absent).

Resolver entry point for the (future) Catalogue supplier facade: given a company or contact uuid, returns %{uuid, name, email, phone, website, source: :crm} if that party currently has an active supplier role, or nil otherwise (unknown uuid, inactive role, or no supplier role at all).

Grants role to a company or contact. Idempotent: granting an already-active role is a no-op (returns the existing row); granting a previously-revoked role reactivates it (clears valid_to). attrs may set :valid_from / :valid_to — never pass caller-supplied metadata here from a UI path.

Whether the company/contact currently has an active role.

Companies holding an active role, name ascending. Excludes trashed companies by default.

Contacts holding an active role, name ascending. Same options as list_companies_with_role/2.

All role rows (active and inactive) held by a company/contact, role ascending.

Revokes role from a company or contact — sets is_active false and stamps valid_to with today's date. Never deletes the row (role history is kept). A no-op if the role isn't currently held (returns {:error, :not_found}) or is already inactive.

Functions

active_roles_map(type, uuids)

@spec active_roles_map(String.t(), [UUIDv7.t()]) :: %{
  required(UUIDv7.t()) => [String.t()]
}

Active roles for a batch of companies/contacts in one query — for role badges on list pages. Returns %{roleable_uuid => [role, ...]} (uuids with no active roles are absent).

count_companies_with_role(role, opts \\ [])

@spec count_companies_with_role(
  String.t(),
  keyword()
) :: non_neg_integer()

Same filters as list_companies_with_role/2, minus :limit/:offset.

count_contacts_with_role(role, opts \\ [])

@spec count_contacts_with_role(
  String.t(),
  keyword()
) :: non_neg_integer()

Same filters as list_contacts_with_role/2, minus :limit/:offset.

get_supplier(uuid)

@spec get_supplier(UUIDv7.t() | String.t() | nil) ::
  %{
    uuid: UUIDv7.t(),
    name: String.t(),
    email: String.t() | nil,
    phone: String.t() | nil,
    website: String.t() | nil,
    source: :crm
  }
  | nil

Resolver entry point for the (future) Catalogue supplier facade: given a company or contact uuid, returns %{uuid, name, email, phone, website, source: :crm} if that party currently has an active supplier role, or nil otherwise (unknown uuid, inactive role, or no supplier role at all).

This is the contract PhoenixKitCatalogue.Catalogue.Suppliers.resolve/1 will call in Phase 2 (see the CRM v2 parties design doc, §4.3) — keep the return shape stable.

grant_role(roleable, role, attrs \\ %{}, opts \\ [])

Grants role to a company or contact. Idempotent: granting an already-active role is a no-op (returns the existing row); granting a previously-revoked role reactivates it (clears valid_to). attrs may set :valid_from / :valid_to — never pass caller-supplied metadata here from a UI path.

Pass :actor_uuid in opts so the activity log entry records who granted the role (mirrors every other logged CRM mutation).

has_role?(roleable, role)

Whether the company/contact currently has an active role.

list_companies_with_role(role, opts \\ [])

@spec list_companies_with_role(
  String.t(),
  keyword()
) :: [PhoenixKitCRM.Schemas.Company.t()]

Companies holding an active role, name ascending. Excludes trashed companies by default.

Options

  • :include_inactive — include revoked role rows too
  • :include_trashed — include trashed companies too
  • :search — name/email ILIKE match
  • :limit / :offset — pagination; no-ops when absent

list_contacts_with_role(role, opts \\ [])

@spec list_contacts_with_role(
  String.t(),
  keyword()
) :: [PhoenixKitCRM.Schemas.Contact.t()]

Contacts holding an active role, name ascending. Same options as list_companies_with_role/2.

list_roles(roleable)

All role rows (active and inactive) held by a company/contact, role ascending.

revoke_role(roleable, role, opts \\ [])

Revokes role from a company or contact — sets is_active false and stamps valid_to with today's date. Never deletes the row (role history is kept). A no-op if the role isn't currently held (returns {:error, :not_found}) or is already inactive.

Pass :actor_uuid in opts so the activity log entry records who revoked the role (mirrors every other logged CRM mutation).