1
0
Fork 0

fix(banking): join parent transaction in account provisioning hooks

Thread the Payload request through createAccount/ensurePersonalAccount and the Users beforeChange hook writes so nested creates share the parent transaction instead of failing FK checks on a fresh connection.

Ultraworked with [Sisyphus](https://github.com/code-yeongyu/oh-my-openagent)

Co-authored-by: Sisyphus <clio-agent@sisyphuslabs.ai>
This commit is contained in:
Jason Fraley 2026-08-23 18:51:49 -04:00
parent fc3b961a43
commit a0c4eaabcf
2 changed files with 23 additions and 6 deletions

View file

@ -17,7 +17,7 @@ export const Users: CollectionConfig = {
const userId = doc.id as number;
try {
await ensurePersonalAccount(payload, userId);
await ensurePersonalAccount(payload, userId, req);
} catch (e) {
payload.logger.error(
`[Users] Failed to create personal bank account for user ${userId}: ${e}`,
@ -37,6 +37,7 @@ export const Users: CollectionConfig = {
limit: 1,
depth: 0,
overrideAccess: true,
req,
});
recruit = (ranks as { docs: Array<{ id: number }> }).docs[0];
@ -49,6 +50,7 @@ export const Users: CollectionConfig = {
description: "Entry-level rank for new members.",
},
overrideAccess: true,
req,
});
recruit = { id: created.id };
payload.logger.info("[Users] Created default 'Recruit' rank on demand.");
@ -74,6 +76,7 @@ export const Users: CollectionConfig = {
} as any,
},
overrideAccess: true,
req,
});
} catch (e) {
payload.logger.error(`[Users] Failed to create profile for user ${userId}: ${e}`);

View file

@ -1,3 +1,4 @@
import type { PayloadRequest } from "payload";
import type { BankAccount, BankTransaction } from "@/payload-types";
export type BankAccountType = "treasury" | "faction" | "personal";
@ -70,6 +71,11 @@ export async function createAccount(
ownerFactionId?: number;
ownerUserId?: number;
},
// Optional request carrying a transactionID. Pass it when calling from
// inside another operation's hooks so nested writes join that transaction —
// on a fresh connection the uncommitted parent row is invisible and FK
// checks fail.
req?: PayloadRequest,
): Promise<BankAccount> {
const { name, accountType, ownerFactionId, ownerUserId } = input;
const currencyId = await getMainCurrencyId(payload);
@ -89,12 +95,14 @@ export async function createAccount(
},
overrideAccess: true,
depth: 0,
req,
})) as unknown as BankAccount;
}
export async function ensurePersonalAccount(
payload: PayloadType,
userId: number,
req?: PayloadRequest,
): Promise<BankAccount> {
const existing = (await payload.find({
collection: "bank-accounts",
@ -104,6 +112,7 @@ export async function ensurePersonalAccount(
limit: 1,
depth: 0,
overrideAccess: true,
req,
})) as unknown as { docs: BankAccount[] };
if (existing.docs.length > 0) return existing.docs[0];
@ -113,15 +122,20 @@ export async function ensurePersonalAccount(
id: userId,
depth: 0,
overrideAccess: true,
req,
})
.catch(() => null)) as unknown as { username?: string; displayName?: string } | null;
const label = user?.displayName || user?.username || `User ${userId}`;
return createAccount(payload, {
name: `${label}'s Account`,
accountType: "personal",
ownerUserId: userId,
});
return createAccount(
payload,
{
name: `${label}'s Account`,
accountType: "personal",
ownerUserId: userId,
},
req,
);
}
export async function applyTransaction(