Skip to Content
Living documentation — last reviewed 2026-05-28
FeaturesPaymentsPayments — Code Map

Payments — Code Map

API — apps/api/src/payments/

Module + DI

  • payments.module.ts — wires all services, adapters, controllers. onModuleInit registers each provider into PaymentProviderRegistry.

Providers (providers/)

  • payment-provider.registry.ts — Map<PaymentProviderType, PaymentProviderAdapter> with register/get/getOrThrow/list.
  • cardcom.provider.ts — LowProfile/Create + GetLpResult + ChargeWithToken + v11 RefundByTransactionId. tokenOnly pages run CreateTokenOnly, or SuspendedDeal + J5 when the request carries cardValidation: 'issuer_hold'; classifyDeal reads Cardcom’s 700/701 J-validation success codes as settled on those two operations only, and the token mapper falls back from TokenInfo to TranzactionInfo. FailedRedirectUrl takes request.failedUrl when present (falling back to cancelUrl), so a declined card no longer lands on the “you cancelled” page; CancelRedirectUrl is unchanged. No webhook signature. getRefundCapability() → 'manual' = refund API implemented but unverified against a live terminal; RefundCapabilityService still tries it for a bring-your-own Cardcom terminal.
  • icredit.provider.ts — Rivhit hosted page. GroupPrivateToken body signature.
  • meshulam.provider.ts — Light-API iframe + JSON IPN. webhookKey === credentials.apiKey signature.
  • morning.provider.ts — Single-URL Morning webhook (?org=…). Signature TBD (:941). Issues חשבונית/קבלה automatically.
  • tranzila.provider.ts — Stub-grade adapter; signature returns true.

Services (services/)

  • payment.service.ts — orchestrator + the exported withSubParam (stamps sub=<id> on every return leg, idempotently). createHostedPayment, createCourseHostedPayment, charge, createRecurring, refund (capability switch), completeManualRefundTask, verifyAndActivateReturn, sendPaymentReceipt.
  • card-validation-policy.service.ts — answers card-issuer-validation per org for every tokenise-only page (presale checkout via PaymentService.createHostedPayment, card registration via CardRegistrationController). Only a definite true asks for an issuer hold; off/unset/unevaluable keeps the provider default.
  • refund-capability.service.ts — third gate in refund’s automatic-vs-manual routing: bring-your-own Cardcom terminals whose adapter reports manual try the provider API and fall back to the manual task when it refuses; refuses when the charge predates the active provider config.
  • payment-transaction.service.ts — CRUD on payment_transactions. upsertPending, completePendingBySubscriptionId, findByProviderTransactionId.
  • payment-provider-config.service.ts — encrypted credential CRUD on payment_provider_configs; redacted reads.
  • payment-provider-clients.service.ts — payment_provider_clients upserts (Morning client linkage).
  • credential-encryption.service.ts — AES-256-GCM round trip. Key from PAYMENT_CREDENTIALS_ENCRYPTION_KEY (32-byte hex).
  • webhook-processing.service.ts — dispatches payment.completed | payment.failed | subscription.renewed | subscription.cancelled | refund.completed | client.created. Cross-org guard on course entitlements (:215, :362). handlePaymentFailed’s first-purchase arm marks the transaction failed and leaves the subscription pending (emitting payment.activation_failed with reason: 'first_charge_failed') — the charge failed, not the checkout.
  • recurring-charge.service.ts — daily 02:00 UTC cron. FOR UPDATE SKIP LOCKED sweep, charge-then-update, debt promotion at 3 fails.
  • payment-method.service.ts — replacePaymentMethod (deactivate old, insert new), getActivePaymentMethod.
  • debt.service.ts — clearDebt(subscriptionId) charges the accumulated debtAmountInCents and zeroes it.
  • payment-analytics.service.ts — KPIs (collected this month, MRR snapshot, forecasted recurring, recurring-charges list), all on recurring plans only; outstanding and members in debt come from sumOutstanding.
  • revenue-metrics.sql.ts — RECURRING_PLAN, sumOutstanding / outstandingRowCondition, sumPacksSold: the money nouns shared with analytics and insights (definitions).
  • payment-monitoring.service.ts — the stale/abandoned-checkout guard. detectStuckPending (15-min alert), sweepAbandonedCheckouts (24h release), voidPendingTransaction (owner, by txn id) and voidPendingSubscription (member rollback + staff member-page dismiss, by subscription id — takes requestedByUserId, reason, intent, source, and stamps the decision onto the abandoned transaction’s metadata.checkoutCancel). Exports ABANDONED_CHECKOUT_REASON, the marker that keeps a released row revivable.
  • checkout-urls.ts (+ .unit.spec.ts) — deriveFailedUrl(cancelUrl): flips status=cancelled → status=failed so a REFUSED charge can land somewhere other than the “you cancelled” page. Returns undefined rather than guessing when there is nothing to flip, and adapters fall back to cancelUrl.
  • payment-observability.service.ts — typed emit(eventName, payload) interface; the central spine for all payment telemetry.
  • manual-charge.service.ts (FIT-254 §3.3/§3.4) — ManualChargeService.charge (desk charge) + .clearDebt (debt collection wrapper over DebtService). Exports CHARGE_VERIFIED_PROVIDERS (['cardcom', 'meshulam', 'test']), the synchronous-token-charge provider allowlist also imported by plan-change.service.ts.
  • manual-charge.service.unit.spec.ts — unit tests.
  • terminal-provisioning.service.ts (FIT-286) — opens a Cardcom terminal under Taikan’s dealer agreement (CompanyOperations/NewCompany). Derives the KYC volume estimates from the org’s plans + member count, refuses a second application while one is pending_kyc, and stores the result via createPendingManagedConfig. Deliberately NOT a PaymentProviderAdapter — it uses dealer-level credentials, not the gym’s.
  • terminal-provisioning.service.unit.spec.ts — derivation, duplicate guard, pending-not-active storage, CompanyNumber-not-CompanyInternalID capture, GetCompanyStatus GET-only behavior.
  • managed-terminal-status.service.ts (FIT-286) — CompanyOperations/GetCompanyStatus checks for pending_kyc terminals. Two entry points on one code path: the hourly @ScheduledJob(…, '30 * * * *') sweep, gated per-org on managed-terminal-kyc-poll (and skipping any terminal with no stored companyNumber), and the owner’s ungated on-demand “check status”. Activates on IsDone, re-encrypting the credentials from the approving response; otherwise stores the outstanding requirements in status_reason. The sweep swallows per-org failures so one bad terminal cannot stall it; the on-demand path deliberately propagates them instead.
  • managed-terminal-status.service.unit.spec.ts — approval flip, settle-before-email ordering, on-demand provider-failure propagation, failed-query safety, and the sweep: flag on/off/unevaluable, per-org rollout, missing-company-number skip, sweep isolation.

Controllers (controllers/)

  • payment.controller.ts — GET/POST /organizations/:orgId/payments[…]. Member-facing list, refund, refund-task complete, verify-return, transaction detail, cash credit note (credit-note/preview, credit-note) and settle-cash-refund.
  • payment-webhook.controller.ts — @Public path-style and query-style webhook entry points.
  • payment-provider-config.controller.ts — GET/POST/PATCH/DELETE /organizations/:orgId/payment-config, plus POST …/provision (owner/admin, opens a managed terminal), POST …/managed-status/refresh (owner/admin, re-checks KYC now) and POST …/managed-status (@PlatformAdmin, manual override / the only way to close a rejection).
  • card-registration.controller.ts — admin-initiates-card-on-file for a member, plus member-side equivalents.
  • manual-charge.controller.ts (FIT-254 §3.3/§3.4) — POST members/:membershipId/charge (desk charge), POST subscriptions/:subscriptionId/clear-debt.
  • app-return.controller.ts — @Public GET /payments/app-return. HTTPS→taikan:// bridge for hosted-page returns from the native app (providers reject custom-scheme return URLs; Morning errors 1103).
  • payment-analytics.controller.ts — GET /organizations/:orgId/payment-analytics/*.
  • invoicing.controller.ts — /organizations/:orgId/invoicing/* proxy onto the provider’s listDocuments / getDocument adapter methods.

DTOs (dto/)

  • refund.dto.ts — { amountInCents?, reason?, idempotencyKey? } (the key is required for a manual transaction).
  • credit-note.dto.ts (TKN-425) — CreditNoteDto { idempotencyKey (UUID), amountInCents?, reason (1–255), cashReturned }; SettleCashRefundDto { idempotencyKey }.
  • settle-unpaid-term.dto.ts — settle (method, paidAt?, paidOn? YYYY-MM-DD, reference, note, cheque, skipDocument?) and write-off (reason?) bodies.
  • configure-provider.dto.ts — { provider, credentials, config? } + update variant.
  • manual-charge.dto.ts (FIT-254 §3.3) — { amountInCents: int ≥ 100, description: string }.
  • provision-terminal.dto.ts (FIT-286) — nested { business, owner, bankAccount, expectedActivity? }; the estimates are optional because the API derives them. Plus SettleTerminalStatusDto.

Shared — libs/shared/src/lib/

  • schemas/payment.schema.ts — Zod schemas for PaymentTransactionResponse, refund DTOs, transaction filters.
  • interfaces/payment-provider.ts (canonical PaymentProviderAdapter contract, ChargeRequest, RefundRequest, WebhookEvent, RefundCapability, ClientInfo, etc.).
  • constants/platform-tiers.ts — tierHasFeature consumed by RequiresFeature.
  • types/cardcom-provisioning.types.ts (FIT-286) — NewCompany wire contracts mirrored from Cardcom (including its AvarageTransactionAmountInCreditCard misspelling), TerminalProvisioningInput/Draft/Result.

DB — libs/db/src/lib/schema/

  • payments.ts — plans, subscriptions (+ this feature’s cancellation_reason_code and nine retention_* columns), member_payment_methods, payment_provider_configs, payment_transactions, invoicing_configs, payment_provider_clients. No cancellation_requests table.
  • enums.ts — paymentProvider, planType, planInterval, subscriptionStatus, transactionStatus, transactionType, taskType (includes manual_refund, cancellation_review), plus this feature’s cancellationReasonCode, retentionOutcome, retentionCaseKind.

Web — apps/web/src/

  • components/payments/ — owner dashboard widgets: transactions-table.tsx (refund confirm dialog + optional partial amount + refundExecution-driven task note), kpi-cards.tsx, payment-tabs.tsx, refund-task-complete-dialog.tsx, recurring-charges-table.tsx, documents-table.tsx, payments-data-table.tsx, summary-detail-toggle.tsx, date-range-filter.tsx.
  • components/subscriptions/staff-cancel-dialog.tsx — staff cancel dialog (no default initiator, per-notice-date preview, reason codes). See subscriptions-plans/code-map.md.
  • components/overview/members/member-payments-tab.tsx — member-detail refund confirm dialog + partial amount + refundExecution task note (same pattern as transactions-table.tsx).
  • components/member/plan-card.tsx — member-facing plan/subscription summary.
  • app/[lang]/(protected)/dashboard/payments/ — owner payment console.
  • app/[lang]/(protected)/dashboard/settings/checkout-return/page.tsx — Cardcom return page; calls verify-checkout for platform-billing.
  • app/[lang]/buy/courses/[id]/page.tsx — public course buy page (handles Clerk email-code flow). See courses/code-map.md.
  • components/settings/provider-config-dialog.tsx (+ .driver.tsx, .int.spec.tsx) — mode choice (Taikan-managed vs bring-your-own) → explanation → application → one-time provider login.
  • components/settings/managed-terminal-form.tsx (FIT-286) — the ~15-field terminal application.
  • components/address/israeli-address-picker.tsx (FIT-286) — reusable locality + street combobox over the national registry. Emits סמל ישוב / סמל רחוב codes; the street list is city-scoped and resets when the city changes, because street codes are unique per city only.
  • components/settings/payment-provider-config.tsx (+ .driver.tsx, .int.spec.tsx) — settings card; renders the pending_kyc / rejected states, lists what Cardcom is still waiting on, swaps Configure for Check status while a review is outstanding.

Tests

  • apps/api/src/payments/services/refund-flow.int.spec.ts — end-to-end refund integration test.
  • apps/api/src/payments/services/payment-transaction.service.unit.spec.ts
  • apps/api/src/payments/services/credential-encryption.service.unit.spec.ts
  • apps/api/src/payments/services/manual-charge.service.unit.spec.ts (FIT-254 §3.3/§3.4) — guard-stack ordering, pending-row-first, allowlist.
  • apps/api/src/payments/providers/*.unit.spec.ts — per-provider adapter contract tests.
  • apps/api/src/subscriptions/cancellation-flow.int.spec.ts — cancellation-request + refund handshake.

Web — card-on-file & manual charge (FIT-254 §3)

  • apps/web/src/components/overview/members/payment-methods-card.tsx (+ .driver.tsx, .int.spec.tsx) — member-detail Memberships-tab card: active card, expiry warning, collapsed inactive history, “Register card” CTA.
  • apps/web/src/components/members/manual-charge-dialog.tsx (+ .driver.tsx, .int.spec.tsx) — staff desk-charge confirm dialog (amount, description, last-4, confirm-with-amount button).
  • apps/web/src/components/members/collect-debt-dialog.tsx — staff debt-collection confirm dialog.
  • apps/web/src/components/payments/debt-report-table.tsx — payments-dashboard debt report rows, links into collect-debt.

Billing resilience (TKN-353)

Behavior: behavior.md › Billing resilience. Operations: runbook.

API — apps/api/src/payments/services/

  • billing-resilience-policy.service.ts — the payment-billing-resilience flag as on | off | unevaluable; enabled() is on only.
  • billing-attempt.service.ts — member recurring attempts: collect (claim → provider → outcome), recordOutcome, apply (atomic settlement), recover (five-minute external-id lookup on the original terminal), hasUnresolved, hasProtectedObligation, terminalState (open | busy | blocked), settlement outboxes (notifications, pendingLifecycleEvents), deduplicated alert.
  • billing-collection.service.ts — the same protocol for desk charges and debt collection (manualAttempt, collect, apply, recover every five minutes).
  • billing-charge-guard.ts — lock order (lockBillingOrganization, lockBillingAccount), pendingMemberCollection, and withLegacyBillingAdmission for legacy pre-debit writers.
  • billing-settlement.ts — pure settlement math: billingSettlement (success/decline patch: debt opened / retried / cleared), missedPaymentDebtEntry, chargeRowDebtPolicy, debtOpenedEvent, scheduledBillingRow, cardUsableAt.
  • billing-resolution-state.ts / billing-resolution.service.ts — owner reconciliation: inspect, reconcile, confirmNoDebit (owner only), authorizeRetry; TECHNICAL_RETRY_DELAYS_MS, external-id lineage for retries.
  • billing-notification.service.ts — frozen-payload receipt/failure mail with stable idempotency keys (prepare, deliver).
  • billing-due-query.ts — read-only due candidates for the catch-up (organizations, subscriptions), including the persisted-protocol filter for un-opted organizations.
  • billing-catchup.service.ts — collectDue, every minute on the billing-collection queue (20 orgs × 5 rows, 30 s start budget, Redis fairness cursors).
  • billing-schedule.service.ts — opening-day and staff charge-date writers under the billing locks (protects, updateOrganization, moveChargeDate).
  • presale-checkout.service.ts — protected card-save checkout fulfillment (handle): exact page, verified provider, terminal identity, expired-page reopen, abandoned revival.
  • billing-readiness.service.ts / billing-readiness-actions.service.ts — presale readiness report and the verifyAccount / repairSchedule repairs.
  • Touched legacy services: recurring-charge.service.ts (routing, processResilientCharge, collectProtectedCharge, recoverBillingAttempts), webhook-processing.service.ts (protected webhook ownership, page-expired marker), payment.service.ts (billingCheckout on card-save pages), payment-method.service.ts (scheduled-card protection, terminal binding), manual-charge.service.ts / debt.service.ts (claims and idempotency), payment-transaction.service.ts (publicTransactionMetadata strips the protocol snapshots from API responses).

API — controllers, jobs, DTOs

  • payments/controllers/billing-resolution.controller.ts — /organizations/:orgId/payments/billing/transactions/:transactionId (GET, reconcile, confirm-no-debit, authorize-retry); dto/billing-resolution.dto.ts.
  • admin/controllers/admin-billing-readiness.controller.ts — /admin/organizations/:orgId/billing-readiness (GET, verify-account, repair-schedule), PlatformAdmin; payments/dto/billing-readiness.dto.ts.
  • payments/dto/verify-return.dto.ts — POST /payments/verify-return body; the provider deal’s own subscription is authoritative.
  • common/scheduled-jobs/billing-collection.processor.ts — the dedicated billing-collection BullMQ worker.

Shared, web, admin

  • libs/shared/src/lib/types/billing-resolution.types.ts, billing-readiness.types.ts; constants/payment-error-codes.ts (billing_* codes); constants/feature-flags.ts (PAYMENT_BILLING_RESILIENCE).
  • apps/web/src/components/payments/billing-review-dialog.tsx (+ driver, int spec) — Review billing, opened from transactions-table.tsx and overview/members/member-payments-tab.tsx.
  • apps/web/src/components/members/manual-charge-dialog.tsx, collect-debt-dialog.tsx — pending-reconciliation vs confirmed-decline outcomes, request-key retention.
  • apps/admin/src/pages/organizations/billing-readiness-panel.tsx — readiness panel on the admin organization page.

Tests

  • Real-PostgreSQL suites, run by apps/api/vitest.billing-resilience.config.ts: billing-resilience.int.spec.ts (+ .int.driver.ts), billing-resilience-{provider,settlement,execution,presale,readiness}.int.spec.ts, common/scheduled-jobs/billing-collection.processor.int.spec.ts.
  • Unit: billing-resilience-policy.service, billing-settlement, billing-lifecycle, billing-review-api, billing-resolution (controller), cardcom-resilience (provider), admin-billing-readiness (controller).

Desk money, refunds and unpaid payments (TKN-425 / 426 / 427)

Behavior: Cash credit notes, Pay-later terms, Unpaid payment, Refund flows.

API

  • payments/services/cash-credit-note.service.ts — CashCreditNoteService (preview, issue, settleCashRefund, recordCredit + completeCredit for callers holding their own transaction) and the pure computeCreditable / priorCreditsInCents.
  • payments/services/manual-document.service.ts — ManualDocumentService.issue: files a desk document (sale or credit) through the active provider or a named one, writes the outcome (incl. document_url) on the row, never throws.
  • payments/credit-document-kind.ts — creditKindFor (original document → credit kind) and creditableOriginal (the 409 verdicts).
  • payments/services/manual-payment.service.ts — refund (now the credit core), cancelCashPlan / previewCashCancellation (credit amount + cashReturned), settleCashCancellation (reservations), settleUnpaidTerm (paidOn, client key), writeOffUnpaidTerm, record (settlement replay), prepayCashPlan / settlesCashLapse / quoteCashCoverage (desk restore of a cash_lapsed debt), audit rows; distributeCredit, unpaidSettlementKey.
  • payments/services/unpaid-term-close.ts — closeUnpaidTerm (closes a pay-later term and clears its debt: restore or stay cancelled), refreshMembershipPaymentStatus.
  • payments/services/payment.service.ts — manual routing and task origin in refund; processAutomaticRefund (sale lock, cap, pending row before the provider); openManualRefundTask (lock, cap, metadata.manualRefund, portal-first line); getManualRefundTask (preview); completeManualRefundTask (amount + document number, refund row, flip at 100%, cash-notice refusal); refund-row credit documents in issueCreditDocument.
  • payments/controllers/payment.controller.ts — GET refund-tasks/:taskId, POST refund-tasks/:taskId/complete; payments/dto/complete-refund-task.dto.ts.
  • payments/cash-renewal-task.ts — cashRenewalDueDate (org-calendar day, 7 days before coverage ends); openCashRenewalTask now takes timezone.
  • payments/services/cash-plan-coverage.service.ts — task escalation compares due dates with each org’s own today.
  • payments/providers/cardcom.provider.ts — refund outcome refused / unknown, credit twin mapping, ExternalId, Comments, DocumentDate (toCardcomDocumentDate), Email ≤ 50 rule, Name ≤ 50, ISOCoinID from CURRENCY_TO_COIN_ID. morning.provider.ts — both credit kinds → 330.
  • payments/billing-debt.ts — DebtPolicy, debtCancelsAt, debtPayBy, debtRetryInstants, nextDebtRetry, resolveBillingDebt, hasOpenDebtAfterCancellation, earliestBillingDebt.
  • payments/services/debt-entry.ts — enterDebtPatch, retryFailedPatch, debtClearedPatch, debtClearedFields.
  • organizations/debt-policy.ts — loadDebtPolicy(db, orgId).
  • payments/subscription-events.ts — SUBSCRIPTION_DEBT_OPENED (reason, payBy, cancelsAt), BILLING_CARD_UNUSABLE / BillingCardUnusableEvent.
  • payments/services/recurring-charge.service.ts — markCardUnusable, debt entry / retry / clear in handleChargeFailure and handleChargeSuccess, presale day-0 retention case; the same in billing-settlement.ts, webhook-processing.service.ts (handlePaymentFailed, handleSubscriptionRenewed), cancellation-tail-settlement.service.ts; restore in debt.service.ts (clearDebt, getDebtReport), billing-collection.service.ts, external-links/external-payment-apply.service.ts.
  • subscriptions/subscription-lifecycle.service.ts — SubscriptionLifecycleService.tick (hourly), runForOrg, pure lifecycleTransition; subscriptions/subscriptions.service.ts — endSubscription, findBookableForMembership.
  • bookings/booking-horizon.ts — bookingHorizon, isCreditSource, closedMoneyWall, startsBeyondHorizon; bookings/bookings.service.ts — loadLiveSubscriptions, assertBillingAllowsBooking.
  • subscriptions/subscriptions.controller.ts (/my and staff list billingDebt, paymentLastDay; POST my/:id/pay-debt), subscriptions/member-action.ts (pay_debt), memberships/member-status.ts (billingDebt, non_payment), memberships/memberships.service.ts (getDebtPolicy, nonPaymentCondition).
  • notifications/billing-debt-notifications.service.ts — BillingDebtNotificationsService: debtOpened, debtLastDay, debtCancelled, card-unusable listener, runCardExpiryReminders; notifications/email-types.ts (CARD_EXPIRING, CARD_UNUSABLE, DEBT_OPENED, DEBT_LAST_DAY, DEBT_CANCELLED); templates in notifications/templates/payment-emails.ts, push copy in push-notifications/notification-copy.ts.
  • audit/audit-actions.ts — payment.cash_recorded, payment.credit_note_issued, payment.cash_plan_cancelled, payment.unpaid_term_settled, payment.unpaid_term_written_off.

Shared and DB

  • libs/shared/src/lib/types/payment-provider.types.ts — TaxDocumentKind ('credit' replaced by tax_invoice_receipt_credit / receipt_credit), CREDIT_DOCUMENT_KINDS, isCreditDocumentKind; IssueDocumentRequest.{externalId, linkedDocumentNumber, documentDate}, RefundDocumentRequest.externalId.
  • libs/shared/src/lib/constants/payment-error-codes.ts — credit_note_*, refund_task_use_cash_settlement, manual_refund_idempotency_required, refund_amount_exceeds_cap, refund_task_amount_required, debt_partial_payment_refused, booking_blocked_debt, plan_required_to_book, plan_not_started.
  • libs/shared/src/lib/plan-duration.ts — planDurationDays, addDaysToDateString, unpaidTermDates.
  • libs/shared/src/lib/schemas/ — payment.schema.ts (transaction method, paidAt, document*, refund_pending; manualRefundOriginValues, completeRefundTaskSchema, refundTaskPreviewSchema), plan.schema.ts (billingDebtSchema, debtReasonValues, NON_PAYMENT_CANCELLATION_REASON, pay_debt, paymentLastDay), membership.schema.ts (member status billingDebt, non_payment, paymentLastDay), organization.schema.ts (billingGraceDays, MAX_BILLING_GRACE_DAYS = 30), scheduling.schema.ts (eligibility debt_blocked, plan_not_started), cancellation.schema.ts (refund.cashReturned, preview creditableInCents / capInCents), notification-prefs.ts (billing).
  • libs/db/src/lib/schema/payments.ts, organizations.ts; migration libs/db/drizzle/0164_special_meteorite.sql (data-model).

Web

  • components/payments/credit-note-dialog.tsx (+ driver, int spec) — CreditNoteDialog, isCashCreditable, useCodedErrorCopy, invalidatePaymentViews.
  • components/payments/confirm-cash-returned-dialog.tsx (+ driver, int spec) — ConfirmCashReturnedDialog, pendingCashRefundOriginalId.
  • components/payments/refund-task-complete-dialog.tsx (+ driver, int spec) — preview-driven amount (default, cap hint), portal-first line, posts amount + document number; refund_task_use_cash_settlement copy and member link.
  • components/payments/transactions-table.tsx, components/overview/members/member-payments-tab.tsx — credit-note and confirm-cash actions, document number / failed pill.
  • components/overview/members/enroll-member-dialog.tsx — dated unpaid notice, cash received now/later.
  • components/overview/members/member-memberships-tab.tsx, components/members/settle-unpaid-term-dialog.tsx, components/members/write-off-unpaid-term-dialog.tsx (+ drivers, int specs) — unpaid-term badge actions.
  • components/member/unpaid-term-banner.tsx (+ driver, int spec), components/overview/members/member-status-badge.tsx — last day as a plain date.
  • components/subscriptions/staff-cancel-dialog.tsx — cash credit amount and Cash returned switch.
  • app/[lang]/(protected)/dashboard/settings/(shell)/booking/page.tsx — billing-grace-days and plan-required-to-book settings.
  • components/member/billing-debt-banner.tsx (+ driver, int spec), app/[lang]/(protected)/(member)/profile/payments/page.tsx — grace / cancelled-for-non-payment banner, pay-debt button, contact link.
  • components/member/schedule/session-detail-drawer.tsx — booking refusal codes (booking_blocked_debt with amount).

Tests

  • API: credit-note.int.spec.ts, cash-credit-note.service.unit.spec.ts, cash-plan-payment.int.spec.ts, refund-flow.int.spec.ts, credit-document-kind.unit.spec.ts, cash-renewal-task.unit.spec.ts, refund-task.int.spec.ts, billing-debt.unit.spec.ts, debt-entry.unit.spec.ts, subscription-lifecycle.service.{unit,int}.spec.ts, billing-debt-notifications.service.unit.spec.ts, booking-horizon.unit.spec.ts, bookings.service.unit.spec.ts (billing gate), renew-early.int.spec.ts (renewing and debt), provider specs (cardcom.provider, card-registration-roundtrip, morning-issue-document).
  • Shared: plan-duration.unit.spec.ts, i18n/dictionaries.unit.spec.ts (locale parity, no “now”/“from today” in unpaid notices).

Address registry (FIT-286)

  • libs/db/src/lib/schema/israel-addresses.ts — israel_cities (1,310 rows), israel_streets (63,571 rows, PK (city_code, code)). Street code 9000 is the registry’s “the locality itself” entry, present once per city and the only option where a locality has no named streets.
  • libs/db/data/israel-streets.csv.gz — committed UTF-8 snapshot of data.gov.il’s “רשימת רחובות בישראל” (source file is cp1255).
  • scripts/seed-israel-streets.ts (pnpm db:seed:streets) — idempotent upsert; needs running once per environment, including production.
  • apps/api/src/addresses/ — AddressesModule, IsraelAddressService, GET /addresses/israel/cities|streets. Authenticated but not org-scoped: public government data, identical for every gym.

Env

  • PAYMENT_CREDENTIALS_ENCRYPTION_KEY — 64-char hex (32 bytes) AES-256-GCM key.
  • API_BASE_URL — used to construct webhook URLs (payment.service.ts:128).
  • FRONTEND_URL — used for cancellation-request review links.
  • Cardcom platform terminal: PLATFORM_BILLING_TERMINAL_NUMBER, PLATFORM_BILLING_API_NAME, PLATFORM_BILLING_API_PASSWORD (see platform-billing/).
  • CARDCOM_PROVISIONING_DEBUG (FIT-286) — true logs the NewCompany body verbatim for a Cardcom support ticket. Default (unset/false) redacts the dealer secret, ת.ז, bank account, mother’s maiden name and the generated dashboard password, keeping field names, structure and every other value. Local dev only.
  • Cardcom dealer provisioning (FIT-286): CARDCOM_SUPPLIER_USERNAME, CARDCOM_SUPPLIER_PASSWORD, CARDCOM_SUPPLIER_SECRET, CARDCOM_MODULE_IDS — required together; resolveSupplier throws ServiceUnavailable naming what is missing rather than half-opening a terminal. CARDCOM_AGREEMENT_ID is optional (Cardcom does not require it): unset means the AgreementInfo block is omitted from the request rather than sent as 0.