@accounter/server
Version:
Accounter GraphQL server
134 lines (130 loc) • 4.43 kB
text/typescript
/**
* Transaction factory for test fixtures
*
* Creates minimal transaction objects ready for database insertion.
*
* Based on transactions table schema from migrations:
* - Required: account_id, charge_id, source_id, currency, event_date, amount, current_balance
* - Optional: source_description, debit_date, business_id, is_fee, and other extended fields
*
* @see packages/migrations/src/actions/2024-01-29T13-15-23.initial.ts (transactions table)
*/
import { makeUUID, makeUUIDLegacy } from '../../demo-fixtures/helpers/deterministic-uuid.js';
import { formatNumeric } from './money.js';
/**
* Transaction insert parameters shape
*
* Matches transactions table schema:
* - Numeric fields (amount, current_balance) use string type for PostgreSQL numeric
* - Dates are ISO strings
* - currency is typed as string enum in database
*/
export interface TransactionInsertParams {
id?: string;
account_id: string;
charge_id: string;
source_id: string;
source_description?: string | null;
currency: string;
event_date: string;
debit_date?: string | null;
amount: string; // PostgreSQL numeric -> string
current_balance?: string; // PostgreSQL numeric -> string
business_id?: string | null;
is_fee?: boolean | null;
currency_rate?: number | null;
owner_id: string;
}
/**
* Create a transaction for test fixtures
*
* @param params - Required transaction fields
* @param overrides - Optional overrides for any transaction field
* @returns Transaction object ready for database insertion
*
* @remarks
* - charge_id is required (links transaction to a charge)
* - business_id is required (identifies counterparty for ledger)
* - amount is required and must be string for PostgreSQL numeric
* - currency is required (e.g., 'ILS', 'USD', 'EUR')
* - event_date is required (transaction date)
* - is_fee defaults to false (regular transaction, not a fee)
* - currency_rate defaults to null (foreign currency transactions can specify exchange rate)
* - account_id defaults to deterministic UUID if not provided
* - source_id defaults to deterministic UUID (raw transaction reference)
* - source_description defaults to null
* - debit_date defaults to null (same as event_date in most cases)
* - current_balance defaults to '0' (balance after transaction)
* - id defaults to deterministic UUID if not provided
*
* @example
* ```typescript
* // Minimal transaction with required fields
* const transaction = createTransaction({
* charge_id: makeUUID('charge', 'charge-1'),
* business_id: makeUUID('business', 'supplier-1'),
* amount: '-100.50',
* currency: 'ILS',
* event_date: '2024-01-15',
* });
*
* // Transaction with optional is_fee flag
* const feeTransaction = createTransaction({
* charge_id: makeUUID('charge', 'charge-1'),
* business_id: makeUUID('business', 'bank'),
* amount: '-5.00',
* currency: 'USD',
* event_date: '2024-01-15',
* is_fee: true,
* });
*
* // Transaction with full overrides
* const customTransaction = createTransaction(
* {
* charge_id: makeUUID('charge', 'charge-1'),
* business_id: makeUUID('business', 'supplier-1'),
* amount: '500.00',
* currency: 'EUR',
* event_date: '2024-03-10',
* },
* {
* account_id: makeUUID('account', 'eur-account'),
* source_description: 'Invoice payment EUR',
* debit_date: '2024-03-12',
* current_balance: '15000.00',
* }
* );
* ```
*/
export function createTransaction(
params: {
charge_id: string;
business_id: string;
amount: string | number;
currency: string;
event_date: string | Date;
is_fee?: boolean;
owner_id: string;
},
overrides?: Partial<TransactionInsertParams>,
): TransactionInsertParams {
return {
id: makeUUIDLegacy(),
account_id: makeUUID('account', 'default-account'),
charge_id: params.charge_id,
source_id: makeUUID('transaction-source', 'source-raw-tx'),
source_description: null,
currency: params.currency,
event_date:
typeof params.event_date === 'string'
? params.event_date
: params.event_date.toISOString().slice(0, 10),
debit_date: null,
amount: typeof params.amount === 'string' ? params.amount : formatNumeric(params.amount),
current_balance: '0',
business_id: params.business_id,
is_fee: params.is_fee ?? false,
owner_id: params.owner_id,
...overrides,
};
}