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:
parent
fc3b961a43
commit
a0c4eaabcf
2 changed files with 23 additions and 6 deletions
|
|
@ -17,7 +17,7 @@ export const Users: CollectionConfig = {
|
||||||
const userId = doc.id as number;
|
const userId = doc.id as number;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
await ensurePersonalAccount(payload, userId);
|
await ensurePersonalAccount(payload, userId, req);
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
payload.logger.error(
|
payload.logger.error(
|
||||||
`[Users] Failed to create personal bank account for user ${userId}: ${e}`,
|
`[Users] Failed to create personal bank account for user ${userId}: ${e}`,
|
||||||
|
|
@ -37,6 +37,7 @@ export const Users: CollectionConfig = {
|
||||||
limit: 1,
|
limit: 1,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
|
req,
|
||||||
});
|
});
|
||||||
recruit = (ranks as { docs: Array<{ id: number }> }).docs[0];
|
recruit = (ranks as { docs: Array<{ id: number }> }).docs[0];
|
||||||
|
|
||||||
|
|
@ -49,6 +50,7 @@ export const Users: CollectionConfig = {
|
||||||
description: "Entry-level rank for new members.",
|
description: "Entry-level rank for new members.",
|
||||||
},
|
},
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
|
req,
|
||||||
});
|
});
|
||||||
recruit = { id: created.id };
|
recruit = { id: created.id };
|
||||||
payload.logger.info("[Users] Created default 'Recruit' rank on demand.");
|
payload.logger.info("[Users] Created default 'Recruit' rank on demand.");
|
||||||
|
|
@ -74,6 +76,7 @@ export const Users: CollectionConfig = {
|
||||||
} as any,
|
} as any,
|
||||||
},
|
},
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
|
req,
|
||||||
});
|
});
|
||||||
} catch (e) {
|
} catch (e) {
|
||||||
payload.logger.error(`[Users] Failed to create profile for user ${userId}: ${e}`);
|
payload.logger.error(`[Users] Failed to create profile for user ${userId}: ${e}`);
|
||||||
|
|
|
||||||
|
|
@ -1,3 +1,4 @@
|
||||||
|
import type { PayloadRequest } from "payload";
|
||||||
import type { BankAccount, BankTransaction } from "@/payload-types";
|
import type { BankAccount, BankTransaction } from "@/payload-types";
|
||||||
|
|
||||||
export type BankAccountType = "treasury" | "faction" | "personal";
|
export type BankAccountType = "treasury" | "faction" | "personal";
|
||||||
|
|
@ -70,6 +71,11 @@ export async function createAccount(
|
||||||
ownerFactionId?: number;
|
ownerFactionId?: number;
|
||||||
ownerUserId?: 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> {
|
): Promise<BankAccount> {
|
||||||
const { name, accountType, ownerFactionId, ownerUserId } = input;
|
const { name, accountType, ownerFactionId, ownerUserId } = input;
|
||||||
const currencyId = await getMainCurrencyId(payload);
|
const currencyId = await getMainCurrencyId(payload);
|
||||||
|
|
@ -89,12 +95,14 @@ export async function createAccount(
|
||||||
},
|
},
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
|
req,
|
||||||
})) as unknown as BankAccount;
|
})) as unknown as BankAccount;
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function ensurePersonalAccount(
|
export async function ensurePersonalAccount(
|
||||||
payload: PayloadType,
|
payload: PayloadType,
|
||||||
userId: number,
|
userId: number,
|
||||||
|
req?: PayloadRequest,
|
||||||
): Promise<BankAccount> {
|
): Promise<BankAccount> {
|
||||||
const existing = (await payload.find({
|
const existing = (await payload.find({
|
||||||
collection: "bank-accounts",
|
collection: "bank-accounts",
|
||||||
|
|
@ -104,6 +112,7 @@ export async function ensurePersonalAccount(
|
||||||
limit: 1,
|
limit: 1,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
|
req,
|
||||||
})) as unknown as { docs: BankAccount[] };
|
})) as unknown as { docs: BankAccount[] };
|
||||||
if (existing.docs.length > 0) return existing.docs[0];
|
if (existing.docs.length > 0) return existing.docs[0];
|
||||||
|
|
||||||
|
|
@ -113,15 +122,20 @@ export async function ensurePersonalAccount(
|
||||||
id: userId,
|
id: userId,
|
||||||
depth: 0,
|
depth: 0,
|
||||||
overrideAccess: true,
|
overrideAccess: true,
|
||||||
|
req,
|
||||||
})
|
})
|
||||||
.catch(() => null)) as unknown as { username?: string; displayName?: string } | null;
|
.catch(() => null)) as unknown as { username?: string; displayName?: string } | null;
|
||||||
const label = user?.displayName || user?.username || `User ${userId}`;
|
const label = user?.displayName || user?.username || `User ${userId}`;
|
||||||
|
|
||||||
return createAccount(payload, {
|
return createAccount(
|
||||||
|
payload,
|
||||||
|
{
|
||||||
name: `${label}'s Account`,
|
name: `${label}'s Account`,
|
||||||
accountType: "personal",
|
accountType: "personal",
|
||||||
ownerUserId: userId,
|
ownerUserId: userId,
|
||||||
});
|
},
|
||||||
|
req,
|
||||||
|
);
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function applyTransaction(
|
export async function applyTransaction(
|
||||||
|
|
|
||||||
Loading…
Reference in a new issue