| 1 | import assert from "node:assert/strict"; |
| 2 | import { readFileSync, readdirSync } from "node:fs"; |
| 3 | import { DatabaseSync } from "node:sqlite"; |
| 4 | import { test } from "node:test"; |
| 5 | |
| 6 | // Complimentary enrollment against the complete migrated schema, using the |
| 7 | // production SQL: the allocation that posts usage, and the terms change as |
| 8 | // `admin_set_complimentary` writes it. |
| 9 | const source = name => readFileSync(new URL(`../services/billing/src/${name}.rs`, import.meta.url), "utf8"); |
| 10 | const sqlFile = name => readFileSync(new URL(`../services/billing/src/${name}.sql`, import.meta.url), "utf8"); |
| 11 | const constant = (file, name) => { |
| 12 | const match = source(file).match(new RegExp(`const ${name}: &str = "([\\s\\S]*?)";`)); |
| 13 | assert.ok(match, `${file}::${name}`); |
| 14 | return match[1]; |
| 15 | }; |
| 16 | const prepares = (file, from, to) => { |
| 17 | const text = source(file).split(from)[1].split(to)[0]; |
| 18 | return [...text.matchAll(/\.prepare\(\s*"([\s\S]*?)"\s*,?\s*\)/g)].map(m => m[1]); |
| 19 | }; |
| 20 | const migrations = new URL("../services/billing/migrations/", import.meta.url); |
| 21 | const names = readdirSync(migrations).filter(n => n.endsWith(".sql")).sort(); |
| 22 | function database(before = null) { |
| 23 | const db = new DatabaseSync(":memory:"); |
| 24 | for (const name of names.filter(n => before === null || n < before)) db.exec(readFileSync(new URL(name, migrations), "utf8")); |
| 25 | return db; |
| 26 | } |
| 27 | function batch(db, writes) { |
| 28 | db.exec("BEGIN"); |
| 29 | try { for (const [sql, args] of writes) db.prepare(sql).run(...args); db.exec("COMMIT"); } |
| 30 | catch (e) { db.exec("ROLLBACK"); throw e; } |
| 31 | } |
| 32 | const at = "2026-10-14T12:00:00.000Z"; |
| 33 | function usage(id, reference, workspace, gross, { plan = 10_000_000, trial = 1, given = 0, when = at } = {}) { |
| 34 | const insert = prepares("storage", "pub(crate) async fn post_usage_with(", "/// Takes `charged`")[0]; |
| 35 | const balance = prepares("storage", "pub(crate) fn balance_if_posted(", "/// Writes down")[0]; |
| 36 | const month = when.slice(0, 7); |
| 37 | return [ |
| 38 | [insert, [id, workspace, -gross, "Usage", `${workspace}/repo`, "sandbox", gross, reference, when, 0, 0, 0, 0, null]], |
| 39 | [sqlFile("allocate_usage"), [id, workspace, month, plan, trial, `${workspace}/repo`, 1_000_000, 1_000_000, given]], |
| 40 | [constant("allocation", "PLAN"), [id, month]], |
| 41 | [constant("allocation", "GIFT"), [id, month]], |
| 42 | [constant("allocation", "TRIAL"), [id]], |
| 43 | [constant("allocation", "OSS_POOL"), [id, month]], |
| 44 | [constant("allocation", "OSS_REPO"), [id, month, `${workspace}/repo`]], |
| 45 | [balance, [workspace, when, id]], |
| 46 | ]; |
| 47 | } |
| 48 | const enrolledAt = "2026-10-01T00:00:00.000Z"; |
| 49 | function enroll(db, workspace, allowance, { unlimited = 0, overage = "stop" } = {}) { |
| 50 | db.prepare(`INSERT INTO complimentary (workspace, grant_id, status, allowance_micros, unlimited, fee_cents, note, created_by, created_at, created_ms, updated_by, updated_at, subscription_id, overage) |
| 51 | VALUES (?, ?, 'active', ?, ?, 0, 'partner', 'staff', ?, 0, 'staff', ?, ?, ?)`).run(workspace, `cmp_${workspace}`, allowance, unlimited, enrolledAt, enrolledAt, `sub_${workspace}`, overage); |
| 52 | db.prepare(`INSERT INTO complimentary_periods (id, workspace, grant_id, starts_at, allowance_micros, unlimited, fee_cents, note, created_by, created_at, overage) |
| 53 | VALUES (?, ?, ?, ?, ?, ?, 0, 'partner', 'staff', ?, ?)`).run(`p_${workspace}`, workspace, `cmp_${workspace}`, enrolledAt, allowance, unlimited, enrolledAt, overage); |
| 54 | } |
| 55 | const termsChange = prepares("complimentary", "// One batch: the open period closes", "self.audit("); |
| 56 | function changeTerms(db, workspace, allowance, when, overage = "stop") { |
| 57 | assert.equal(termsChange.length, 3); |
| 58 | batch(db, [ |
| 59 | [termsChange[0], [workspace, when]], |
| 60 | [termsChange[1], [`p_${when}`, workspace, `cmp_${workspace}`, when, allowance, 0, 0, "changed", "staff", overage]], |
| 61 | [termsChange[2], [workspace, allowance, 0, 0, "changed", "staff", when, JSON.stringify({ op: "terms", period: `p_${when}` }), overage]], |
| 62 | ]); |
| 63 | } |
| 64 | const line = (db, id) => ({ ...db.prepare("SELECT amount_micros, credit_micros, gift_micros, trial_micros, oss_micros, given_micros FROM ledger WHERE id=?").get(id) }); |
| 65 | const giftUsed = (db, workspace, month = "2026-10") => |
| 66 | db.prepare("SELECT used FROM allowance_use WHERE kind='complimentary' AND scope=? AND month=?").get(workspace, month)?.used ?? 0; |
| 67 | |
| 68 | test("a complimentary allowance pays first and alone, and past it g1t covers rather than charging", () => { |
| 69 | const db = database(); |
| 70 | enroll(db, "acme", 10_000_000); |
| 71 | db.prepare("INSERT INTO trial_grants (workspace, month, granted_micros, used_micros, created_at) VALUES ('acme', '2026-10', 5000000, 0, ?)").run(at); |
| 72 | batch(db, usage("a", "run/a", "acme", 6_000_000)); |
| 73 | assert.deepEqual(line(db, "a"), { amount_micros: 0, credit_micros: 0, gift_micros: 6_000_000, trial_micros: 0, oss_micros: 0, given_micros: 0 }); |
| 74 | // Running work that outlasts the allowance: the rest is g1t's, recorded |
| 75 | // apart from the allowance, and nothing is owed. |
| 76 | batch(db, usage("b", "run/b", "acme", 6_000_000)); |
| 77 | assert.deepEqual(line(db, "b"), { amount_micros: 0, credit_micros: 0, gift_micros: 4_000_000, trial_micros: 0, oss_micros: 0, given_micros: 2_000_000 }); |
| 78 | assert.equal(giftUsed(db, "acme"), 10_000_000); |
| 79 | assert.equal(db.prepare("SELECT balance_micros FROM accounts WHERE workspace='acme'").get().balance_micros, 0); |
| 80 | // Plan credit, the trial and the pools were never touched. |
| 81 | assert.equal(db.prepare("SELECT COUNT(*) n FROM allowance_use WHERE kind IN ('plan_credit','oss_pool','oss_repo')").get().n, 0); |
| 82 | assert.equal(db.prepare("SELECT used_micros FROM trial_grants WHERE workspace='acme'").get().used_micros, 0); |
| 83 | // A duplicate delivery consumes nothing more. |
| 84 | batch(db, usage("dup", "run/b", "acme", 6_000_000)); |
| 85 | assert.equal(giftUsed(db, "acme"), 10_000_000); |
| 86 | assert.equal(db.prepare("SELECT COUNT(*) n FROM ledger").get().n, 2); |
| 87 | db.close(); |
| 88 | }); |
| 89 | |
| 90 | test("changing the amount keeps the month's consumption; lowering it never creates a debt", () => { |
| 91 | const db = database(); |
| 92 | enroll(db, "acme", 10_000_000); |
| 93 | batch(db, usage("a", "run/a", "acme", 8_000_000, { when: "2026-10-10T00:00:00.000Z" })); |
| 94 | changeTerms(db, "acme", 5_000_000, "2026-10-11T00:00:00.000Z"); |
| 95 | assert.equal(db.prepare("SELECT COUNT(*) n FROM complimentary_periods WHERE workspace='acme' AND ends_at IS NULL").get().n, 1); |
| 96 | assert.equal(db.prepare("SELECT allowance_micros FROM complimentary WHERE workspace='acme'").get().allowance_micros, 5_000_000); |
| 97 | // Lowered below what was used: nothing more from it, nothing owed. |
| 98 | batch(db, usage("b", "run/b", "acme", 1_000_000, { when: "2026-10-12T00:00:00.000Z" })); |
| 99 | assert.deepEqual(line(db, "b"), { amount_micros: 0, credit_micros: 0, gift_micros: 0, trial_micros: 0, oss_micros: 0, given_micros: 1_000_000 }); |
| 100 | assert.equal(giftUsed(db, "acme"), 8_000_000, "the earlier draw is kept, not reset"); |
| 101 | // Raised: only what is over the month's use is left. |
| 102 | changeTerms(db, "acme", 20_000_000, "2026-10-13T00:00:00.000Z"); |
| 103 | batch(db, usage("c", "run/c", "acme", 15_000_000, { when: "2026-10-14T00:00:00.000Z" })); |
| 104 | assert.equal(line(db, "c").gift_micros, 12_000_000); |
| 105 | assert.equal(line(db, "c").given_micros, 3_000_000); |
| 106 | assert.equal(giftUsed(db, "acme"), 20_000_000); |
| 107 | // A new month starts the allowance again, with no rollover. |
| 108 | batch(db, usage("d", "run/d", "acme", 25_000_000, { when: "2026-11-01T00:00:01.000Z" })); |
| 109 | assert.equal(line(db, "d").gift_micros, 20_000_000); |
| 110 | assert.equal(giftUsed(db, "acme", "2026-11"), 20_000_000); |
| 111 | assert.equal(db.prepare("SELECT SUM(amount_micros) n FROM ledger").get().n, 0, "nothing was ever charged"); |
| 112 | db.close(); |
| 113 | }); |
| 114 | |
| 115 | test("late usage draws on the period it happened in, not the one it is posted in", () => { |
| 116 | const db = database(); |
| 117 | enroll(db, "acme", 10_000_000); |
| 118 | // Converted to the plan on the 15th. |
| 119 | db.exec("UPDATE complimentary_periods SET ends_at='2026-10-15T00:00:00.000Z'; UPDATE complimentary SET status='ended', ended_reason='converted'"); |
| 120 | batch(db, usage("before", "run/before", "acme", 3_000_000, { when: "2026-10-14T23:00:00.000Z" })); |
| 121 | assert.equal(line(db, "before").gift_micros, 3_000_000, "gifted usage is never repriced after conversion"); |
| 122 | assert.equal(line(db, "before").amount_micros, 0); |
| 123 | batch(db, usage("after", "run/after", "acme", 3_000_000, { when: "2026-10-15T01:00:00.000Z" })); |
| 124 | assert.deepEqual(line(db, "after"), { amount_micros: 0, credit_micros: 3_000_000, gift_micros: 0, trial_micros: 0, oss_micros: 0, given_micros: 0 }); |
| 125 | db.close(); |
| 126 | }); |
| 127 | |
| 128 | test("charged past the allowance: g1t pays the allowance, the workspace's own card the rest", () => { |
| 129 | const db = database(); |
| 130 | enroll(db, "friend", 10_000_000, { overage: "charge" }); |
| 131 | // No card yet: past the allowance it is g1t's, never a debt. |
| 132 | batch(db, usage("z", "run/z", "friend", 12_000_000, { when: "2026-11-02T00:00:00.000Z" })); |
| 133 | assert.deepEqual(line(db, "z"), { amount_micros: 0, credit_micros: 0, gift_micros: 10_000_000, trial_micros: 0, oss_micros: 0, given_micros: 2_000_000 }); |
| 134 | db.prepare("INSERT INTO card_checks (workspace, setup_intent, payment_method, checked_by, checked_at) VALUES ('friend', 'seti_1', 'pm_1', 'owner', ?)").run(at); |
| 135 | batch(db, usage("a", "run/a", "friend", 6_000_000)); |
| 136 | batch(db, usage("b", "run/b", "friend", 7_000_000)); |
| 137 | // 4 of 7 from the allowance, 3 charged; nothing covered by g1t. |
| 138 | assert.deepEqual(line(db, "b"), { amount_micros: -3_000_000, credit_micros: 0, gift_micros: 4_000_000, trial_micros: 0, oss_micros: 0, given_micros: 0 }); |
| 139 | assert.equal(db.prepare("SELECT balance_micros FROM accounts WHERE workspace='friend'").get().balance_micros, -3_000_000); |
| 140 | // Switched to stop mid-month: from then, past the allowance is g1t's. |
| 141 | changeTerms(db, "friend", 10_000_000, "2026-10-15T00:00:00.000Z", "stop"); |
| 142 | batch(db, usage("c", "run/c", "friend", 1_000_000, { when: "2026-10-16T00:00:00.000Z" })); |
| 143 | assert.deepEqual(line(db, "c"), { amount_micros: 0, credit_micros: 0, gift_micros: 0, trial_micros: 0, oss_micros: 0, given_micros: 1_000_000 }); |
| 144 | // Usage from before the switch, posted late, keeps the period it happened in. |
| 145 | batch(db, usage("d", "run/d", "friend", 2_000_000, { when: "2026-10-14T00:00:00.000Z" })); |
| 146 | assert.equal(line(db, "d").amount_micros, -2_000_000); |
| 147 | db.close(); |
| 148 | }); |
| 149 | |
| 150 | test("an enrollment's fee paid while enrolled is not evidence of the plan", () => { |
| 151 | const db = database(); |
| 152 | enroll(db, "acme", 10_000_000); |
| 153 | db.exec("UPDATE complimentary_periods SET ends_at='2026-10-15T00:00:00.000Z'"); |
| 154 | const evidence = db.prepare(constant("storage", "PLAN_EVIDENCE")); |
| 155 | db.exec("UPDATE complimentary_periods SET fee_cents = 2500"); |
| 156 | db.prepare("INSERT INTO plan_payments (invoice_id, workspace, amount_micros, paid_at) VALUES ('in_fee', 'acme', 25000000, '2026-10-02T00:00:00.000Z')").run(); |
| 157 | assert.equal(evidence.get("acme", "2026-10-01", "2026-11-01", "2026-10").had, 0); |
| 158 | // The conversion's first plan payment, made while the period is still open, is the plan. |
| 159 | db.prepare("INSERT INTO plan_payments (invoice_id, workspace, amount_micros, paid_at) VALUES ('in_plan', 'acme', 21000000, '2026-10-14T23:59:00.000Z')").run(); |
| 160 | assert.equal(evidence.get("acme", "2026-10-01", "2026-11-01", "2026-10").had, 1); |
| 161 | db.close(); |
| 162 | }); |
| 163 | |
| 164 | test("an unlimited enrollment pays everything and still records what it used", () => { |
| 165 | const db = database(); |
| 166 | enroll(db, "flagon-io", 0, { unlimited: 1 }); |
| 167 | batch(db, usage("a", "run/a", "flagon-io", 900_000_000)); |
| 168 | assert.equal(line(db, "a").gift_micros, 900_000_000); |
| 169 | assert.equal(line(db, "a").given_micros, 0); |
| 170 | assert.equal(giftUsed(db, "flagon-io"), 900_000_000); |
| 171 | db.close(); |
| 172 | }); |
| 173 | |
| 174 | test("an interrupted posting consumes no complimentary allowance", () => { |
| 175 | const db = database(); |
| 176 | enroll(db, "acme", 10_000_000); |
| 177 | db.exec("CREATE TRIGGER fail_balance BEFORE INSERT ON accounts WHEN NEW.workspace='acme' BEGIN SELECT RAISE(ABORT, 'injected failure'); END"); |
| 178 | assert.throws(() => batch(db, usage("a", "run/a", "acme", 4_000_000)), /injected failure/); |
| 179 | assert.equal(giftUsed(db, "acme"), 0); |
| 180 | db.exec("DROP TRIGGER fail_balance"); |
| 181 | batch(db, usage("b", "run/a", "acme", 4_000_000)); |
| 182 | assert.equal(giftUsed(db, "acme"), 4_000_000); |
| 183 | db.close(); |
| 184 | }); |
| 185 | |
| 186 | test("one open period per workspace", () => { |
| 187 | const db = database(); |
| 188 | enroll(db, "acme", 1); |
| 189 | assert.throws(() => db.prepare(`INSERT INTO complimentary_periods (id, workspace, grant_id, starts_at, allowance_micros, note, created_by, created_at) |
| 190 | VALUES ('second', 'acme', 'cmp_acme', ?, 1, 'x', 'staff', ?)`).run(at, at), /UNIQUE/); |
| 191 | db.close(); |
| 192 | }); |
| 193 | |
| 194 | test("migration 0065 returns every workspace but flagon-io to Free, with an audit entry", () => { |
| 195 | const db = database("0065"); |
| 196 | const account = db.prepare("INSERT INTO billing_accounts (id, kind, name, terms_kind, discount_percent, team_granted, created_by, created_at) VALUES (?, ?, ?, ?, ?, ?, 'staff', ?)"); |
| 197 | account.run("ws_flagon-io-x", "workspace", "flagon-io-x", "comped", 100, 0, at); |
| 198 | db.prepare("UPDATE billing_accounts SET terms_kind='custom' WHERE id='ws_flagon-io'").run(); |
| 199 | account.run("ws_partner", "workspace", "partner", "comped", 100, 0, at); |
| 200 | account.run("ws_given", "workspace", "given", "standard", 0, 1, at); |
| 201 | account.run("ws_plain", "workspace", "plain", "standard", 0, 0, at); |
| 202 | db.prepare("INSERT INTO account_members (workspace, account_id, added_by, added_at) VALUES ('member', 'ent_x', 'staff', ?)").run(at); |
| 203 | // One on an enterprise invoice still being made: kept, not a failed deploy. |
| 204 | db.prepare("INSERT INTO account_members (workspace, account_id, added_by, added_at) VALUES ('invoicing', 'ent_y', 'staff', ?)").run(at); |
| 205 | db.prepare("INSERT INTO enterprise_invoice_attempts (account_id, id, payload, created_ms) VALUES ('ent_y', 'att', ?, 1)") |
| 206 | .run(JSON.stringify({ lines: [{ workspace: "invoicing", amountMicros: 1 }] })); |
| 207 | const flagonBefore = db.prepare("SELECT * FROM billing_accounts WHERE id='ws_flagon-io'").get(); |
| 208 | db.exec(readFileSync(new URL(names.find(n => n.startsWith("0065")), migrations), "utf8")); |
| 209 | const terms = Object.fromEntries(db.prepare("SELECT id, terms_kind, discount_percent, team_granted FROM billing_accounts").all().map(r => [r.id, [r.terms_kind, r.discount_percent, r.team_granted]])); |
| 210 | assert.deepEqual({ ...db.prepare("SELECT * FROM billing_accounts WHERE id='ws_flagon-io'").get() }, { ...flagonBefore }, "flagon-io is untouched"); |
| 211 | assert.deepEqual(terms["ws_flagon-io-x"], ["standard", 0, 0], "only flagon-io itself is kept"); |
| 212 | assert.deepEqual(terms.ws_partner, ["standard", 0, 0]); |
| 213 | assert.deepEqual(terms.ws_given, ["standard", 0, 0]); |
| 214 | assert.deepEqual(terms.ws_plain, ["standard", 0, 0]); |
| 215 | assert.deepEqual(db.prepare("SELECT workspace FROM account_members").all().map(r => r.workspace), ["invoicing"]); |
| 216 | const audited = db.prepare("SELECT account FROM admin_actions WHERE by='billing' ORDER BY account").all().map(r => r.account); |
| 217 | assert.deepEqual(audited, ["ent_x", "ws_flagon-io-x", "ws_given", "ws_partner"]); |
| 218 | db.close(); |
| 219 | }); |