@fuzzle/opencode-accountant 0.13.15-next.1 → 0.13.16-next.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +120 -64
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -25306,31 +25306,41 @@ function generateSplitEntry(action, oldQuantity, newQuantity, totalCostBasis, cu
|
|
|
25306
25306
|
logger?.debug(`Generating ${splitType} entry: ${oldQuantity} -> ${newQuantity} ${action.symbol}`);
|
|
25307
25307
|
const commodity = formatCommodity(action.symbol);
|
|
25308
25308
|
const totalCost = formatAmount2(totalCostBasis, currency);
|
|
25309
|
-
const
|
|
25309
|
+
const conversionAccount = `equity:conversion:${currency.toLowerCase()}`;
|
|
25310
|
+
const outgoingPostings = [
|
|
25310
25311
|
{
|
|
25311
25312
|
account: `assets:investments:stocks:${action.symbol}`,
|
|
25312
25313
|
amount: `-${formatQuantity(oldQuantity)} ${commodity} @@ ${totalCost}`
|
|
25313
25314
|
},
|
|
25314
25315
|
{
|
|
25315
|
-
account:
|
|
25316
|
-
amount:
|
|
25317
|
-
}
|
|
25316
|
+
account: conversionAccount,
|
|
25317
|
+
amount: totalCost
|
|
25318
|
+
}
|
|
25319
|
+
];
|
|
25320
|
+
const incomingPostings = [
|
|
25318
25321
|
{
|
|
25319
|
-
account:
|
|
25320
|
-
amount:
|
|
25322
|
+
account: conversionAccount,
|
|
25323
|
+
amount: formatAmount2(-totalCostBasis, currency)
|
|
25321
25324
|
},
|
|
25322
25325
|
{
|
|
25323
25326
|
account: `assets:investments:stocks:${action.symbol}`,
|
|
25324
25327
|
amount: `${formatQuantity(newQuantity)} ${commodity} @@ ${totalCost}`
|
|
25325
25328
|
}
|
|
25326
25329
|
];
|
|
25330
|
+
const metadata = ` ; swissquote:order:${action.orderNum} isin:${action.isin}
|
|
25331
|
+
` + ` ; Ratio: ${ratio.toFixed(4)} (${oldQuantity} -> ${newQuantity})
|
|
25332
|
+
`;
|
|
25327
25333
|
let entry = `${date5} ${description}
|
|
25328
25334
|
`;
|
|
25329
|
-
entry +=
|
|
25335
|
+
entry += metadata;
|
|
25336
|
+
entry += formatPostings(outgoingPostings) + `
|
|
25330
25337
|
`;
|
|
25331
|
-
entry += `
|
|
25338
|
+
entry += `
|
|
25332
25339
|
`;
|
|
25333
|
-
entry +=
|
|
25340
|
+
entry += `${date5} ${description}
|
|
25341
|
+
`;
|
|
25342
|
+
entry += metadata;
|
|
25343
|
+
entry += formatPostings(incomingPostings) + `
|
|
25334
25344
|
`;
|
|
25335
25345
|
return entry;
|
|
25336
25346
|
}
|
|
@@ -25371,43 +25381,89 @@ function generateMultiWayMergerEntry(group, crossCurrencyOutgoingSymbols, crossC
|
|
|
25371
25381
|
logger?.debug(`Generating multi-way merger entry: ${outSymbols.join(", ")} -> ${inSymbols.join(", ")}`);
|
|
25372
25382
|
const oldIsins = (crossCurrencyOutgoingIsins ?? group.outgoing.map((a) => a.isin)).filter(Boolean);
|
|
25373
25383
|
const newIsins = group.incoming.map((a) => a.isin).filter(Boolean);
|
|
25374
|
-
|
|
25384
|
+
let metadata = ` ; swissquote:order:${group.orderNum}
|
|
25385
|
+
`;
|
|
25386
|
+
if (oldIsins.length > 0 || newIsins.length > 0) {
|
|
25387
|
+
metadata += ` ; Old ISIN: ${oldIsins.join(", ") || "n/a"}, New ISINs: ${newIsins.join(", ") || "n/a"}
|
|
25388
|
+
`;
|
|
25389
|
+
}
|
|
25390
|
+
const entries = [];
|
|
25375
25391
|
for (let i2 = 0;i2 < group.outgoing.length; i2++) {
|
|
25376
25392
|
const out = group.outgoing[i2];
|
|
25377
25393
|
const qty = formatQuantity(Math.abs(out.quantity));
|
|
25378
25394
|
const commodity = formatCommodity(out.symbol);
|
|
25379
|
-
|
|
25380
|
-
|
|
25381
|
-
|
|
25382
|
-
|
|
25383
|
-
|
|
25384
|
-
|
|
25395
|
+
if (costInfo && costInfo.outgoingTotalCosts[i2] != null) {
|
|
25396
|
+
const costAmount = formatAmount2(costInfo.outgoingTotalCosts[i2], costInfo.currency);
|
|
25397
|
+
const postings = [
|
|
25398
|
+
{
|
|
25399
|
+
account: `assets:investments:stocks:${out.symbol}`,
|
|
25400
|
+
amount: `-${qty} ${commodity} @@ ${costAmount}`
|
|
25401
|
+
},
|
|
25402
|
+
{
|
|
25403
|
+
account: `equity:conversion:${costInfo.currency.toLowerCase()}`,
|
|
25404
|
+
amount: costAmount
|
|
25405
|
+
}
|
|
25406
|
+
];
|
|
25407
|
+
let sub = `${date5} ${description}
|
|
25408
|
+
`;
|
|
25409
|
+
sub += metadata;
|
|
25410
|
+
sub += formatPostings(postings) + `
|
|
25411
|
+
`;
|
|
25412
|
+
entries.push(sub);
|
|
25413
|
+
} else {
|
|
25414
|
+
const postings = [
|
|
25415
|
+
{
|
|
25416
|
+
account: `assets:investments:stocks:${out.symbol}`,
|
|
25417
|
+
amount: `-${qty} ${commodity}`
|
|
25418
|
+
}
|
|
25419
|
+
];
|
|
25420
|
+
let sub = `${date5} ${description}
|
|
25421
|
+
`;
|
|
25422
|
+
sub += metadata;
|
|
25423
|
+
sub += formatPostings(postings) + `
|
|
25424
|
+
`;
|
|
25425
|
+
entries.push(sub);
|
|
25426
|
+
}
|
|
25385
25427
|
}
|
|
25386
25428
|
for (let i2 = 0;i2 < group.incoming.length; i2++) {
|
|
25387
25429
|
const inc = group.incoming[i2];
|
|
25388
25430
|
const qty = formatQuantity(Math.abs(inc.quantity));
|
|
25389
25431
|
const commodity = formatCommodity(inc.symbol);
|
|
25390
|
-
|
|
25391
|
-
|
|
25392
|
-
|
|
25393
|
-
|
|
25394
|
-
|
|
25395
|
-
|
|
25396
|
-
|
|
25397
|
-
|
|
25398
|
-
|
|
25399
|
-
|
|
25400
|
-
|
|
25432
|
+
if (costInfo && costInfo.incomingTotalCosts[i2] != null) {
|
|
25433
|
+
const costAmount = formatAmount2(costInfo.incomingTotalCosts[i2], costInfo.currency);
|
|
25434
|
+
const postings = [
|
|
25435
|
+
{
|
|
25436
|
+
account: `equity:conversion:${costInfo.currency.toLowerCase()}`,
|
|
25437
|
+
amount: formatAmount2(-costInfo.incomingTotalCosts[i2], costInfo.currency)
|
|
25438
|
+
},
|
|
25439
|
+
{
|
|
25440
|
+
account: `assets:investments:stocks:${inc.symbol}`,
|
|
25441
|
+
amount: `${qty} ${commodity} @@ ${costAmount}`
|
|
25442
|
+
}
|
|
25443
|
+
];
|
|
25444
|
+
let sub = `${date5} ${description}
|
|
25401
25445
|
`;
|
|
25402
|
-
|
|
25446
|
+
sub += metadata;
|
|
25447
|
+
sub += formatPostings(postings) + `
|
|
25403
25448
|
`;
|
|
25404
|
-
|
|
25405
|
-
|
|
25449
|
+
entries.push(sub);
|
|
25450
|
+
} else {
|
|
25451
|
+
const postings = [
|
|
25452
|
+
{
|
|
25453
|
+
account: `assets:investments:stocks:${inc.symbol}`,
|
|
25454
|
+
amount: `${qty} ${commodity}`
|
|
25455
|
+
}
|
|
25456
|
+
];
|
|
25457
|
+
let sub = `${date5} ${description}
|
|
25406
25458
|
`;
|
|
25407
|
-
|
|
25408
|
-
|
|
25459
|
+
sub += metadata;
|
|
25460
|
+
sub += formatPostings(postings) + `
|
|
25409
25461
|
`;
|
|
25410
|
-
|
|
25462
|
+
entries.push(sub);
|
|
25463
|
+
}
|
|
25464
|
+
}
|
|
25465
|
+
return entries.join(`
|
|
25466
|
+
`);
|
|
25411
25467
|
}
|
|
25412
25468
|
function generateRightsDistributionEntry(action, logger) {
|
|
25413
25469
|
const date5 = formatDate(action.date);
|
|
@@ -25430,28 +25486,23 @@ function generateRightsDistributionEntry(action, logger) {
|
|
|
25430
25486
|
`;
|
|
25431
25487
|
return entry;
|
|
25432
25488
|
}
|
|
25433
|
-
function
|
|
25489
|
+
function generateDirectWorthlessEntry(date5, orderNum, outgoingSymbols, outgoingIsins, outgoingQuantities, outgoingTotalCosts, totalCostBasis, currency, logger) {
|
|
25434
25490
|
const formattedDate = formatDate(date5);
|
|
25435
25491
|
const symbols = outgoingSymbols.join(" + ");
|
|
25436
|
-
const description = escapeDescription(`Worthless: ${symbols}
|
|
25437
|
-
logger?.debug(`Generating
|
|
25492
|
+
const description = escapeDescription(`Worthless liquidation: ${symbols}`);
|
|
25493
|
+
logger?.debug(`Generating direct worthless entry: ${symbols}, loss: ${totalCostBasis.toFixed(2)} ${currency}`);
|
|
25438
25494
|
const postings = [];
|
|
25439
|
-
|
|
25440
|
-
const
|
|
25441
|
-
|
|
25442
|
-
|
|
25443
|
-
|
|
25444
|
-
|
|
25445
|
-
|
|
25446
|
-
|
|
25447
|
-
|
|
25448
|
-
|
|
25449
|
-
|
|
25450
|
-
postings.push({
|
|
25451
|
-
account: "equity:conversion",
|
|
25452
|
-
amount: `-${formatQuantity(quantity)} ${commodity} @ ${formatPrice(costBasisPerUnit)} ${currency}`
|
|
25453
|
-
});
|
|
25454
|
-
}
|
|
25495
|
+
for (let i2 = 0;i2 < outgoingSymbols.length; i2++) {
|
|
25496
|
+
const symbol2 = outgoingSymbols[i2];
|
|
25497
|
+
const quantity = outgoingQuantities[i2] || 0;
|
|
25498
|
+
const cost = outgoingTotalCosts[i2] || 0;
|
|
25499
|
+
if (quantity <= 0)
|
|
25500
|
+
continue;
|
|
25501
|
+
const commodity = formatCommodity(symbol2);
|
|
25502
|
+
postings.push({
|
|
25503
|
+
account: `assets:investments:stocks:${symbol2}`,
|
|
25504
|
+
amount: `-${formatQuantity(quantity)} ${commodity} @@ ${formatAmount2(cost, currency)}`
|
|
25505
|
+
});
|
|
25455
25506
|
}
|
|
25456
25507
|
postings.push({
|
|
25457
25508
|
account: "expenses:losses:capital",
|
|
@@ -25461,7 +25512,7 @@ function generatePendingMergerWorthlessEntry(date5, orderNum, outgoingSymbols, o
|
|
|
25461
25512
|
`;
|
|
25462
25513
|
entry += ` ; swissquote:order:${orderNum}
|
|
25463
25514
|
`;
|
|
25464
|
-
entry += ` ;
|
|
25515
|
+
entry += ` ; total loss: ${totalCostBasis.toFixed(2)} ${currency}
|
|
25465
25516
|
`;
|
|
25466
25517
|
if (outgoingIsins.length > 0) {
|
|
25467
25518
|
entry += ` ; Original ISINs: ${outgoingIsins.join(", ")}
|
|
@@ -25699,6 +25750,17 @@ function processMultiWayMerger(group, inventory, lotInventoryPath, projectDir, l
|
|
|
25699
25750
|
if (group.outgoing.length === 0 && group.incoming.length > 0) {
|
|
25700
25751
|
const pendingState = loadPendingMerger(projectDir, lotInventoryPath, group.key, logger);
|
|
25701
25752
|
if (pendingState) {
|
|
25753
|
+
for (let i2 = 0;i2 < pendingState.outgoingSymbols.length; i2++) {
|
|
25754
|
+
group.outgoing.push({
|
|
25755
|
+
date: pendingState.date,
|
|
25756
|
+
orderNum: pendingState.orderNum,
|
|
25757
|
+
type: "Internal exchange of securities",
|
|
25758
|
+
symbol: pendingState.outgoingSymbols[i2],
|
|
25759
|
+
name: "",
|
|
25760
|
+
isin: pendingState.outgoingIsins[i2] || "",
|
|
25761
|
+
quantity: -(pendingState.outgoingQuantities[i2] || 0)
|
|
25762
|
+
});
|
|
25763
|
+
}
|
|
25702
25764
|
const totalIncomingQty2 = group.incoming.reduce((sum, a) => sum + Math.abs(a.quantity), 0);
|
|
25703
25765
|
const incomingTotalCosts2 = [];
|
|
25704
25766
|
for (const inc of group.incoming) {
|
|
@@ -25722,11 +25784,11 @@ function processMultiWayMerger(group, inventory, lotInventoryPath, projectDir, l
|
|
|
25722
25784
|
logger?.info(`Cross-currency merger incoming: ${absQty} ${inc.symbol} @ ${costBasisPerUnit.toFixed(2)} ${pendingState.currency}`);
|
|
25723
25785
|
}
|
|
25724
25786
|
const costInfo2 = {
|
|
25725
|
-
outgoingTotalCosts: [],
|
|
25787
|
+
outgoingTotalCosts: pendingState.outgoingTotalCosts || [],
|
|
25726
25788
|
incomingTotalCosts: incomingTotalCosts2,
|
|
25727
25789
|
currency: pendingState.currency
|
|
25728
25790
|
};
|
|
25729
|
-
const entry2 = generateMultiWayMergerEntry(group,
|
|
25791
|
+
const entry2 = generateMultiWayMergerEntry(group, undefined, undefined, costInfo2, logger);
|
|
25730
25792
|
entries.push(entry2);
|
|
25731
25793
|
removePendingMerger(projectDir, lotInventoryPath, group.key, logger);
|
|
25732
25794
|
} else {
|
|
@@ -25764,16 +25826,10 @@ function processMultiWayMerger(group, inventory, lotInventoryPath, projectDir, l
|
|
|
25764
25826
|
outgoingSymbols,
|
|
25765
25827
|
outgoingIsins: group.outgoing.map((a) => a.isin),
|
|
25766
25828
|
outgoingQuantities: group.outgoing.map((a) => Math.abs(a.quantity)),
|
|
25829
|
+
outgoingTotalCosts,
|
|
25767
25830
|
totalCostBasis,
|
|
25768
25831
|
currency: costCurrency
|
|
25769
25832
|
}, logger);
|
|
25770
|
-
const costInfo2 = {
|
|
25771
|
-
outgoingTotalCosts,
|
|
25772
|
-
incomingTotalCosts: [],
|
|
25773
|
-
currency: costCurrency
|
|
25774
|
-
};
|
|
25775
|
-
const entry2 = generateMultiWayMergerEntry(group, undefined, undefined, costInfo2, logger);
|
|
25776
|
-
entries.push(entry2);
|
|
25777
25833
|
logger?.info(`Cross-currency merger outgoing: ${outgoingSymbols.join(", ")} -> pending (cost basis: ${totalCostBasis.toFixed(2)})`);
|
|
25778
25834
|
return entries;
|
|
25779
25835
|
}
|
|
@@ -25871,7 +25927,7 @@ function resolveRemainingPendingMergers(projectDir, lotInventoryPath, logger) {
|
|
|
25871
25927
|
continue;
|
|
25872
25928
|
}
|
|
25873
25929
|
const year = parseInt(dateMatch[1], 10);
|
|
25874
|
-
const entry =
|
|
25930
|
+
const entry = generateDirectWorthlessEntry(state.date, state.orderNum, state.outgoingSymbols, state.outgoingIsins, state.outgoingQuantities || [], state.outgoingTotalCosts || [], state.totalCostBasis, state.currency, logger);
|
|
25875
25931
|
const journalFile = path13.join(projectDir, "ledger", "investments", `${year}-${state.currency.toLowerCase()}.journal`);
|
|
25876
25932
|
if (!entriesByJournal.has(journalFile)) {
|
|
25877
25933
|
entriesByJournal.set(journalFile, []);
|
|
@@ -26178,7 +26234,7 @@ async function preprocessSwissquote(csvPath, projectDir, currency, year, lotInve
|
|
|
26178
26234
|
investmentAccounts.add("income:capital-gains:realized");
|
|
26179
26235
|
investmentAccounts.add("income:capital-gains:rights-distribution");
|
|
26180
26236
|
investmentAccounts.add("expenses:losses:capital");
|
|
26181
|
-
investmentAccounts.add(
|
|
26237
|
+
investmentAccounts.add(`equity:conversion:${currency.toLowerCase()}`);
|
|
26182
26238
|
investmentAccounts.add("equity:rounding");
|
|
26183
26239
|
ensureInvestmentAccountDeclarations(accountJournalPath, investmentAccounts, logger);
|
|
26184
26240
|
}
|
package/package.json
CHANGED