Packages

phoenix_kit

1.7.202
1.7.208 1.7.207 1.7.206 1.7.205 1.7.204 1.7.203 1.7.202 1.7.201 1.7.200 1.7.199 1.7.198 1.7.197 1.7.196 1.7.194 1.7.193 1.7.192 1.7.191 1.7.190 1.7.189 1.7.187 1.7.186 1.7.185 1.7.184 1.7.183 1.7.182 1.7.181 1.7.180 1.7.179 1.7.178 1.7.177 1.7.176 1.7.175 1.7.174 1.7.173 1.7.172 1.7.171 1.7.170 1.7.169 1.7.168 1.7.167 1.7.166 1.7.165 1.7.164 1.7.162 1.7.161 1.7.160 1.7.159 1.7.157 1.7.156 1.7.155 1.7.154 1.7.153 1.7.152 1.7.151 1.7.150 1.7.149 1.7.146 1.7.145 1.7.144 1.7.143 1.7.138 1.7.133 1.7.132 1.7.131 1.7.130 1.7.128 1.7.126 1.7.125 1.7.121 1.7.120 1.7.119 1.7.118 1.7.117 1.7.116 1.7.115 1.7.114 1.7.113 1.7.112 1.7.111 1.7.110 1.7.109 1.7.108 1.7.107 1.7.106 1.7.105 1.7.104 1.7.103 1.7.102 1.7.101 1.7.100 1.7.99 1.7.98 1.7.97 1.7.96 1.7.95 1.7.94 1.7.93 1.7.92 1.7.91 1.7.90 1.7.89 1.7.88 1.7.87 1.7.86 1.7.85 1.7.84 1.7.83 1.7.82 1.7.81 1.7.80 1.7.79 1.7.78 1.7.77 1.7.76 1.7.75 1.7.74 1.7.71 1.7.70 1.7.69 1.7.66 1.7.65 1.7.64 1.7.63 1.7.62 1.7.61 1.7.59 1.7.58 1.7.57 1.7.56 1.7.55 1.7.54 1.7.53 1.7.52 1.7.51 1.7.49 1.7.44 1.7.43 1.7.42 1.7.41 1.7.39 1.7.38 1.7.37 1.7.36 1.7.34 1.7.33 1.7.31 1.7.30 1.7.29 1.7.28 1.7.27 1.7.26 1.7.25 1.7.24 1.7.23 1.7.22 1.7.21 1.7.20 1.7.19 1.7.18 1.7.17 1.7.16 1.7.15 1.7.14 1.7.13 1.7.12 1.7.11 1.7.10 1.7.9 1.7.8 1.7.7 1.7.6 1.7.5 1.7.4 1.7.3 1.7.2 1.7.1 1.7.0 1.6.20 1.6.19 1.6.18 1.6.17 1.6.16 1.6.15 1.6.14 1.6.13 1.6.12 1.6.11 1.6.10 1.6.9 1.6.8 1.6.7 1.6.6 1.6.5 1.6.4 1.6.3 1.5.2 1.5.1 1.5.0 1.4.9 1.4.8 1.4.7 1.4.6 1.4.5 1.4.4 1.4.3 1.4.2 1.4.1 1.4.0 1.3.2 1.3.1 1.3.0 1.2.10 1.2.9 1.2.8 1.2.7 1.2.5 1.2.4 1.2.2 1.2.1 1.2.0 1.1.0 1.0.0

A foundation for building Elixir Phoenix apps — SaaS, social networks, ERP systems, marketplaces, and more

Current section

Files

Jump to
phoenix_kit lib phoenix_kit migrations postgres v148.ex
Raw

lib/phoenix_kit/migrations/postgres/v148.ex

defmodule PhoenixKit.Migrations.Postgres.V148 do
@moduledoc """
V148: CRM v2 — party roles (suppliers, clients).
One table for the `phoenix_kit_crm` plugin's commercial party typing: a
polymorphic role edge that marks an existing CRM company **or** contact as
a `supplier`, `client`, or other commercial counterparty role. This is the
Odoo `supplier_rank`/`customer_rank` / SAP Business-Partner-roles property
expressed as rows: one party can hold several roles simultaneously (a
company that is both supplier and client has two rows).
## phoenix_kit_crm_party_roles
`roleable_type` + `roleable_uuid` point at `phoenix_kit_crm_companies` or
`phoenix_kit_crm_contacts` (sole-trader suppliers are contacts). The pair
carries **no FK** — a single FK cannot express the polymorphic target;
integrity lives in the CRM changesets, mirroring the `staff_person_uuid`
soft-ref precedent in V138's `interaction_parties`.
`role` is a free string (initial vocabulary: supplier/client/partner) so
the set can grow without a migration; the CRM module validates allowed
values. `valid_from`/`valid_to` give roles a lifecycle ("former supplier")
without deleting history; `is_active` is the quick filter. `metadata`
absorbs role-scoped commercial attributes (payment terms, tax id, account
number, default currency) until they stabilize into typed columns.
Design doc: `phoenix_kit_crm` `dev_docs/design/crm_v2_parties_suppliers_clients.md`.
All operations are idempotent.
"""
use Ecto.Migration
def up(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
execute("""
CREATE TABLE IF NOT EXISTS #{p}phoenix_kit_crm_party_roles (
uuid UUID PRIMARY KEY DEFAULT #{p}uuid_generate_v7(),
roleable_type VARCHAR(20) NOT NULL,
roleable_uuid UUID NOT NULL,
role VARCHAR(30) NOT NULL,
is_active BOOLEAN NOT NULL DEFAULT TRUE,
valid_from DATE,
valid_to DATE,
metadata JSONB NOT NULL DEFAULT '{}',
inserted_at TIMESTAMPTZ NOT NULL DEFAULT NOW(),
updated_at TIMESTAMPTZ NOT NULL DEFAULT NOW()
)
""")
# Guarded CHECK: roleable_type is a closed set (the polymorphic targets
# are CRM-owned tables; adding a third target is a migration anyway).
execute("""
DO $$
BEGIN
IF NOT EXISTS (
SELECT 1 FROM pg_constraint
WHERE conname = 'phoenix_kit_crm_party_roles_roleable_type_check'
AND conrelid = '#{p}phoenix_kit_crm_party_roles'::regclass
) THEN
ALTER TABLE #{p}phoenix_kit_crm_party_roles
ADD CONSTRAINT phoenix_kit_crm_party_roles_roleable_type_check
CHECK (roleable_type IN ('company', 'contact'));
END IF;
END $$;
""")
execute("""
CREATE UNIQUE INDEX IF NOT EXISTS phoenix_kit_crm_party_roles_uniq
ON #{p}phoenix_kit_crm_party_roles (roleable_type, roleable_uuid, role)
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_crm_party_roles_role_active_idx
ON #{p}phoenix_kit_crm_party_roles (role, is_active)
""")
execute("""
CREATE INDEX IF NOT EXISTS phoenix_kit_crm_party_roles_roleable_idx
ON #{p}phoenix_kit_crm_party_roles (roleable_type, roleable_uuid)
""")
execute("COMMENT ON TABLE #{p}phoenix_kit IS '148'")
end
@doc """
Rolls V148 back by dropping the party-roles table.
**Lossy rollback:** all supplier/client role assignments are lost. The
underlying companies/contacts (V138) are untouched.
"""
def down(opts) do
prefix = Map.get(opts, :prefix, "public")
p = prefix_str(prefix)
execute("DROP TABLE IF EXISTS #{p}phoenix_kit_crm_party_roles CASCADE")
execute("COMMENT ON TABLE #{p}phoenix_kit IS '147'")
end
defp prefix_str("public"), do: "public."
defp prefix_str(prefix), do: "#{prefix}."
end