Files
AtreidesAssetsFree/server/data/assets.js
T
2026-10-29 11:57:29 +01:00

85 lines
4.2 KiB
JavaScript

// Generated, do not edit. sha256:ae0d48181a52fd75f129b890a9ec73664ed0e72770dbab20484d6647df3ef532
import * as db from '../db.js';
import { toSearchName } from '../../shared/search-name.js';
import { CONFIG, ENUMS } from '../../shared/config.js';
import { assertEnum, assertTaxCategory, assertTaxScope, RATE_ONLY_ASSET } from './_shared.js';
import { capacityReachedFor } from './_limits.js';
import { allowedAssets } from '../license.mjs';
import { fail } from '../../shared/app-error.js';
import { trackDelete, trackUpdate } from './change-log.js';
export function listAssets() { return db.all(`SELECT * FROM Asset ORDER BY symbol`); }
export function listBookableAssets() {
return db.all(`SELECT * FROM Asset WHERE NOT ${RATE_ONLY_ASSET} ORDER BY symbol`);
}
function assertDecimals(decimals) {
const leesbaar = typeof decimals === 'number'
|| (typeof decimals === 'string' && decimals.trim() !== '');
const n = leesbaar ? Number(decimals) : NaN;
if (!Number.isInteger(n) || n < 0 || n > CONFIG.MAX_ASSET_DECIMALS) {
fail('assets.decimalsRange', { max: CONFIG.MAX_ASSET_DECIMALS, waarde: decimals },
`Decimals has to be a whole number from 0 to ${CONFIG.MAX_ASSET_DECIMALS} (got: '${decimals}'); `
+ 'above that an amount can no longer be read back.');
}
}
function assertBalanceCapture(value) {
if (value == null || value === '') return null;
const n = Number(value);
if (n !== 0 && n !== 1) throw new Error(`Invalid balanceCapture: '${value}'. Allowed: empty, 0, 1.`);
return n;
}
export async function createAsset({ symbol, name, kind, unit, subunit, decimals, displayUnit, taxCategory, taxScope, balanceCapture }) {
const allowed = allowedAssets();
if (allowed && kind !== 'fiat' && !allowed.includes(symbol)) {
fail('assets.freeOnly', { list: allowed.join(', ') },
`The free version holds ${allowed.join(', ')} and currencies only. A licence lifts that.`);
}
const max = capacityReachedFor('assets');
if (max !== null) {
fail('assets.maxFree', { max },
`The free version holds ${max} asset(s). A licence lifts that; nothing is removed in the meantime.`);
}
assertEnum('kind', ENUMS.ASSET_KIND, kind);
assertEnum('displayUnit', ENUMS.ASSET_DISPLAY_UNIT, displayUnit);
assertDecimals(decimals);
const categorie = assertTaxCategory(taxCategory);
const capture = assertBalanceCapture(balanceCapture);
const scope = assertTaxScope(taxScope);
db.run(`INSERT INTO Asset (symbol, name, searchName, kind, unit, subunit, decimals, displayUnit, taxCategory, taxScope, balanceCapture)
VALUES (?,?,?,?,?,?,?,?,?,?,?)`,
[symbol, name, toSearchName(name), kind, unit, subunit ?? null, decimals, displayUnit, categorie, scope, capture]);
const id = db.lastId();
db.seedPriceSource(id, 'confirmed');
await db.persist();
return id;
}
export async function updateAsset(id, a) {
assertEnum('kind', ENUMS.ASSET_KIND, a.kind);
assertEnum('displayUnit', ENUMS.ASSET_DISPLAY_UNIT, a.displayUnit);
assertDecimals(a.decimals);
const categorie = assertTaxCategory(a.taxCategory);
const given = Object.hasOwn(a, 'balanceCapture');
const capture = given ? assertBalanceCapture(a.balanceCapture) : null;
const scopeGiven = Object.hasOwn(a, 'taxScope');
const scope = scopeGiven ? assertTaxScope(a.taxScope) : null;
trackUpdate('Asset', id, () =>
db.run(`UPDATE Asset SET symbol=?, name=?, searchName=?, kind=?, unit=?, subunit=?, decimals=?, displayUnit=?, taxCategory=?,
taxScope = CASE WHEN ? THEN ? ELSE taxScope END,
balanceCapture = CASE WHEN ? THEN ? ELSE balanceCapture END WHERE id=?`,
[a.symbol, a.name, toSearchName(a.name), a.kind, a.unit, a.subunit ?? null, a.decimals, a.displayUnit, categorie,
scopeGiven ? 1 : 0, scope, given ? 1 : 0, capture, id]));
await db.persist();
}
export async function deleteAsset(id) {
const used = db.one(`SELECT (SELECT COUNT(*) FROM Event WHERE assetId=?1)
+ (SELECT COUNT(*) FROM Valuation WHERE assetId=?1)
+ (SELECT COUNT(*) FROM ReconcileProposal WHERE assetId=?1) AS n`, [id]).n;
if (used > 0) fail('assets.inUse', { n: used }, `The asset is used by ${used} record(s).`);
trackDelete('Asset', id, () => db.run(`DELETE FROM Asset WHERE id=?`, [id]));
await db.persist();
}