mirror of
https://github.com/nestriness/nestri.git
synced 2026-09-28 05:22:26 +03:00
fix(billing): a customer may already exist, and may belong to somebody else
Registering a team assumed creating a subscription would create the customer it names. It does not — the customer has to exist first, and creating one fails if the address is already taken, which it often is: a checkout taken before the team existed leaves one behind, and so does making one by hand. So the lookup is now in three steps. A customer already carrying this team id is used. Otherwise one is found by address and adopted. Otherwise one is made. **A customer carrying a different team's id is left alone.** Taking it would move where that subscription is billed, and the team that lost it would go quiet rather than fail — which is the kind of thing found a month later in a revenue figure that does not add up. A team whose owner has no address yet gets no customer, reported rather than guessed around: an invented address makes a customer nobody can be reached at, and the next call fixes it once there is a real one. Checked against the provider rather than only in tests: all four paths — new, repeated, taken by another team, and no address — behave as written.
This commit is contained in:
@@ -7,6 +7,7 @@ import { Database } from '../db/index.js';
|
||||
import { Examples } from '../examples.js';
|
||||
import { fn } from '../fn.js';
|
||||
import { Identifier } from '../id.js';
|
||||
import { User } from '../user/index.js';
|
||||
import { TeamMemberTable } from './member.sql.js';
|
||||
import { TeamTable } from './team.sql.js';
|
||||
|
||||
@@ -91,7 +92,12 @@ export namespace Team {
|
||||
// idempotent.
|
||||
Database.effect(async () => {
|
||||
try {
|
||||
await Polar.ensureFree({ teamId: input.id });
|
||||
// The owner's address, so a customer can be found or made. A team
|
||||
// created by somebody with no verified address gets no customer
|
||||
// yet, which is a state `ensureFree` reports rather than guesses
|
||||
// its way out of.
|
||||
const owner = await User.fromID(ownerId);
|
||||
await Polar.ensureFree({ teamId: input.id, email: owner?.email ?? undefined });
|
||||
} catch (error) {
|
||||
// eslint-disable-next-line no-console
|
||||
console.error('could not register team with the payment provider:', error);
|
||||
|
||||
Reference in New Issue
Block a user