Versie 0.2.0

This commit is contained in:
Atreides Assets committed 2026-10-29 11:57:29 +01:00
commit e77d8fd373
495 files changed
+81026

No files matched your search

+86
View File
@@ -0,0 +1,86 @@
// Generated, do not edit. sha256:ebad02dba29ae50bcbaf9c21bb59936cf43f6be868e86ac00d0e6055f404b26f
import * as db from '../db.js';
import { ACCOUNT_SOURCE_KINDS } from '../../shared/config.js';
import { fail } from '../../shared/app-error.js';
import { eventsNetByAccount } from './events.js';
import { trackUpdate, trackUpdateWhere, trackDelete, trackDeleteWhere, withOrigin } from './change-log.js';
function mergeCompatibility(survivor, victim) {
const S = ACCOUNT_SOURCE_KINDS[survivor.kind] || [];
const V = ACCOUNT_SOURCE_KINDS[victim.kind] || [];
if ((S.length === 0) !== (V.length === 0)) {
return { ok: false, reason: 'sourceMismatch' };
}
if (V.some(k => !S.includes(k))) {
return { ok: false, reason: 'kindCannotCarry' };
}
return { ok: true, reason: null };
}
export function mergeCheck(survivorId, victimId) {
if (!survivorId || !victimId) return { ok: false, reason: 'pickTwo', counts: null };
if (Number(survivorId) === Number(victimId)) return { ok: false, reason: 'sameAccount', counts: null };
const survivor = db.one(`SELECT * FROM Account WHERE id=?`, [survivorId]);
const victim = db.one(`SELECT * FROM Account WHERE id=?`, [victimId]);
if (!survivor || !victim) return { ok: false, reason: 'notFound', counts: null };
const compat = mergeCompatibility(survivor, victim);
const counts = {
sources: db.one(`SELECT COUNT(*) AS n FROM WalletSource WHERE accountId=?`, [victimId]).n,
events: db.one(`SELECT COUNT(*) AS n FROM Event WHERE fromAccountId=?1 OR toAccountId=?1`, [victimId]).n,
schedules: db.one(`SELECT COUNT(*) AS n FROM InterestSchedule WHERE accountId=?`, [victimId]).n,
valuations: db.one(`SELECT COUNT(*) AS n FROM Valuation WHERE accountId =?`, [victimId]).n,
};
return { ok: compat.ok, reason: compat.reason, counts, survivorName: survivor.name, victimName: victim.name };
}
export async function mergeAccounts(survivorId, victimId) {
survivorId = Number(survivorId); victimId = Number(victimId);
const chk = mergeCheck(survivorId, victimId);
if (!chk.ok) fail(`accounts.mergeReason_${chk.reason}`, null, `Merge not possible (${chk.reason}).`);
return withOrigin('merge', victimId, () => voerSamenvoegingUit(survivorId, victimId, chk));
}
async function voerSamenvoegingUit(survivorId, victimId, chk) {
const preDiff = new Map();
for (const v of db.all(`SELECT id, accountId, assetId, rateAt, balance FROM Valuation WHERE accountId = ?1 OR accountId = ?2`, [survivorId, victimId])) {
preDiff.set(v.id, v.balance - eventsNetByAccount(v.accountId, v.assetId, v.rateAt));
}
trackUpdateWhere('Event', `fromAccountId = ?`, [victimId], () =>
db.run(`UPDATE Event SET fromAccountId=?1 WHERE fromAccountId=?2`, [survivorId, victimId]));
trackUpdateWhere('Event', `toAccountId = ?`, [victimId], () =>
db.run(`UPDATE Event SET toAccountId=?1 WHERE toAccountId=?2`, [survivorId, victimId]));
trackUpdateWhere('WalletSource', `accountId = ?`, [victimId], () =>
db.run(`UPDATE WalletSource SET accountId=?1 WHERE accountId=?2`, [survivorId, victimId]));
db.run(`UPDATE WalletAddress SET accountId=?1 WHERE accountId=?2`, [survivorId, victimId]);
db.run(`UPDATE WalletTransaction SET accountId=?1 WHERE accountId=?2`, [survivorId, victimId]);
db.run(`UPDATE ScanLog SET accountId=?1 WHERE accountId=?2`, [survivorId, victimId]);
db.run(`UPDATE ReconcileProposal SET accountId=?1 WHERE accountId=?2`, [survivorId, victimId]);
db.run(`UPDATE ImportBatch SET accountId=?1 WHERE accountId=?2`, [survivorId, victimId]);
trackUpdateWhere('InterestSchedule', `accountId = ?`, [victimId], () =>
db.run(`UPDATE InterestSchedule SET accountId=?1 WHERE accountId=?2`, [survivorId, victimId]));
trackDeleteWhere('Valuation', `accountId = ?2
AND EXISTS (SELECT 1 FROM Valuation v2 WHERE v2.accountId = ?1
AND v2.assetId=Valuation.assetId AND v2.valuedOn=Valuation.valuedOn)`,
[survivorId, victimId], () =>
db.run(`DELETE FROM Valuation WHERE accountId =?2
AND EXISTS (SELECT 1 FROM Valuation v2 WHERE v2.accountId =?1
AND v2.assetId=Valuation.assetId AND v2.valuedOn=Valuation.valuedOn)`,
[survivorId, victimId]));
trackUpdateWhere('Valuation', `accountId = ?`, [victimId], () =>
db.run(`UPDATE Valuation SET accountId =?1 WHERE accountId = ?2`, [survivorId, victimId]));
for (const [id, diff] of preDiff) {
const v = db.one(`SELECT id, assetId, rateAt FROM Valuation WHERE id=?`, [id]);
if (!v) continue;
const newNet = eventsNetByAccount(survivorId, v.assetId, v.rateAt);
trackUpdate('Valuation', id, () =>
db.run(`UPDATE Valuation SET balance=? WHERE id=?`, [newNet + diff, id]));
}
trackDelete('Account', victimId, () => db.run(`DELETE FROM Account WHERE id=?`, [victimId]));
await db.persist();
return chk.counts;
}