Skip to main content

Documentation Index

Fetch the complete documentation index at: https://docs.wellapp.ai/llms.txt

Use this file to discover all available pages before exploring further.

InvoicePaymentMeans is a junction (pivot) relation that associates one Invoice with one PaymentMeans, recording the payment instrument through which an invoice is expected to be or has been settled. It acts as the supporting link between the invoicing ledger and the payment-means graph, allowing a single invoice to be associated with a specific IBAN, card, or other payment method. The relation is soft-deleted rather than hard-deleted so that historical payment-means associations remain auditable even after unlinking. Agents and the records data-view surface this entity as an array relationship from both Invoice and PaymentMeans, and it is exposed as the invoice_payment_means records root with composites into payment-means summary and invoice totals.
NamingValue
ObjectInvoice Payment Means
Resource type (JSON:API type)invoice_payment_means
Collection / records rootinvoice_payment_means
REST base/v1/invoice-payment-means
Entity classInvoicePaymentMeans
Read access today: this object is readable via the universal POST /v1/records/query endpoint with root: "invoice_payment_means". A dedicated GET /v1/invoice-payment-means endpoint is Planned.

API operations

OperationMethod & pathStatus
ListGET /v1/invoice-payment-means🟡 Planned via POST /v1/records/query
RetrieveGET /v1/invoice-payment-means/{id}🟡 Planned
CreatePOST /v1/invoice-payment-means🟡 Planned
UpdatePATCH /v1/invoice-payment-means/{id}🟡 Planned
DeleteDELETE /v1/invoice-payment-means/{id}🟡 Planned

Data model

Attributes

FieldTypeRequiredConstraintsAllowed valuesDescription
idstring, UUID, 🔒 system✅ Yesunique; gen_random_uuid() defaultPublic identifier for this invoice–payment-means link. Stable across soft-delete lifecycle. Used as the canonical id in JSON:API responses and in the composite_invoice_payment_means_list source fields on both Invoice and PaymentMeans records views.
invoice_pkinteger, FK (internal)✅ YesNOT NULL; FK → core_api.invoices(pk) ON UPDATE CASCADE; indexed via idx_invoice_payment_means_invoice and partial idx_invoice_payment_means_invoice_active (WHERE deleted_at IS NULL)Internal surrogate key pointing to the parent Invoice. Implicit FK backing column generated by MikroORM from the @ManyToOne invoice relation. Exposed externally through the invoice relationship, not surfaced as a bare attribute in API responses.
payment_means_pkinteger, FK (internal)✅ YesNOT NULL; FK → core_api.payment_means(pk) ON UPDATE CASCADE; indexed via idx_invoice_payment_means_payment_meansInternal surrogate key pointing to the linked PaymentMeans row. Implicit FK backing column generated by MikroORM from the @ManyToOne payment_means relation. Exposed externally through the payment_means relationship.
created_atdatetime, 🔒 system✅ YesNOT NULL; set once on insert via MikroORM onCreate lifecycle hookTimestamp recording when this invoice–payment-means association was created. Used as the sort_proxy basis for the composite_invoice_payment_means_list aggregate ordering on both Invoice and PaymentMeans data views.
updated_atdatetime, 🔒 system⚪ Nonullable (timestamptz null in DDL); set on insert via MikroORM onCreate hook and refreshed on every update via onUpdate hookTimestamp of the most recent mutation to this row. Set on INSERT by the onCreate hook, so it is not null after creation. Refreshed on every subsequent UPDATE.
deleted_atdatetime⚪ Nonullable; NULL = active; non-NULL = soft-deleted. Partial index idx_invoice_payment_means_invoice_active filters WHERE deleted_at IS NULL on the invoice_pk column.Soft-delete timestamp. When set, this junction row is considered unlinked but is preserved for audit purposes. All data-view and Hasura queries must predicate on deleted_at IS NULL to exclude unlinked associations.

Relationships

NameTypeRequiredDescription
invoiceto-one (invoice)✅ YesThe Invoice this junction row links to. FK: invoice_payment_means.invoice_pk → invoices.pk ON UPDATE CASCADE. The invoices entity carries issuer_pk, receiver_pk, invoice_number, grand_total, and currency. Hasura exposes an array_relationship invoice_payment_means on the invoices table, enabling the composite_invoice_payment_means_list on the invoices records view.
payment_meansto-one (payment_means)✅ YesThe PaymentMeans instrument (IBAN, card, check, or other) associated with the invoice. FK: invoice_payment_means.payment_means_pk → payment_means.pk ON UPDATE CASCADE. The PaymentMeans entity carries name, account, card, and company associations. Hasura exposes an array_relationship invoice_payment_means on the payment_means table, enabling the composite_invoice_payment_means_list on the payment_means records view.

System-computed

  • id is generated via gen_random_uuid() PostgreSQL function, set as the column defaultRaw in the MikroORM entity definition. It is unique and stable for the lifetime of the row, including after soft-delete.
  • created_at is set exactly once on INSERT via MikroORM onCreate: () => new Date(). It is never updated after creation.
  • updated_at is set on INSERT (onCreate: () => new Date()) and refreshed on every UPDATE (onUpdate: () => new Date()). Because onCreate is present, updated_at is never null after row creation; the column is declared nullable in the DDL (timestamptz null) to allow the optional TypeScript type, but the onCreate hook ensures it is populated on insert.
  • deleted_at is null on active rows. Setting it to a non-null timestamp constitutes a soft-delete. Hard DELETE is never used; the junction row is retained for audit and historical query purposes. The partial index idx_invoice_payment_means_invoice_active (WHERE deleted_at IS NULL) is maintained to optimize hot Hasura array_relationship traversals on the invoice_pk column while excluding soft-deleted rows from the index.
  • Three indexes are maintained on the table: idx_invoice_payment_means_invoice (invoice_pk, full) and idx_invoice_payment_means_payment_means (payment_means_pk, full) were added in Migration20260415150000_invoice_payment_means_and_transactions_indexes. The partial index idx_invoice_payment_means_invoice_active (invoice_pk, WHERE deleted_at IS NULL) was added later in Migration20260506140000_perf_indexes_round7 during a hot-path performance round. All three are declared via @Index decorators on the entity class.
  • The entity is a pure junction table with no workspace_pk column of its own. Tenant isolation is enforced transitively: Hasura RLS on the invoice or payment_means parent tables scopes access, and application-layer queries always join through the parent entity carrying the workspace predicate.
  • The entity has no workspace-direct FK by design (it is scoped through its Invoice parent). It is registered in allEntities in database/entities/index.ts.
  • The records root invoice_payment_means exposes composites via composites.yml: invoice.composite_total_amount_currency (display_type: currency_amount, source_fields: invoice.invoice_id, invoice.grand_total, invoice.local_currency) and payment_means.composite_payment_means_summary (display_type: payment_means_summary) and payment_means.company.composite_logo_name (display_type: company_logo_name). These composites are read-only, pipeline-resolved at query time by the composite-reconstructor.

Example

{
  "data": {
    "type": "invoice_payment_means",
    "id": "c3e8a1f2-6d47-4b3e-9a12-0f8b7c2d5e94",
    "attributes": {
      "created_at": "2025-11-04T09:22:10.000Z",
      "updated_at": "2025-11-04T09:22:10.000Z",
      "deleted_at": null
    },
    "relationships": {
      "invoice": {
        "data": {
          "type": "invoice",
          "id": "a1b2c3d4-e5f6-7890-abcd-ef1234567890"
        }
      },
      "payment_means": {
        "data": {
          "type": "payment_means",
          "id": "f9e8d7c6-b5a4-3210-fedc-ba9876543210"
        }
      }
    }
  }
}
Source: apps/api/src/database/entities/InvoicePaymentMeans.ts · domain: financial-graph · tier: Supporting