Skip to main content

Payment Methods

System-level catalog of payment methods (cash, card, digital wallets, etc.) that businesses can enable for their operations.

Architecture

Hexagonal architecture with strict layer boundaries:

payment-methods/
├── domain/
│ └── payment-methods-repository.domain.ts # IPaymentMethodsRepository port + DI token
├── application/
│ └── payment-methods.service.ts # Use cases (depends on domain port only)
├── infrastructure/
│ └── payment-methods.repository.ts # Kysely implementation of the port
└── interfaces/
├── payment-methods.controller.ts # HTTP routes + Swagger + RBAC guards
├── dtos/
│ ├── create-payment-method.dto.ts
│ ├── update-payment-method.dto.ts
│ └── payment-method-with-relation-response.dto.ts
└── query/
└── paginate-payment-methods.query.ts

Domain Concepts

Payment Method

A named payment type (e.g. "Credit Card", "Cash", "PayPal") with:

  • paymentGroup — classification bucket (see groups below)
  • businessId — if set, the method is business-specific; if null, it's a global/system method
  • isActive — soft-delete flag
  • generatesAccountsReceivable / generatesAccountsPayable — financial ledger flags

Payment Groups

GroupDescription
electronicAndCardPaymentsCredit/debit cards, POS terminals
digitalWalletsAndMobilePaymentsApple Pay, Google Pay, mobile wallets
cashAndManualCash, checks, manual entries
bankRelatedWire transfers, ACH, bank deposits
cryptocurrencyBitcoin, stablecoins
buyNowPayLaterAfterpay, Klarna, installment plans
otherSpecializedGift cards, store credit, vouchers

When a payment method is created with a businessId, a businessPaymentMethod junction record is auto-created to link it. Businesses can also independently enable/disable global payment methods via the business-payment-methods module.

API Endpoints

MethodPathDescriptionAuth
POST/payment-methodsCreate a payment methodCreate
GET/payment-methodsList all (paginated, searchable)Read
GET/payment-methods/:idGet by IDRead
PATCH/payment-methods/:idPartial updateUpdate
DELETE/payment-methods/:idDeleteDelete
GET/payment-methods/business/:businessIdList active methods for a businessRead
GET/payment-methods/with-relation/:businessIdAll methods + business link statusRead

With-Relation Endpoint

The with-relation endpoint returns all active payment methods (global + business-specific) with a LEFT JOIN to businessPaymentMethod. This tells the caller which methods the business has enabled. Results are sorted: linked methods first (bpmOrder: 1), then unlinked (bpmOrder: 2), alphabetically by name within each group.

Design Decisions

  1. Global vs. business-specific methods: Methods with businessId = null are global (available to all businesses). Methods with a businessId are custom to that business.

  2. Auto-link on creation: When creating a method with a businessId, the repository automatically inserts a businessPaymentMethod record. This keeps the two tables consistent without requiring two API calls.

  3. DI via Symbol token: The service depends on the IPaymentMethodsRepository domain interface via PAYMENT_METHODS_REPOSITORY Symbol token, not the concrete Kysely implementation. This enables testing with mock repositories.

  4. RBAC: All endpoints are protected by RolesGuard with PolicyResource.PaymentMethod + per-endpoint PolicyAction.