feat(banking): add bank accounts, transactions, and ledger entries collections
This commit is contained in:
parent
83d5b85247
commit
a440623d93
6 changed files with 753 additions and 0 deletions
96
src/collections/banking/BankAccounts.ts
Normal file
96
src/collections/banking/BankAccounts.ts
Normal file
|
|
@ -0,0 +1,96 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
import hasRoles from "@/utils/access-control/hasRoles";
|
||||
|
||||
export const BankAccounts: CollectionConfig = {
|
||||
slug: "bank-accounts",
|
||||
admin: {
|
||||
group: "Banking",
|
||||
useAsTitle: "name",
|
||||
defaultColumns: ["name", "accountType", "ownerUser", "ownerFaction", "balance", "status", "currency"],
|
||||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: ({ req }) => hasRoles(["admin", "developer"], req.user),
|
||||
update: ({ req }) => hasRoles(["admin", "developer"], req.user),
|
||||
delete: isDeveloper,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "name",
|
||||
type: "text",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "Display name for the account (e.g., \"Unit Treasury\", \"Red Faction Reserve\").",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "accountType",
|
||||
type: "select",
|
||||
required: true,
|
||||
defaultValue: "personal",
|
||||
options: [
|
||||
{ label: "Treasury", value: "treasury" },
|
||||
{ label: "Faction", value: "faction" },
|
||||
{ label: "Personal", value: "personal" },
|
||||
],
|
||||
admin: {
|
||||
description: "Treasury = unit-level central funds. Faction = a specific faction's funds. Personal = an individual operator's wallet.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ownerFaction",
|
||||
type: "relationship",
|
||||
relationTo: "factions",
|
||||
admin: {
|
||||
condition: (data, siblingData) =>
|
||||
(siblingData?.accountType ?? data?.accountType) === "faction",
|
||||
description: "The faction that owns this account.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "ownerUser",
|
||||
type: "relationship",
|
||||
relationTo: "users",
|
||||
admin: {
|
||||
condition: (data, siblingData) =>
|
||||
(siblingData?.accountType ?? data?.accountType) === "personal",
|
||||
description: "The operator who owns this personal account.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "currency",
|
||||
type: "relationship",
|
||||
relationTo: "resources",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "The currency this account is denominated in (normally the main currency set in Game Rules).",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "balance",
|
||||
type: "number",
|
||||
defaultValue: 0,
|
||||
admin: {
|
||||
readOnly: true,
|
||||
description: "Current account balance. Maintained automatically by banking transactions.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "status",
|
||||
type: "select",
|
||||
required: true,
|
||||
defaultValue: "open",
|
||||
options: [
|
||||
{ label: "Open", value: "open" },
|
||||
{ label: "Frozen", value: "frozen" },
|
||||
{ label: "Closed", value: "closed" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "createdAt",
|
||||
type: "date",
|
||||
defaultValue: () => new Date().toISOString(),
|
||||
},
|
||||
],
|
||||
};
|
||||
140
src/collections/banking/BankTransactions.ts
Normal file
140
src/collections/banking/BankTransactions.ts
Normal file
|
|
@ -0,0 +1,140 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
|
||||
export const BankTransactions: CollectionConfig = {
|
||||
slug: "bank-transactions",
|
||||
admin: {
|
||||
group: "Banking",
|
||||
useAsTitle: "transactionNumber",
|
||||
defaultColumns: [
|
||||
"transactionNumber",
|
||||
"type",
|
||||
"fromAccount",
|
||||
"toAccount",
|
||||
"amount",
|
||||
"status",
|
||||
"timestamp",
|
||||
],
|
||||
pagination: { defaultLimit: 50 },
|
||||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
},
|
||||
hooks: {
|
||||
beforeValidate: [
|
||||
async ({ data, operation }) => {
|
||||
if (operation === "create" && data && !data.transactionNumber) {
|
||||
const stamp = Date.now().toString(36).toUpperCase();
|
||||
const rand = Math.random().toString(36).slice(2, 6).toUpperCase();
|
||||
return { ...data, transactionNumber: `TXN-${stamp}-${rand}` };
|
||||
}
|
||||
return data;
|
||||
},
|
||||
],
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "transactionNumber",
|
||||
type: "text",
|
||||
required: true,
|
||||
unique: true,
|
||||
admin: {
|
||||
readOnly: true,
|
||||
description: "Auto-generated reference number.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "type",
|
||||
type: "select",
|
||||
required: true,
|
||||
options: [
|
||||
{ label: "Deposit", value: "deposit" },
|
||||
{ label: "Withdrawal", value: "withdrawal" },
|
||||
{ label: "Transfer", value: "transfer" },
|
||||
{ label: "Payment", value: "payment" },
|
||||
{ label: "Fee", value: "fee" },
|
||||
{ label: "Salary", value: "salary" },
|
||||
{ label: "Adjustment", value: "adjustment" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "fromAccount",
|
||||
type: "relationship",
|
||||
relationTo: "bank-accounts",
|
||||
admin: {
|
||||
description: "Source account (empty for external deposits / incoming funds).",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "toAccount",
|
||||
type: "relationship",
|
||||
relationTo: "bank-accounts",
|
||||
admin: {
|
||||
description: "Destination account (empty for external withdrawals / outgoing payments).",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "amount",
|
||||
type: "number",
|
||||
required: true,
|
||||
min: 1,
|
||||
admin: {
|
||||
description: "Gross amount moved. Withdrawals may be split as amount + fee.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "fee",
|
||||
type: "number",
|
||||
defaultValue: 0,
|
||||
min: 0,
|
||||
admin: {
|
||||
description: "Transaction fee debited from the source in addition to the amount.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "memo",
|
||||
type: "textarea",
|
||||
admin: {
|
||||
description: "Human-readable note attached to the transaction.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "actor",
|
||||
type: "relationship",
|
||||
relationTo: "users",
|
||||
admin: {
|
||||
description: "User who initiated the transaction.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "status",
|
||||
type: "select",
|
||||
required: true,
|
||||
defaultValue: "completed",
|
||||
options: [
|
||||
{ label: "Completed", value: "completed" },
|
||||
{ label: "Reversed", value: "reversed" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "reference",
|
||||
type: "relationship",
|
||||
relationTo: "bank-transactions",
|
||||
admin: {
|
||||
description: "Original transaction, when this one is a reversal.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "timestamp",
|
||||
type: "date",
|
||||
required: true,
|
||||
defaultValue: () => new Date().toISOString(),
|
||||
admin: {
|
||||
date: { pickerAppearance: "dayAndTime" },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
81
src/collections/banking/LedgerEntries.ts
Normal file
81
src/collections/banking/LedgerEntries.ts
Normal file
|
|
@ -0,0 +1,81 @@
|
|||
import { CollectionConfig } from "payload";
|
||||
import { isDeveloper } from "@/utils/access-control/isRole";
|
||||
|
||||
export const LedgerEntries: CollectionConfig = {
|
||||
slug: "ledger-entries",
|
||||
admin: {
|
||||
group: "Banking",
|
||||
useAsTitle: "memo",
|
||||
defaultColumns: ["account", "timestamp", "type", "amount", "balanceAfter"],
|
||||
pagination: { defaultLimit: 50 },
|
||||
},
|
||||
access: {
|
||||
read: ({ req }) => !!req.user,
|
||||
create: isDeveloper,
|
||||
update: isDeveloper,
|
||||
delete: isDeveloper,
|
||||
},
|
||||
fields: [
|
||||
{
|
||||
name: "account",
|
||||
type: "relationship",
|
||||
relationTo: "bank-accounts",
|
||||
required: true,
|
||||
index: true,
|
||||
admin: {
|
||||
description: "The account this ledger entry applies to.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "transaction",
|
||||
type: "relationship",
|
||||
relationTo: "bank-transactions",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "The originating bank transaction.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "type",
|
||||
type: "select",
|
||||
required: true,
|
||||
options: [
|
||||
{ label: "Deposit", value: "deposit" },
|
||||
{ label: "Withdrawal", value: "withdrawal" },
|
||||
{ label: "Transfer", value: "transfer" },
|
||||
{ label: "Payment", value: "payment" },
|
||||
{ label: "Fee", value: "fee" },
|
||||
{ label: "Salary", value: "salary" },
|
||||
{ label: "Adjustment", value: "adjustment" },
|
||||
],
|
||||
},
|
||||
{
|
||||
name: "amount",
|
||||
type: "number",
|
||||
required: true,
|
||||
admin: {
|
||||
description: "Signed amount: positive = credit into the account, negative = debit out.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "balanceAfter",
|
||||
type: "number",
|
||||
admin: {
|
||||
description: "Account balance immediately after this entry was applied.",
|
||||
},
|
||||
},
|
||||
{
|
||||
name: "memo",
|
||||
type: "text",
|
||||
},
|
||||
{
|
||||
name: "timestamp",
|
||||
type: "date",
|
||||
required: true,
|
||||
defaultValue: () => new Date().toISOString(),
|
||||
admin: {
|
||||
date: { pickerAppearance: "dayAndTime" },
|
||||
},
|
||||
},
|
||||
],
|
||||
};
|
||||
|
|
@ -47,6 +47,9 @@ export const enum_game_event_logs_target_collection = pgEnum(
|
|||
"technologies",
|
||||
"maps",
|
||||
"shipments",
|
||||
"bank-accounts",
|
||||
"bank-transactions",
|
||||
"ledger-entries",
|
||||
],
|
||||
);
|
||||
export const enum_users_roles = pgEnum("enum_users_roles", ["guest", "user", "admin", "developer"]);
|
||||
|
|
@ -235,6 +238,38 @@ export const enum_shipments_status = pgEnum("enum_shipments_status", [
|
|||
"failed",
|
||||
"stranded",
|
||||
]);
|
||||
export const enum_bank_accounts_account_type = pgEnum("enum_bank_accounts_account_type", [
|
||||
"treasury",
|
||||
"faction",
|
||||
"personal",
|
||||
]);
|
||||
export const enum_bank_accounts_status = pgEnum("enum_bank_accounts_status", [
|
||||
"open",
|
||||
"frozen",
|
||||
"closed",
|
||||
]);
|
||||
export const enum_bank_transactions_type = pgEnum("enum_bank_transactions_type", [
|
||||
"deposit",
|
||||
"withdrawal",
|
||||
"transfer",
|
||||
"payment",
|
||||
"fee",
|
||||
"salary",
|
||||
"adjustment",
|
||||
]);
|
||||
export const enum_bank_transactions_status = pgEnum("enum_bank_transactions_status", [
|
||||
"completed",
|
||||
"reversed",
|
||||
]);
|
||||
export const enum_ledger_entries_type = pgEnum("enum_ledger_entries_type", [
|
||||
"deposit",
|
||||
"withdrawal",
|
||||
"transfer",
|
||||
"payment",
|
||||
"fee",
|
||||
"salary",
|
||||
"adjustment",
|
||||
]);
|
||||
export const enum_narrative_events_triggers_type = pgEnum("enum_narrative_events_triggers_type", [
|
||||
"manual",
|
||||
"mission_complete",
|
||||
|
|
@ -2103,6 +2138,123 @@ export const shipments_rels = pgTable(
|
|||
],
|
||||
);
|
||||
|
||||
export const bank_accounts = pgTable(
|
||||
"bank_accounts",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
name: varchar("name").notNull(),
|
||||
accountType: enum_bank_accounts_account_type("account_type").notNull().default("personal"),
|
||||
ownerFaction: integer("owner_faction_id").references(() => factions.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
ownerUser: integer("owner_user_id").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
currency: integer("currency_id")
|
||||
.notNull()
|
||||
.references(() => resources.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
balance: numeric("balance", { mode: "number" }).default(0),
|
||||
status: enum_bank_accounts_status("status").notNull().default("open"),
|
||||
createdAt: timestamp("created_at", { mode: "string", withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: "string", withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index("bank_accounts_owner_faction_idx").on(columns.ownerFaction),
|
||||
index("bank_accounts_owner_user_idx").on(columns.ownerUser),
|
||||
index("bank_accounts_currency_idx").on(columns.currency),
|
||||
index("bank_accounts_updated_at_idx").on(columns.updatedAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const bank_transactions = pgTable(
|
||||
"bank_transactions",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
transactionNumber: varchar("transaction_number").notNull(),
|
||||
type: enum_bank_transactions_type("type").notNull(),
|
||||
fromAccount: integer("from_account_id").references(() => bank_accounts.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
toAccount: integer("to_account_id").references(() => bank_accounts.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
amount: numeric("amount", { mode: "number" }).notNull(),
|
||||
fee: numeric("fee", { mode: "number" }).default(0),
|
||||
memo: varchar("memo"),
|
||||
actor: integer("actor_id").references(() => users.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
status: enum_bank_transactions_status("status").notNull().default("completed"),
|
||||
reference: integer("reference_id").references((): AnyPgColumn => bank_transactions.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
timestamp: timestamp("timestamp", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}).notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: "string", withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", { mode: "string", withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
uniqueIndex("bank_transactions_transaction_number_idx").on(columns.transactionNumber),
|
||||
index("bank_transactions_from_account_idx").on(columns.fromAccount),
|
||||
index("bank_transactions_to_account_idx").on(columns.toAccount),
|
||||
index("bank_transactions_actor_idx").on(columns.actor),
|
||||
index("bank_transactions_reference_idx").on(columns.reference),
|
||||
index("bank_transactions_updated_at_idx").on(columns.updatedAt),
|
||||
index("bank_transactions_created_at_idx").on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const ledger_entries = pgTable(
|
||||
"ledger_entries",
|
||||
{
|
||||
id: serial("id").primaryKey(),
|
||||
account: integer("account_id")
|
||||
.notNull()
|
||||
.references(() => bank_accounts.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
transaction: integer("transaction_id")
|
||||
.notNull()
|
||||
.references(() => bank_transactions.id, {
|
||||
onDelete: "set null",
|
||||
}),
|
||||
type: enum_ledger_entries_type("type").notNull(),
|
||||
amount: numeric("amount", { mode: "number" }).notNull(),
|
||||
balanceAfter: numeric("balance_after", { mode: "number" }),
|
||||
memo: varchar("memo"),
|
||||
timestamp: timestamp("timestamp", {
|
||||
mode: "string",
|
||||
withTimezone: true,
|
||||
precision: 3,
|
||||
}).notNull(),
|
||||
updatedAt: timestamp("updated_at", { mode: "string", withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
createdAt: timestamp("created_at", { mode: "string", withTimezone: true, precision: 3 })
|
||||
.defaultNow()
|
||||
.notNull(),
|
||||
},
|
||||
(columns) => [
|
||||
index("ledger_entries_account_idx").on(columns.account),
|
||||
index("ledger_entries_transaction_idx").on(columns.transaction),
|
||||
index("ledger_entries_updated_at_idx").on(columns.updatedAt),
|
||||
index("ledger_entries_created_at_idx").on(columns.createdAt),
|
||||
],
|
||||
);
|
||||
|
||||
export const maps = pgTable(
|
||||
"maps",
|
||||
{
|
||||
|
|
@ -2271,6 +2423,9 @@ export const payload_locked_documents_rels = pgTable(
|
|||
vehiclesID: integer("vehicles_id"),
|
||||
structuresID: integer("structures_id"),
|
||||
shipmentsID: integer("shipments_id"),
|
||||
"bank-accountsID": integer("bank_accounts_id"),
|
||||
"bank-transactionsID": integer("bank_transactions_id"),
|
||||
"ledger-entriesID": integer("ledger_entries_id"),
|
||||
mapsID: integer("maps_id"),
|
||||
"narrative-eventsID": integer("narrative_events_id"),
|
||||
"mission-filesID": integer("mission_files_id"),
|
||||
|
|
@ -2303,6 +2458,11 @@ export const payload_locked_documents_rels = pgTable(
|
|||
index("payload_locked_documents_rels_vehicles_id_idx").on(columns.vehiclesID),
|
||||
index("payload_locked_documents_rels_structures_id_idx").on(columns.structuresID),
|
||||
index("payload_locked_documents_rels_shipments_id_idx").on(columns.shipmentsID),
|
||||
index("payload_locked_documents_rels_bank_accounts_id_idx").on(columns["bank-accountsID"]),
|
||||
index("payload_locked_documents_rels_bank_transactions_id_idx").on(
|
||||
columns["bank-transactionsID"],
|
||||
),
|
||||
index("payload_locked_documents_rels_ledger_entries_id_idx").on(columns["ledger-entriesID"]),
|
||||
index("payload_locked_documents_rels_maps_id_idx").on(columns.mapsID),
|
||||
index("payload_locked_documents_rels_narrative_events_id_idx").on(
|
||||
columns["narrative-eventsID"],
|
||||
|
|
@ -2419,6 +2579,21 @@ export const payload_locked_documents_rels = pgTable(
|
|||
foreignColumns: [shipments.id],
|
||||
name: "payload_locked_documents_rels_shipments_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["bank-accountsID"]],
|
||||
foreignColumns: [bank_accounts.id],
|
||||
name: "payload_locked_documents_rels_bank_accounts_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["bank-transactionsID"]],
|
||||
foreignColumns: [bank_transactions.id],
|
||||
name: "payload_locked_documents_rels_bank_transactions_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["ledger-entriesID"]],
|
||||
foreignColumns: [ledger_entries.id],
|
||||
name: "payload_locked_documents_rels_ledger_entries_fk",
|
||||
}).onDelete("cascade"),
|
||||
foreignKey({
|
||||
columns: [columns["mapsID"]],
|
||||
foreignColumns: [maps.id],
|
||||
|
|
@ -3387,6 +3562,57 @@ export const relations_shipments = relations(shipments, ({ one, many }) => ({
|
|||
relationName: "_rels",
|
||||
}),
|
||||
}));
|
||||
export const relations_bank_accounts = relations(bank_accounts, ({ one }) => ({
|
||||
ownerFaction: one(factions, {
|
||||
fields: [bank_accounts.ownerFaction],
|
||||
references: [factions.id],
|
||||
relationName: "ownerFaction",
|
||||
}),
|
||||
ownerUser: one(users, {
|
||||
fields: [bank_accounts.ownerUser],
|
||||
references: [users.id],
|
||||
relationName: "ownerUser",
|
||||
}),
|
||||
currency: one(resources, {
|
||||
fields: [bank_accounts.currency],
|
||||
references: [resources.id],
|
||||
relationName: "currency",
|
||||
}),
|
||||
}));
|
||||
export const relations_bank_transactions = relations(bank_transactions, ({ one }) => ({
|
||||
fromAccount: one(bank_accounts, {
|
||||
fields: [bank_transactions.fromAccount],
|
||||
references: [bank_accounts.id],
|
||||
relationName: "fromAccount",
|
||||
}),
|
||||
toAccount: one(bank_accounts, {
|
||||
fields: [bank_transactions.toAccount],
|
||||
references: [bank_accounts.id],
|
||||
relationName: "toAccount",
|
||||
}),
|
||||
actor: one(users, {
|
||||
fields: [bank_transactions.actor],
|
||||
references: [users.id],
|
||||
relationName: "actor",
|
||||
}),
|
||||
reference: one(bank_transactions, {
|
||||
fields: [bank_transactions.reference],
|
||||
references: [bank_transactions.id],
|
||||
relationName: "reference",
|
||||
}),
|
||||
}));
|
||||
export const relations_ledger_entries = relations(ledger_entries, ({ one }) => ({
|
||||
account: one(bank_accounts, {
|
||||
fields: [ledger_entries.account],
|
||||
references: [bank_accounts.id],
|
||||
relationName: "account",
|
||||
}),
|
||||
transaction: one(bank_transactions, {
|
||||
fields: [ledger_entries.transaction],
|
||||
references: [bank_transactions.id],
|
||||
relationName: "transaction",
|
||||
}),
|
||||
}));
|
||||
export const relations_maps = relations(maps, () => ({}));
|
||||
export const relations_narrative_events = relations(narrative_events, () => ({}));
|
||||
export const relations_mission_files = relations(mission_files, ({ one }) => ({
|
||||
|
|
@ -3517,6 +3743,21 @@ export const relations_payload_locked_documents_rels = relations(
|
|||
references: [shipments.id],
|
||||
relationName: "shipments",
|
||||
}),
|
||||
"bank-accountsID": one(bank_accounts, {
|
||||
fields: [payload_locked_documents_rels["bank-accountsID"]],
|
||||
references: [bank_accounts.id],
|
||||
relationName: "bank-accounts",
|
||||
}),
|
||||
"bank-transactionsID": one(bank_transactions, {
|
||||
fields: [payload_locked_documents_rels["bank-transactionsID"]],
|
||||
references: [bank_transactions.id],
|
||||
relationName: "bank-transactions",
|
||||
}),
|
||||
"ledger-entriesID": one(ledger_entries, {
|
||||
fields: [payload_locked_documents_rels["ledger-entriesID"]],
|
||||
references: [ledger_entries.id],
|
||||
relationName: "ledger-entries",
|
||||
}),
|
||||
mapsID: one(maps, {
|
||||
fields: [payload_locked_documents_rels.mapsID],
|
||||
references: [maps.id],
|
||||
|
|
@ -3626,6 +3867,11 @@ type DatabaseSchema = {
|
|||
enum_structures_terrain_type: typeof enum_structures_terrain_type;
|
||||
enum_structures_function_type: typeof enum_structures_function_type;
|
||||
enum_shipments_status: typeof enum_shipments_status;
|
||||
enum_bank_accounts_account_type: typeof enum_bank_accounts_account_type;
|
||||
enum_bank_accounts_status: typeof enum_bank_accounts_status;
|
||||
enum_bank_transactions_type: typeof enum_bank_transactions_type;
|
||||
enum_bank_transactions_status: typeof enum_bank_transactions_status;
|
||||
enum_ledger_entries_type: typeof enum_ledger_entries_type;
|
||||
enum_narrative_events_triggers_type: typeof enum_narrative_events_triggers_type;
|
||||
media: typeof media;
|
||||
game_hard_resources: typeof game_hard_resources;
|
||||
|
|
@ -3689,6 +3935,9 @@ type DatabaseSchema = {
|
|||
shipments_cargo: typeof shipments_cargo;
|
||||
shipments: typeof shipments;
|
||||
shipments_rels: typeof shipments_rels;
|
||||
bank_accounts: typeof bank_accounts;
|
||||
bank_transactions: typeof bank_transactions;
|
||||
ledger_entries: typeof ledger_entries;
|
||||
maps: typeof maps;
|
||||
narrative_events: typeof narrative_events;
|
||||
mission_files: typeof mission_files;
|
||||
|
|
@ -3763,6 +4012,9 @@ type DatabaseSchema = {
|
|||
relations_shipments_cargo: typeof relations_shipments_cargo;
|
||||
relations_shipments_rels: typeof relations_shipments_rels;
|
||||
relations_shipments: typeof relations_shipments;
|
||||
relations_bank_accounts: typeof relations_bank_accounts;
|
||||
relations_bank_transactions: typeof relations_bank_transactions;
|
||||
relations_ledger_entries: typeof relations_ledger_entries;
|
||||
relations_maps: typeof relations_maps;
|
||||
relations_narrative_events: typeof relations_narrative_events;
|
||||
relations_mission_files: typeof relations_mission_files;
|
||||
|
|
|
|||
|
|
@ -88,6 +88,9 @@ export interface Config {
|
|||
vehicles: Vehicle;
|
||||
structures: Structure;
|
||||
shipments: Shipment;
|
||||
'bank-accounts': BankAccount;
|
||||
'bank-transactions': BankTransaction;
|
||||
'ledger-entries': LedgerEntry;
|
||||
maps: Map;
|
||||
'narrative-events': NarrativeEvent;
|
||||
'mission-files': MissionFile;
|
||||
|
|
@ -127,6 +130,9 @@ export interface Config {
|
|||
vehicles: VehiclesSelect<false> | VehiclesSelect<true>;
|
||||
structures: StructuresSelect<false> | StructuresSelect<true>;
|
||||
shipments: ShipmentsSelect<false> | ShipmentsSelect<true>;
|
||||
'bank-accounts': BankAccountsSelect<false> | BankAccountsSelect<true>;
|
||||
'bank-transactions': BankTransactionsSelect<false> | BankTransactionsSelect<true>;
|
||||
'ledger-entries': LedgerEntriesSelect<false> | LedgerEntriesSelect<true>;
|
||||
maps: MapsSelect<false> | MapsSelect<true>;
|
||||
'narrative-events': NarrativeEventsSelect<false> | NarrativeEventsSelect<true>;
|
||||
'mission-files': MissionFilesSelect<false> | MissionFilesSelect<true>;
|
||||
|
|
@ -1081,6 +1087,9 @@ export interface GameEventLog {
|
|||
| 'technologies'
|
||||
| 'maps'
|
||||
| 'shipments'
|
||||
| 'bank-accounts'
|
||||
| 'bank-transactions'
|
||||
| 'ledger-entries'
|
||||
)
|
||||
| null;
|
||||
targetId?: number | null;
|
||||
|
|
@ -1609,6 +1618,112 @@ export interface Shipment {
|
|||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "bank-accounts".
|
||||
*/
|
||||
export interface BankAccount {
|
||||
id: number;
|
||||
/**
|
||||
* Display name for the account (e.g., "Unit Treasury", "Red Faction Reserve").
|
||||
*/
|
||||
name: string;
|
||||
/**
|
||||
* Treasury = unit-level central funds. Faction = a specific faction's funds. Personal = an individual operator's wallet.
|
||||
*/
|
||||
accountType: 'treasury' | 'faction' | 'personal';
|
||||
/**
|
||||
* The faction that owns this account.
|
||||
*/
|
||||
ownerFaction?: (number | null) | Faction;
|
||||
/**
|
||||
* The operator who owns this personal account.
|
||||
*/
|
||||
ownerUser?: (number | null) | User;
|
||||
/**
|
||||
* The currency this account is denominated in (normally the main currency set in Game Rules).
|
||||
*/
|
||||
currency: number | Resource;
|
||||
/**
|
||||
* Current account balance. Maintained automatically by banking transactions.
|
||||
*/
|
||||
balance?: number | null;
|
||||
status: 'open' | 'frozen' | 'closed';
|
||||
createdAt: string;
|
||||
updatedAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "bank-transactions".
|
||||
*/
|
||||
export interface BankTransaction {
|
||||
id: number;
|
||||
/**
|
||||
* Auto-generated reference number.
|
||||
*/
|
||||
transactionNumber: string;
|
||||
type: 'deposit' | 'withdrawal' | 'transfer' | 'payment' | 'fee' | 'salary' | 'adjustment';
|
||||
/**
|
||||
* Source account (empty for external deposits / incoming funds).
|
||||
*/
|
||||
fromAccount?: (number | null) | BankAccount;
|
||||
/**
|
||||
* Destination account (empty for external withdrawals / outgoing payments).
|
||||
*/
|
||||
toAccount?: (number | null) | BankAccount;
|
||||
/**
|
||||
* Gross amount moved. Withdrawals may be split as amount + fee.
|
||||
*/
|
||||
amount: number;
|
||||
/**
|
||||
* Transaction fee debited from the source in addition to the amount.
|
||||
*/
|
||||
fee?: number | null;
|
||||
/**
|
||||
* Human-readable note attached to the transaction.
|
||||
*/
|
||||
memo?: string | null;
|
||||
/**
|
||||
* User who initiated the transaction.
|
||||
*/
|
||||
actor?: (number | null) | User;
|
||||
status: 'completed' | 'reversed';
|
||||
/**
|
||||
* Original transaction, when this one is a reversal.
|
||||
*/
|
||||
reference?: (number | null) | BankTransaction;
|
||||
timestamp: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "ledger-entries".
|
||||
*/
|
||||
export interface LedgerEntry {
|
||||
id: number;
|
||||
/**
|
||||
* The account this ledger entry applies to.
|
||||
*/
|
||||
account: number | BankAccount;
|
||||
/**
|
||||
* The originating bank transaction.
|
||||
*/
|
||||
transaction: number | BankTransaction;
|
||||
type: 'deposit' | 'withdrawal' | 'transfer' | 'payment' | 'fee' | 'salary' | 'adjustment';
|
||||
/**
|
||||
* Signed amount: positive = credit into the account, negative = debit out.
|
||||
*/
|
||||
amount: number;
|
||||
/**
|
||||
* Account balance immediately after this entry was applied.
|
||||
*/
|
||||
balanceAfter?: number | null;
|
||||
memo?: string | null;
|
||||
timestamp: string;
|
||||
updatedAt: string;
|
||||
createdAt: string;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "narrative-events".
|
||||
|
|
@ -1758,6 +1873,18 @@ export interface PayloadLockedDocument {
|
|||
relationTo: 'shipments';
|
||||
value: number | Shipment;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'bank-accounts';
|
||||
value: number | BankAccount;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'bank-transactions';
|
||||
value: number | BankTransaction;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'ledger-entries';
|
||||
value: number | LedgerEntry;
|
||||
} | null)
|
||||
| ({
|
||||
relationTo: 'maps';
|
||||
value: number | Map;
|
||||
|
|
@ -2541,6 +2668,55 @@ export interface ShipmentsSelect<T extends boolean = true> {
|
|||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "bank-accounts_select".
|
||||
*/
|
||||
export interface BankAccountsSelect<T extends boolean = true> {
|
||||
name?: T;
|
||||
accountType?: T;
|
||||
ownerFaction?: T;
|
||||
ownerUser?: T;
|
||||
currency?: T;
|
||||
balance?: T;
|
||||
status?: T;
|
||||
createdAt?: T;
|
||||
updatedAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "bank-transactions_select".
|
||||
*/
|
||||
export interface BankTransactionsSelect<T extends boolean = true> {
|
||||
transactionNumber?: T;
|
||||
type?: T;
|
||||
fromAccount?: T;
|
||||
toAccount?: T;
|
||||
amount?: T;
|
||||
fee?: T;
|
||||
memo?: T;
|
||||
actor?: T;
|
||||
status?: T;
|
||||
reference?: T;
|
||||
timestamp?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "ledger-entries_select".
|
||||
*/
|
||||
export interface LedgerEntriesSelect<T extends boolean = true> {
|
||||
account?: T;
|
||||
transaction?: T;
|
||||
type?: T;
|
||||
amount?: T;
|
||||
balanceAfter?: T;
|
||||
memo?: T;
|
||||
timestamp?: T;
|
||||
updatedAt?: T;
|
||||
createdAt?: T;
|
||||
}
|
||||
/**
|
||||
* This interface was referenced by `Config`'s JSON-Schema
|
||||
* via the `definition` "maps_select".
|
||||
|
|
|
|||
|
|
@ -32,6 +32,9 @@ import { GameHardResources } from "@/collections/game/GameHardResources";
|
|||
import { GameEventLogs } from "@/collections/game/GameEventLogs";
|
||||
import { GameVehicles } from "@/collections/game/GameVehicles";
|
||||
import { Experience } from "@/collections/users/Experience";
|
||||
import { BankAccounts } from "@/collections/banking/BankAccounts";
|
||||
import { BankTransactions } from "@/collections/banking/BankTransactions";
|
||||
import { LedgerEntries } from "@/collections/banking/LedgerEntries";
|
||||
import { nodemailerAdapter } from "@payloadcms/email-nodemailer";
|
||||
import nodemailer from "nodemailer";
|
||||
|
||||
|
|
@ -96,6 +99,11 @@ export default buildConfig({
|
|||
Structures,
|
||||
Shipments,
|
||||
|
||||
// Banking
|
||||
BankAccounts,
|
||||
BankTransactions,
|
||||
LedgerEntries,
|
||||
|
||||
// World
|
||||
Maps,
|
||||
NarrativeEvents,
|
||||
|
|
|
|||
Loading…
Reference in a new issue