Skip to content

feat: record the advance in the merchant's Xero books - #8

Merged
tela merged 5 commits into
feat/ui-v1from
feat/settle-in-xero
Nov 4, 2026
Merged

tela merged 5 commits into
feat/ui-v1from
feat/settle-in-xero

Conversation

@tela

@tela tela commented Nov 4, 2026

Copy link
Copy Markdown
Contributor

Stacked on #7, which is stacked on #6, #5 and #4. Merge in order: #4, #5, #6, #7, then this. The base branch is feat/ui-v1, and GitHub retargets this once that branch is merged and deleted.

Motivation

Funding moves the money, but the merchant's books still have to show it. This records the advance in the merchant's Xero as the last step of the second click, which completes the arc: apply, offer, accept, fund and settle. Repayment is still held out.

It also fixes a seeding failure against the current Stripe app emulator, which is described below.

Changes

  • fix(acme): seed the bank account with a real Stripe test token: the seeder gave the merchant's first bank account the token btok_us, which Stripe does not have. The old Stripe app emulator accepted any token, but the current build (WonderTwin-AI/wondertwin #483, "resolve or refuse bank account tokens") refuses one it does not know, and seeding failed with No such token: 'btok_us'. It now uses btok_us_verified, one of Stripe's own test tokens, which both builds accept. The line is from feat: seed the ACME world and add reset #4, which is why the fix is in this PR and not a rewrite of the earlier ones.
  • feat(acme): record the advance in the merchant's Xero books: the advance is a loan, so it is booked as money received against a new liability account (810 Working capital advance), which debits the bank and credits the loan. It needs no manual journal. The account and the lender contact are created only if missing, and the bank transaction is found by its reference before it is recorded, so a retry never books the advance twice.
  • feat(acme): add the settle route to the API
  • feat(web): show the settlement and run it on the second click: the second click now accepts, funds and settles. The funding card shows the bank account the advance was received into, the loan account and the bank transaction. A failed settlement retries on its own without paying the advance out again.
  • docs(acme): document settling the advance in Xero

Tests

On the final tip:

$ make vet && make test && make check-kits && make build    # Go, all exit 0
$ pnpm --dir web install --frozen-lockfile && pnpm --dir web lint
$ pnpm --dir web type-check                                # no errors
$ pnpm --dir web test                                      # 3 files, 16 tests passed

Each of the five commits was also checked out on its own and passes gofmt, go vet, go test -race, make check-kits, and the web install, lint, type-check, tests and build.

The Go tests cover the booking (a RECEIVE into bank account 090, from the lender, for $30,000, coded to a CURRLIAB account 810, dated at the end of the history), an existing account and contact that must not be created again, a failed settlement that saves nothing and retries without creating the account or contact twice, and the transaction already being in the books under the application's reference. Four deliberate breakages of the settlement code (the account code, the transaction type, the account type and the date) were each caught by a test.

The fake Stripe now refuses an unknown bank token as the current app emulator does, and putting btok_us back fails four tests. The UI tests cover the three-step second click, the settlement on the funding card, and a settlement that fails once and retries without calling fund again.

Run for real with Plaid, Xero and Stripe built from WonderTwin-AI/wondertwin origin/main at 8e4a7235, which has Xero's bank transactions and account creation and Stripe's bank-token fix. In Chrome the second click showed Received into bank account 090, Booked against Working capital advance 810 and a bank transaction id, with no console problems. Looking inside Xero afterwards:

chart:              810 Working capital advance, CURRLIAB
bank transactions:  RECEIVE, AUTHORISED, 30000, reference app-0001, bank account 090
lender contact:     ACME Commerce Lenders

A second application on the same books gave a second bank transaction (reference app-0002) and still exactly one account 810 and one lender contact.

Not tested: running with the network off, and Xero served by LocalStack, since the plugin does not include it yet.

Related

DOC-581

tela added 5 commits November 3, 2026 22:03
The seeder gave the merchant's first bank account the token btok_us, which Stripe does not have. The old Stripe app emulator accepted any token, but the current one refuses a token it does not know, and seeding failed with No such token. Use btok_us_verified, one of Stripe's own test tokens, which both builds accept.
Funding moves the money, and the merchant's books have to show it. The advance is booked as money received against a new loan liability account, which debits the bank and credits the loan, so it needs no manual journal. The account and the lender contact are created only if missing, and the bank transaction is found by its reference before it is recorded, so a retry never books the advance twice.
The UI's second click now runs accept, fund and settle.
The second click now accepts the offer, pays the advance out and records it in the merchant's Xero books. The funding card shows where it was booked: the bank account it was received into, the loan account and the bank transaction. A failed settlement retries on its own, without paying the advance out again.
Say how the advance is booked, why it needs no manual journal, that every step checks before it creates so a retry or a second application duplicates nothing, and which Xero app emulator builds can do it.
@tela
tela force-pushed the feat/settle-in-xero branch from d91a7cc to 0e367ad Compare November 4, 2026 06:06
@tela
tela merged commit 77f8953 into feat/ui-v1 Nov 4, 2026
2 checks passed
tela added a commit that referenced this pull request Nov 4, 2026
feat(acme): settle the advance in Xero (lands #8 on main)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant