// A refusal of the Ledger service reaches the person as the kit's sentence for it, in their language. // Before the kit helper, the module mapped refusals itself and compared a `BusinessErrorCode` with Ledger's // reasons (`unbalanced`, `insufficient-funds`), which it never is: an unbalanced posting was answered // "reload the ledger record". Generated HTTP client with a synthetic binding; no gateway/live acceptance. import type { RequestBusinessBinding } from "@conusai-kit/business" import { describeBusinessRefusal } from "@conusai-kit/business/refusals" import { describe, expect, it } from "vitest" import { sdkLedgerService } from "../adapters/service.js" import { LEDGER_ERRORS } from "../contract/index.js" import type { LedgerService } from "../core/ports.js" import { en } from "../i18n/en.js" import { lt } from "../i18n/lt.js" import { ledgerFailure } from "../ui/errors.js" import { ledgerLabels } from "../ui/labels.js" const id = "acc_00000000-0000-4000-8000-000000000001" function refusing(reason: string, status: number) { const binding = { orgSlug: "verified-org", client: (factory: Parameters[0]) => { const client = factory({ baseUrl: "https://ledger.example.test", auth: "synthetic", throwOnError: false }) client.setConfig({ fetch: async () => new Response( JSON.stringify({ type: `urn:conusai:ledger:${reason}`, status, code: `LEDGER_${reason.replaceAll("-", "_").toUpperCase()}`, title: "Ledger request refused", }), { status, headers: { "content-type": "application/json" } }, ), }) return client }, } as RequestBusinessBinding return sdkLedgerService(binding) } const terms: Parameters[0] = { effectiveAt: "2026-11-03T00:00:00Z", description: "Synthetic", status: "posted", entries: [ { accountId: id, direction: "debit", amountMinor: "100" }, { accountId: id, direction: "credit", amountMinor: "99" }, ], } async function refusalOf(reason: string, status: number): Promise { try { await refusing(reason, status).record(terms, "stable-key") } catch (error) { return error } throw new Error("expected a refusal") } describe("Ledger refusals through the kit", () => { it("tells the person an unbalanced posting does not balance, in English and Lithuanian", async () => { const error = await refusalOf("unbalanced", 409) expect(error).toHaveProperty("problem.code", "business_unbalanced") expect(error).toHaveProperty("problem.status", 409) expect(describeBusinessRefusal(error, "en")).toBe("Debits and credits do not balance.") expect(describeBusinessRefusal(error, "lt")).toBe("Debetas ir kreditas nesutampa.") }) it("names insufficient funds and a transaction's state as such", async () => { expect(await refusalOf("insufficient-funds", 409)).toHaveProperty("problem.code", "business_insufficient_funds") expect(await refusalOf("transaction-state", 409)).toHaveProperty("problem.code", "business_transaction_state") }) it("shows a form the kit's sentence, a conflict in this module's words, and the module's own drift fence", async () => { const labelsOf = (messages: Record, locale: "en" | "lt") => ledgerLabels((key) => messages[key] ?? key, locale) const english = labelsOf(en, "en") const lithuanian = labelsOf(lt, "lt") expect(ledgerFailure(await refusalOf("unbalanced", 409), english)).toBe("Debits and credits do not balance.") expect(ledgerFailure(await refusalOf("unbalanced", 409), lithuanian)).toBe("Debetas ir kreditas nesutampa.") expect(ledgerFailure(await refusalOf("revision-conflict", 409), english)).toBe(en.revisionConflict) expect(ledgerFailure(await refusalOf("idempotency-conflict", 409), lithuanian)).toBe(lt.idempotencyConflict) expect(ledgerFailure({ problem: { code: LEDGER_ERRORS.drift } }, english)).toBe(en.drift) }) })