@fuzzle/opencode-accountant 0.10.8 → 0.11.0
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 +69 -19
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -2739,6 +2739,19 @@ var init_agentLoader = __esm(() => {
|
|
|
2739
2739
|
]);
|
|
2740
2740
|
});
|
|
2741
2741
|
|
|
2742
|
+
// src/utils/journalMatchers.ts
|
|
2743
|
+
function extractAccount(line, pattern) {
|
|
2744
|
+
const match = line.match(pattern);
|
|
2745
|
+
return match ? match[1].trim() : null;
|
|
2746
|
+
}
|
|
2747
|
+
var JOURNAL_ACCOUNT_DECL, RULES_ACCOUNT_DIRECTIVE, RULES_ACCOUNT2_DIRECTIVE, TX_HEADER_PATTERN;
|
|
2748
|
+
var init_journalMatchers = __esm(() => {
|
|
2749
|
+
JOURNAL_ACCOUNT_DECL = /^account\s+(.+)$/;
|
|
2750
|
+
RULES_ACCOUNT_DIRECTIVE = /^account\d+\s+(.+)$/;
|
|
2751
|
+
RULES_ACCOUNT2_DIRECTIVE = /^\s*account2\s+(.+)$/;
|
|
2752
|
+
TX_HEADER_PATTERN = /^(\d{4})-(\d{2}-\d{2})(\s+(.+))?$/;
|
|
2753
|
+
});
|
|
2754
|
+
|
|
2742
2755
|
// node_modules/papaparse/papaparse.js
|
|
2743
2756
|
var require_papaparse = __commonJS((exports, module) => {
|
|
2744
2757
|
(function(root, factory) {
|
|
@@ -4258,19 +4271,6 @@ var require_brace_expansion = __commonJS((exports, module) => {
|
|
|
4258
4271
|
}
|
|
4259
4272
|
});
|
|
4260
4273
|
|
|
4261
|
-
// src/utils/journalMatchers.ts
|
|
4262
|
-
function extractAccount(line, pattern) {
|
|
4263
|
-
const match2 = line.match(pattern);
|
|
4264
|
-
return match2 ? match2[1].trim() : null;
|
|
4265
|
-
}
|
|
4266
|
-
var JOURNAL_ACCOUNT_DECL, RULES_ACCOUNT_DIRECTIVE, RULES_ACCOUNT2_DIRECTIVE, TX_HEADER_PATTERN;
|
|
4267
|
-
var init_journalMatchers = __esm(() => {
|
|
4268
|
-
JOURNAL_ACCOUNT_DECL = /^account\s+(.+)$/;
|
|
4269
|
-
RULES_ACCOUNT_DIRECTIVE = /^account\d+\s+(.+)$/;
|
|
4270
|
-
RULES_ACCOUNT2_DIRECTIVE = /^\s*account2\s+(.+)$/;
|
|
4271
|
-
TX_HEADER_PATTERN = /^(\d{4})-(\d{2}-\d{2})(\s+(.+))?$/;
|
|
4272
|
-
});
|
|
4273
|
-
|
|
4274
4274
|
// src/utils/accountSuggester.ts
|
|
4275
4275
|
var exports_accountSuggester = {};
|
|
4276
4276
|
__export(exports_accountSuggester, {
|
|
@@ -17012,6 +17012,7 @@ function ensureDirectory(dirPath) {
|
|
|
17012
17012
|
}
|
|
17013
17013
|
|
|
17014
17014
|
// src/utils/journalUtils.ts
|
|
17015
|
+
init_journalMatchers();
|
|
17015
17016
|
function extractDateFromPriceLine(line) {
|
|
17016
17017
|
return line.split(" ")[1];
|
|
17017
17018
|
}
|
|
@@ -17097,6 +17098,37 @@ function ensureCommodityDeclarations(commodityJournalPath, symbols, logger) {
|
|
|
17097
17098
|
logger?.info(`Commodity declarations: added ${missing.length} (${missing.join(", ")})`);
|
|
17098
17099
|
return { added: missing.sort(), updated: true };
|
|
17099
17100
|
}
|
|
17101
|
+
function ensureInvestmentAccountDeclarations(accountJournalPath, accounts, logger) {
|
|
17102
|
+
const existing = new Set;
|
|
17103
|
+
if (fs4.existsSync(accountJournalPath)) {
|
|
17104
|
+
const content2 = fs4.readFileSync(accountJournalPath, "utf-8");
|
|
17105
|
+
for (const line of content2.split(`
|
|
17106
|
+
`)) {
|
|
17107
|
+
const match = line.trim().match(JOURNAL_ACCOUNT_DECL);
|
|
17108
|
+
if (match) {
|
|
17109
|
+
existing.add(match[1]);
|
|
17110
|
+
}
|
|
17111
|
+
}
|
|
17112
|
+
}
|
|
17113
|
+
const missing = [];
|
|
17114
|
+
for (const account of accounts) {
|
|
17115
|
+
if (!existing.has(account)) {
|
|
17116
|
+
missing.push(account);
|
|
17117
|
+
existing.add(account);
|
|
17118
|
+
}
|
|
17119
|
+
}
|
|
17120
|
+
if (missing.length === 0) {
|
|
17121
|
+
return { added: [], updated: false };
|
|
17122
|
+
}
|
|
17123
|
+
const sorted = Array.from(existing).sort((a, b) => a.localeCompare(b));
|
|
17124
|
+
const content = sorted.map((a) => `account ${a}`).join(`
|
|
17125
|
+
`) + `
|
|
17126
|
+
`;
|
|
17127
|
+
ensureDirectory(path3.dirname(accountJournalPath));
|
|
17128
|
+
fs4.writeFileSync(accountJournalPath, content);
|
|
17129
|
+
logger?.info(`Account declarations: added ${missing.length} (${missing.join(", ")})`);
|
|
17130
|
+
return { added: missing.sort(), updated: true };
|
|
17131
|
+
}
|
|
17100
17132
|
|
|
17101
17133
|
// src/utils/dateUtils.ts
|
|
17102
17134
|
function formatDateISO(date5) {
|
|
@@ -25033,7 +25065,7 @@ function removeLots(inventory, symbol2, logger) {
|
|
|
25033
25065
|
return [];
|
|
25034
25066
|
}
|
|
25035
25067
|
const removedLots = [...lots];
|
|
25036
|
-
|
|
25068
|
+
inventory[symbol2] = [];
|
|
25037
25069
|
const totalQuantity = removedLots.reduce((sum, lot) => sum + lot.quantity, 0);
|
|
25038
25070
|
const totalCost = removedLots.reduce((sum, lot) => sum + lot.quantity * lot.costBasis, 0);
|
|
25039
25071
|
logger?.info(`Removed ${removedLots.length} lots for ${symbol2}: ${totalQuantity} shares, cost basis ${totalCost}`);
|
|
@@ -25202,17 +25234,18 @@ function generateWorthlessEntry(action, removedLots, logger) {
|
|
|
25202
25234
|
`;
|
|
25203
25235
|
return entry;
|
|
25204
25236
|
}
|
|
25205
|
-
function generateMultiWayMergerEntry(group, crossCurrencyOutgoingSymbols, logger) {
|
|
25237
|
+
function generateMultiWayMergerEntry(group, crossCurrencyOutgoingSymbols, crossCurrencyOutgoingIsins, logger) {
|
|
25206
25238
|
const date5 = formatDate(group.date);
|
|
25207
25239
|
const outSymbols = crossCurrencyOutgoingSymbols ?? group.outgoing.map((a) => a.symbol);
|
|
25208
25240
|
const inSymbols = group.incoming.map((a) => a.symbol);
|
|
25209
|
-
const
|
|
25241
|
+
const descriptionParts = outSymbols.join(" + ");
|
|
25242
|
+
const description = escapeDescription(inSymbols.length > 0 ? `Merger: ${descriptionParts} -> ${inSymbols.join(" + ")}` : `Merger: ${descriptionParts}`);
|
|
25210
25243
|
logger?.debug(`Generating multi-way merger entry: ${outSymbols.join(", ")} -> ${inSymbols.join(", ")}`);
|
|
25211
25244
|
let entry = `${date5} ${description}
|
|
25212
25245
|
`;
|
|
25213
25246
|
entry += ` ; swissquote:order:${group.orderNum}
|
|
25214
25247
|
`;
|
|
25215
|
-
const oldIsins = group.outgoing.map((a) => a.isin).filter(Boolean);
|
|
25248
|
+
const oldIsins = (crossCurrencyOutgoingIsins ?? group.outgoing.map((a) => a.isin)).filter(Boolean);
|
|
25216
25249
|
const newIsins = group.incoming.map((a) => a.isin).filter(Boolean);
|
|
25217
25250
|
if (oldIsins.length > 0 || newIsins.length > 0) {
|
|
25218
25251
|
entry += ` ; Old ISIN: ${oldIsins.join(", ") || "n/a"}, New ISINs: ${newIsins.join(", ") || "n/a"}
|
|
@@ -25514,7 +25547,7 @@ function processMultiWayMerger(group, inventory, lotInventoryPath, projectDir, l
|
|
|
25514
25547
|
inventory[inc.symbol].push(lot);
|
|
25515
25548
|
logger?.info(`Cross-currency merger incoming: ${absQty} ${inc.symbol} @ ${costBasisPerUnit.toFixed(2)} ${pendingState.currency}`);
|
|
25516
25549
|
}
|
|
25517
|
-
const entry2 = generateMultiWayMergerEntry(group, pendingState.outgoingSymbols, logger);
|
|
25550
|
+
const entry2 = generateMultiWayMergerEntry(group, pendingState.outgoingSymbols, pendingState.outgoingIsins, logger);
|
|
25518
25551
|
entries.push(entry2);
|
|
25519
25552
|
removePendingMerger(projectDir, lotInventoryPath, group.key, logger);
|
|
25520
25553
|
} else {
|
|
@@ -25545,9 +25578,12 @@ function processMultiWayMerger(group, inventory, lotInventoryPath, projectDir, l
|
|
|
25545
25578
|
date: group.date,
|
|
25546
25579
|
orderNum: group.orderNum,
|
|
25547
25580
|
outgoingSymbols,
|
|
25581
|
+
outgoingIsins: group.outgoing.map((a) => a.isin),
|
|
25548
25582
|
totalCostBasis,
|
|
25549
25583
|
currency: outgoingCurrency || "CAD"
|
|
25550
25584
|
}, logger);
|
|
25585
|
+
const entry2 = generateMultiWayMergerEntry(group, undefined, undefined, logger);
|
|
25586
|
+
entries.push(entry2);
|
|
25551
25587
|
logger?.info(`Cross-currency merger outgoing: ${outgoingSymbols.join(", ")} -> pending (cost basis: ${totalCostBasis.toFixed(2)})`);
|
|
25552
25588
|
return entries;
|
|
25553
25589
|
}
|
|
@@ -25576,7 +25612,7 @@ function processMultiWayMerger(group, inventory, lotInventoryPath, projectDir, l
|
|
|
25576
25612
|
inventory[inc.symbol].push(lot);
|
|
25577
25613
|
logger?.debug(`Merger incoming: added ${absQty} ${inc.symbol} @ ${costBasisPerUnit.toFixed(2)}`);
|
|
25578
25614
|
}
|
|
25579
|
-
const entry = generateMultiWayMergerEntry(group, undefined, logger);
|
|
25615
|
+
const entry = generateMultiWayMergerEntry(group, undefined, undefined, logger);
|
|
25580
25616
|
entries.push(entry);
|
|
25581
25617
|
return entries;
|
|
25582
25618
|
}
|
|
@@ -25830,6 +25866,20 @@ async function preprocessSwissquote(csvPath, projectDir, currency, year, lotInve
|
|
|
25830
25866
|
if (stockSymbols.size > 0) {
|
|
25831
25867
|
const commodityJournalPath = path13.join(projectDir, "ledger", "investments", "commodities.journal");
|
|
25832
25868
|
ensureCommodityDeclarations(commodityJournalPath, stockSymbols, logger);
|
|
25869
|
+
const accountJournalPath = path13.join(projectDir, "ledger", "investments", "accounts.journal");
|
|
25870
|
+
const investmentAccounts = new Set;
|
|
25871
|
+
for (const symbol2 of stockSymbols) {
|
|
25872
|
+
investmentAccounts.add(`assets:investments:stocks:${symbol2}`);
|
|
25873
|
+
investmentAccounts.add(`income:dividends:${symbol2}`);
|
|
25874
|
+
}
|
|
25875
|
+
investmentAccounts.add(`assets:broker:swissquote:${currency.toLowerCase()}`);
|
|
25876
|
+
investmentAccounts.add("expenses:fees:trading:swissquote");
|
|
25877
|
+
investmentAccounts.add("expenses:taxes:withholding");
|
|
25878
|
+
investmentAccounts.add("income:capital-gains:realized");
|
|
25879
|
+
investmentAccounts.add("income:capital-gains:rights-distribution");
|
|
25880
|
+
investmentAccounts.add("expenses:losses:capital");
|
|
25881
|
+
investmentAccounts.add("equity:conversion");
|
|
25882
|
+
ensureInvestmentAccountDeclarations(accountJournalPath, investmentAccounts, logger);
|
|
25833
25883
|
}
|
|
25834
25884
|
logger?.logResult({
|
|
25835
25885
|
totalRows: stats.totalRows,
|