@cfxlabsinc/b2b-services
    Preparing search index...
    Index
    • Charge one customer for one period.

      Idempotent without a pre-check: create is keyed on ${customerId}:${periodKey} and returns the existing transfer rather than making a second one, so a Temporal retry, a concurrent sweep and a manual re-run all converge on the same charge.

      Parameters

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

      Returns Promise<{ ok: true; value: RecurringFeeChargeOutcome }>

    • 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 },
      >

    • 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: "CANCELLED"
                  | "FAILED"
                  | "PENDING"
                  | "SUCCEEDED";
              }[];
          },
      >

    • Customers to charge for periodKey: an ACTIVE fee on an ACTIVE customer with no fee_transfer yet carrying this period's idempotency key.

      The absent transfer is the claim, so the feature needs no cursor and no table of its own. fee_transfer already has a partial unique index on idempotency_key, and CustomerFeeTransferAdminService.create inserts against it with ON CONFLICT DO NOTHING — so a customer who slips through this query twice still cannot be billed twice.

      A customer who could not pay leaves no transfer behind and so stays due: the nightly sweep re-attempts them and bills as soon as the account is funded, rather than writing off the month.

      Parameters

      • __namedParameters: { periodKey: string }

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

    • 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, so re-pricing a paused fee does not silently resume billing.

      Parameters

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

      Returns Promise<
          | { ok: true; value: RecurringFeeConfig }
          | {
              error:
                  | ServiceError<"INVALID_FEE_AMOUNT">
                  | ServiceError<"LEDGER_ACCOUNT_NOT_FOUND", { sourceAccountId: string }>
                  | ServiceError<
                      "LEDGER_ACCOUNT_CUSTOMER_MISMATCH",
                      { sourceAccountId: string },
                  >
                  | ServiceError<"CUSTOMER_NOT_FOUND", { customerId: 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;
          },
      >