defmodule DaProductApp.Partners.Partner do @moduledoc """ Partner schema representing merchant acquirers/aggregators. Partners are entities that: - Enroll merchants under them - Generate QR codes for merchants - Handle merchant settlements - Provide merchant services """ use Ecto.Schema import Ecto.Changeset @primary_key {:id, :binary_id, autogenerate: true} @foreign_key_type :binary_id schema "partners" do field :partner_code, :string # Unique partner identifier (e.g., "RAZORPAY", "PAYU") field :partner_name, :string # Display name (e.g., "Razorpay Business") field :partner_type, :string # "AGGREGATOR", "ACQUIRER", "PROCESSOR" field :api_endpoint, :string # Partner's API base URL field :api_key, :string # Partner API key for PSP authentication (new) field :api_secret, :string # Partner API secret (encrypted) field :webhook_url, :string # Partner's webhook for callbacks field :webhook_secret, :string # Webhook signature verification field :settlement_account, :string # Partner's settlement account details field :commission_rate, :decimal # Commission % charged by partner field :status, :string, default: "ACTIVE" # "ACTIVE", "SUSPENDED", "INACTIVE" field :contact_email, :string field :contact_phone, :string field :corridor, :string # International corridor: "SINGAPORE", "UAE", "USA", "DOMESTIC" field :base_currency, :string # Partner's base currency: "SGD", "AED", "USD", "INR" field :ip_whitelist, :string # JSON array of allowed IPs field :rate_limit_per_minute, :integer, default: 100 field :last_used_at, :utc_datetime field :api_key_expires_at, :utc_datetime field :onboarded_at, :utc_datetime field :last_reconciled_at, :utc_datetime has_many :merchants, DaProductApp.Partners.Merchant has_many :transactions, DaProductApp.Transactions.Transaction timestamps(type: :utc_datetime) end def changeset(partner, attrs) do partner |> cast(attrs, [ :partner_code, :partner_name, :partner_type, :api_endpoint, :api_key, :api_secret, :webhook_url, :webhook_secret, :settlement_account, :commission_rate, :status, :contact_email, :contact_phone, :corridor, :base_currency, :ip_whitelist, :rate_limit_per_minute, :last_used_at, :api_key_expires_at, :onboarded_at, :last_reconciled_at ]) |> validate_required([:partner_code, :partner_name, :partner_type]) |> validate_inclusion(:partner_type, ["AGGREGATOR", "ACQUIRER", "PROCESSOR"]) |> validate_inclusion(:status, ["ACTIVE", "SUSPENDED", "INACTIVE"]) |> validate_inclusion(:corridor, ["SINGAPORE", "UAE", "USA", "DOMESTIC"]) |> validate_inclusion(:base_currency, ["SGD", "AED", "USD", "INR"]) |> validate_format(:contact_email, ~r/@/) |> validate_number(:rate_limit_per_minute, greater_than: 0, less_than: 10000) |> unique_constraint(:partner_code) |> unique_constraint(:api_key) end @doc """ Changeset for API key generation/rotation """ def api_key_changeset(partner, attrs) do partner |> cast(attrs, [:api_key, :api_secret, :api_key_expires_at, :status]) |> validate_required([:api_key, :api_secret]) |> unique_constraint(:api_key) end end