@cfxlabsinc/b2b-services
    Preparing search index...
    Index
    instance: (...args: []) => RecurringFeeAdminService = ...

    The process default: built from each dependency's own instance().

    • The billing date and period an instant falls in, in the billing timezone. Both come from one instant, so a sweep running across local midnight cannot pair a date with the other day's period.

      Parameters

      Returns { billingDate: string; periodKey: string }

    • Charge one month at its invoice's amount and account, only once SES accepted the invoice email. One idempotency key per month: a FAILED charge frees it until RECURRING_FEE_RETRY_LIMIT, a CANCELLED one holds the month.

      Parameters

      • __namedParameters: { billingDate?: string; customerId: string; periodKey: string }
        • OptionalbillingDate?: string

          YYYY-MM-DD in the billing timezone; today when started by hand.

        • customerId: string
        • periodKey: string

      Returns Promise<
          | { ok: true; value: RecurringFeeChargeOutcome }
          | { error: ServiceError; ok: false },
      >

    • Charge again: one attempt past the retry limit on an escalated month, with charge's other checks and locks. Any other month is refused first.

      Parameters

      • __namedParameters: { billingDate?: string; customerId: string; periodKey: string }
        • OptionalbillingDate?: string

          YYYY-MM-DD in the billing timezone; today when omitted.

        • customerId: string
        • periodKey: string

      Returns Promise<
          | { ok: true; value: RecurringFeeChargeOutcome }
          | {
              error:
                  | ServiceError<
                      "INVALID_PERIOD_KEY"
                      | "FUTURE_PERIOD_KEY",
                      { periodKey: string },
                  >
                  | ServiceError<
                      "RECURRING_FEE_MONTH_NOT_ESCALATED",
                      { customerId: string; periodKey: string },
                  >;
              ok: false;
          },
      >

    • Stop billing the customer entirely. Drops the key rather than writing a json null, because every read tests key presence.

      Returns the config it removed: that amount survives nowhere else, and the caller needs it for the audit entry it records.

      Parameters

      • __namedParameters: { customerId: string }

      Returns Promise<
          | { ok: true; value: RecurringFeeConfig
          | null }
          | { error: ServiceError; ok: false },
      >

    • Enroll one candidate at the amount and account its list row holds, read under the customer row lock. Refuses a start date whose month, or a later one, holds a live manual PLATFORM charge, which the sweep would bill again.

      Parameters

      • __namedParameters: {
            billingStartDate?: string;
            currentPeriodKey?: string;
            customerId: string;
            idempotencyKey: string;
            periodKey: string;
        }
        • OptionalbillingStartDate?: string

          The suggested date when absent.

        • OptionalcurrentPeriodKey?: string

          The month enrolling happens in; a first attempt must be for it.

        • customerId: string
        • idempotencyKey: string

          One per enroll attempt: only a retry with it is answered as enrolled.

        • periodKey: string

          The month the caller's candidate list was read for.

      Returns Promise<
          | {
              ok: true;
              value: {
                  candidate: RecurringFeeEnrollmentCandidate;
                  fee: RecurringFeeConfig;
              };
          }
          | {
              error: | ServiceError<"INVALID_BILLING_START_DATE">
              | ServiceError<"NOT_AN_ENROLLMENT_CANDIDATE", { customerId: string }>
              | ServiceError<"RECURRING_FEE_ALREADY_CONFIGURED", { customerId: string }>
              | ServiceError<"ENROLLMENT_PERIOD_ROLLED_OVER", { periodKey: string }>
              | ServiceError<"BILLING_PERIOD_ALREADY_CHARGED", { periodKey: string }>
              | ServiceError<"LEDGER_ACCOUNT_NOT_FOUND", { sourceAccountId: string }>
              | ServiceError<
                  "LEDGER_ACCOUNT_CUSTOMER_MISMATCH",
                  { sourceAccountId: string },
              >;
              ok: false;
          },
      >

    • This customer's recorded fee changes, newest first.

      Reads the shared admin activity feed rather than a table of the feature's own, filtered by objectId and the customer.recurringFee.* types. Joins the actor so the surface can name a person instead of a user id.

      Parameters

      • __namedParameters: { customerId: string; pageSize?: number }

      Returns Promise<{ ok: true; value: RecurringFeeActivity[] }>

    • Recurring-fee charges, most recent first.

      Reads fee_transfer directly rather than any table of the feature's own. Selection and the period both come from data.recurringFee, which the sweep stamps on every charge it makes, so the set is enumerable as a whole rather than one customer at a time.

      customerId is optional: omit it to enumerate every recurring fee taken, and pair it with periodKey to pull a single month across the platform.

      A period with no row here was never charged — the customer could not pay, or is not yet due. That absence is the same signal listDue reads.

      NOTE: the cross-customer form has no index behind it. fee_transfer is indexed by account and by idempotency key, neither of which this predicate uses, so an unscoped call scans. Fine for an operator report; add a jsonb expression index on (data -> 'recurringFee' ->> 'periodKey') before putting it on a hot path.

      Parameters

      • __namedParameters: { customerId?: string; pageSize?: number; periodKey?: string }

      Returns Promise<
          {
              ok: true;
              value: {
                  amount: BigNumber;
                  createdAt: Date;
                  customerId: string;
                  id: string;
                  periodKey: string;
                  status: "FAILED"
                  | "PROCESSING"
                  | "COMPLETED"
                  | "CANCELLED";
                  statusDescription: string;
              }[];
          },
      >

    • Customers to charge for periodKey: an ACTIVE fee on an ACTIVE customer with no PROCESSING, COMPLETED or CANCELLED charge for the month, not waived and not escalated.

      The absent charge is the claim, so the feature needs no cursor and no table of its own. A customer who slips through this query twice still cannot be billed twice: see recurringFeeIdempotencyKey.

      A customer whose charge went FAILED stays due: the nightly sweep charges again until RECURRING_FEE_RETRY_LIMIT, then escalates the month to ops. A CANCELLED charge holds the month until ops resolve it on chain.

      A customer with a billingStartDate is due once billingDate, the date the sweep runs on, has reached the start date's day of the month (see isAnchorDayReached), so its invoice is issued and charged on that day. charge applies the same rule. A fee with no start date is due from the first sweep of the month.

      Parameters

      • __namedParameters: { billingDate: string; periodKey: string }

      Returns Promise<
          | { ok: true; value: RecurringFeeConfig[] }
          | { error: ServiceError; ok: false },
      >

    • Set (or re-price) the fee. Validates the nominated source account exists and belongs to this customer — jsonb carries no check constraint, so the invariants are enforced here, on the one path that writes the key.

      Preserves the current status, read under the customer row lock, so re-pricing a paused fee does not silently resume billing. billingStartDate is required: every fee says which day of the month it bills on.

      A new or moved start date is refused past a month with a live unpaid invoice, which the sweep would stop charging, or with a manual PLATFORM charge in its month or later. A re-price keeping the stored date skips both checks.

      Parameters

      • __namedParameters: {
            amount: BigNumber;
            billingStartDate: string;
            customerId: string;
            sourceAccountId: string;
        }

      Returns Promise<
          | { ok: true; value: RecurringFeeConfig }
          | {
              error:
                  | ServiceError<"INVALID_FEE_AMOUNT">
                  | ServiceError<"BILLING_START_DATE_REQUIRED">
                  | ServiceError<"INVALID_BILLING_START_DATE">
                  | ServiceError<"LEDGER_ACCOUNT_NOT_FOUND", { sourceAccountId: string }>
                  | ServiceError<
                      "LEDGER_ACCOUNT_CUSTOMER_MISMATCH",
                      { sourceAccountId: string },
                  >
                  | ServiceError<"CUSTOMER_NOT_FOUND", { customerId: string }>
                  | ServiceError<"BILLING_PERIOD_ALREADY_CHARGED", { periodKey: string }>
                  | ServiceError<
                      "RECURRING_FEE_OPEN_MONTH_BEFORE_START",
                      { periodKey: string },
                  >;
              ok: false;
          },
      >

    • Pause or resume billing without discarding the configured amount.

      Parameters

      • __namedParameters: { customerId: string; status: "ACTIVE" | "PAUSED" }

      Returns Promise<
          | { ok: true; value: RecurringFeeConfig }
          | {
              error:
                  | ServiceError<"RECURRING_FEE_NOT_CONFIGURED", { customerId: string }>
                  | ServiceError<"CUSTOMER_NOT_FOUND", { customerId: string }>;
              ok: false;
          },
      >