Accrue.Billing.PaymentMethodActions (accrue v0.3.1)

Copy Markdown View Source

Phase 3 Plan 06 payment method write surface (BILL-23, BILL-25).

Ships three public entry points, all exposed via defdelegate on Accrue.Billing:

  • attach_payment_method/3 — attaches a processor-side payment method to a customer, with fingerprint dedup (BILL-23). If an existing PaymentMethod row for the same (customer_id, fingerprint) exists, the processor-side duplicate is detached and the existing row is returned with existing?: true. A concurrent race that slips past the application-level check hits the accrue_payment_methods_customer_fingerprint_idx partial unique index and is rescued via Ecto.ConstraintError.
  • detach_payment_method/2 — detaches on the processor and deletes the local row.
  • set_default_payment_method/3 — asserts pm.customer_id == customer.id (BILL-25, strict attachment check) and raises Accrue.Error.NotAttached otherwise. Never silently wires a foreign PM as a customer default.

Summary

Functions

Attaches a processor-side payment method to a customer with fingerprint dedup (BILL-23). Returns {:ok, %PaymentMethod{}}; the existing?: true virtual flag is set when dedup hit an existing row.

Detaches a payment method from its customer on the processor and deletes the local row in the same transaction.

Sets a payment method as the customer's default. Raises Accrue.Error.NotAttached if pm.customer_id != customer.id (BILL-25 strict attachment check — never silently wires a foreign PM as default).

Functions

attach_payment_method(customer, pm_processor_id, opts \\ [])

@spec attach_payment_method(Accrue.Billing.Customer.t(), String.t(), keyword()) ::
  {:ok, Accrue.Billing.PaymentMethod.t()} | {:error, term()}

Attaches a processor-side payment method to a customer with fingerprint dedup (BILL-23). Returns {:ok, %PaymentMethod{}}; the existing?: true virtual flag is set when dedup hit an existing row.

attach_payment_method!(customer, pm_processor_id, opts \\ [])

@spec attach_payment_method!(Accrue.Billing.Customer.t(), String.t(), keyword()) ::
  Accrue.Billing.PaymentMethod.t()

Raising variant of attach_payment_method/3.

detach_payment_method(pm, opts \\ [])

@spec detach_payment_method(
  Accrue.Billing.PaymentMethod.t(),
  keyword()
) :: {:ok, Accrue.Billing.PaymentMethod.t()} | {:error, term()}

Detaches a payment method from its customer on the processor and deletes the local row in the same transaction.

detach_payment_method!(pm, opts \\ [])

@spec detach_payment_method!(
  Accrue.Billing.PaymentMethod.t(),
  keyword()
) :: Accrue.Billing.PaymentMethod.t()

Raising variant of detach_payment_method/2.

set_default_payment_method(customer, pm, opts \\ [])

@spec set_default_payment_method(
  Accrue.Billing.Customer.t(),
  Accrue.Billing.PaymentMethod.t(),
  keyword()
) :: {:ok, Accrue.Billing.Customer.t()} | {:error, term()}

Sets a payment method as the customer's default. Raises Accrue.Error.NotAttached if pm.customer_id != customer.id (BILL-25 strict attachment check — never silently wires a foreign PM as default).

set_default_payment_method!(customer, pm, opts \\ [])

Raising variant of set_default_payment_method/3.