118 lines
5.8 KiB
JavaScript
118 lines
5.8 KiB
JavaScript
// Generated, do not edit. sha256:defdf4c970fac7940f2bd495e2911283709af51809bb6a2d4c4f9c43ed032b8f
|
|
import * as db from '../db.js';
|
|
import { toSearchName } from '../../shared/search-name.js';
|
|
import { nowUtcIso } from '../../shared/time.js';
|
|
import { ENUMS } from '../../shared/config.js';
|
|
import { assertEnum, assertName, assertTaxCategory, assertTaxScope, assertWealthScope } from './_shared.js';
|
|
import { capacityReachedFor } from './_limits.js';
|
|
import { fail } from '../../shared/app-error.js';
|
|
import { purgeWalletSourceSecret } from './wallet-sources.js';
|
|
import { accountPositions } from './positions.js';
|
|
import { trackUpdate, trackDelete } from './change-log.js';
|
|
|
|
export function listAccounts() {
|
|
return db.all(`SELECT * FROM Account ORDER BY name`);
|
|
}
|
|
|
|
export function listSelectableAccounts({ metGesloten = false, ookId = null } = {}) {
|
|
return metGesloten
|
|
? db.all(`SELECT * FROM Account ORDER BY isActive DESC, name`)
|
|
: db.all(`SELECT * FROM Account WHERE isActive = 1 OR id = ?1 ORDER BY isActive DESC, name`,
|
|
[ookId ?? null]);
|
|
}
|
|
export async function createAccount({ name, kind, isOwnCustody, scanEnabled, taxCategory, taxScope, wealthScope }) {
|
|
assertEnum('kind', ENUMS.ACCOUNT_KIND, kind);
|
|
if (kind === 'bank') {
|
|
const max = capacityReachedFor('fiatAccounts');
|
|
if (max !== null) {
|
|
fail('accounts.maxFreeBank', { max },
|
|
`The free version holds ${max} fiat account(s). A licence lifts that; nothing is removed in the meantime.`);
|
|
}
|
|
}
|
|
const naam = assertName('Accountnaam', name);
|
|
const categorie = assertTaxCategory(taxCategory);
|
|
const scope = assertTaxScope(taxScope);
|
|
const wealth = assertWealthScope(wealthScope);
|
|
db.run(`INSERT INTO Account (name, searchName, kind, isOwnCustody, scanEnabled, isActive, closedAt, taxCategory, taxScope, wealthScope)
|
|
VALUES (?,?,?,?,?,1,NULL,?,?,?)`,
|
|
[naam, toSearchName(naam), kind, isOwnCustody ? 1 : 0, scanEnabled ? 1 : 0, categorie, scope, wealth]);
|
|
const id = db.lastId();
|
|
await db.persist();
|
|
return id;
|
|
}
|
|
export async function updateAccount(id, a) {
|
|
assertEnum('kind', ENUMS.ACCOUNT_KIND, a.kind);
|
|
const naam = assertName('Accountnaam', a.name);
|
|
const categorie = assertTaxCategory(a.taxCategory);
|
|
const scopeGiven = Object.hasOwn(a, 'taxScope');
|
|
const scope = scopeGiven ? assertTaxScope(a.taxScope) : null;
|
|
const wealthGiven = Object.hasOwn(a, 'wealthScope');
|
|
const wealth = wealthGiven ? assertWealthScope(a.wealthScope) : null;
|
|
trackUpdate('Account', id, () =>
|
|
db.run(`UPDATE Account SET name=?, searchName=?, kind=?, isOwnCustody=?, scanEnabled=?, taxCategory=?,
|
|
taxScope = CASE WHEN ? THEN ? ELSE taxScope END,
|
|
wealthScope = CASE WHEN ? THEN ? ELSE wealthScope END WHERE id=?`,
|
|
[naam, toSearchName(naam), a.kind, a.isOwnCustody ? 1 : 0, a.scanEnabled ? 1 : 0, categorie,
|
|
scopeGiven ? 1 : 0, scope, wealthGiven ? 1 : 0, wealth, id]));
|
|
await db.persist();
|
|
}
|
|
export async function deleteAccount(id) {
|
|
const used = db.one(`SELECT (SELECT COUNT(*) FROM Event WHERE fromAccountId=?1 OR toAccountId=?1)
|
|
+ (SELECT COUNT(*) FROM Valuation WHERE accountId =?1)
|
|
+ (SELECT COUNT(*) FROM ScanLog WHERE accountId=?1)
|
|
+ (SELECT COUNT(*) FROM ReconcileProposal WHERE accountId=?1) AS n`, [id]).n;
|
|
if (used > 0) fail('accounts.inUse', { n: used }, `Account is used by ${used} record(s); remove or relink those first.`);
|
|
for (const s of db.all(`SELECT id FROM WalletSource WHERE accountId=? AND kind='nwc'`, [id])) {
|
|
await purgeWalletSourceSecret(s.id);
|
|
}
|
|
trackDelete('Account', id, () => db.run(`DELETE FROM Account WHERE id=?`, [id]));
|
|
await db.persist();
|
|
}
|
|
|
|
export function deactivateCheck(accountId) {
|
|
const account = db.one(`SELECT * FROM Account WHERE id = ?`, [accountId]);
|
|
if (!account) return { found: false, findings: [] };
|
|
|
|
const n = (sql, params = [accountId]) => db.one(sql, params).n;
|
|
const findings = [];
|
|
|
|
if (account.scanEnabled) {
|
|
findings.push({ kind: 'scanEnabled', count: 1 });
|
|
}
|
|
const sources = n(`SELECT COUNT(*) AS n FROM WalletSource WHERE accountId = ?`);
|
|
if (sources) findings.push({ kind: 'walletSources', count: sources });
|
|
|
|
const vandaag = new Date().toISOString().slice(0, 10);
|
|
const schedules = n(
|
|
`SELECT COUNT(*) AS n FROM InterestSchedule
|
|
WHERE accountId = ? AND (endsOn IS NULL OR endsOn >= ?)`, [accountId, vandaag]);
|
|
if (schedules) findings.push({ kind: 'openSchedules', count: schedules });
|
|
|
|
const proposals = n(`SELECT COUNT(*) AS n FROM ReconcileProposal WHERE accountId = ? AND status = 'pending'`);
|
|
if (proposals) findings.push({ kind: 'pendingProposals', count: proposals });
|
|
|
|
const balances = accountPositions(accountId);
|
|
if (balances.length) findings.push({ kind: 'balance', count: balances.length, balances });
|
|
|
|
const events = n(`SELECT COUNT(*) AS n FROM Event WHERE fromAccountId = ?1 OR toAccountId = ?1`);
|
|
if (events) findings.push({ kind: 'events', count: events, informational: true });
|
|
|
|
return { found: true, isActive: !!account.isActive, name: account.name, findings };
|
|
}
|
|
|
|
export async function deactivateAccount(id, closedAt = nowUtcIso()) {
|
|
const account = db.one(`SELECT isActive FROM Account WHERE id = ?`, [id]);
|
|
if (!account) fail('accounts.unknownAccount', { id }, `Account #${id} does not exist.`);
|
|
trackUpdate('Account', id, () =>
|
|
db.run(`UPDATE Account SET isActive = 0, closedAt = ?, scanEnabled = 0 WHERE id = ?`, [closedAt, id]));
|
|
await db.persist();
|
|
}
|
|
|
|
export async function reactivateAccount(id) {
|
|
const account = db.one(`SELECT isActive FROM Account WHERE id = ?`, [id]);
|
|
if (!account) fail('accounts.unknownAccount', { id }, `Account #${id} does not exist.`);
|
|
trackUpdate('Account', id, () =>
|
|
db.run(`UPDATE Account SET isActive = 1, closedAt = NULL WHERE id = ?`, [id]));
|
|
await db.persist();
|
|
}
|