@fuzzle/opencode-accountant 0.16.0-next.1 → 0.16.1-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 +70 -9
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -23515,7 +23515,8 @@ function balancesMatch(balance1, balance2) {
|
|
|
23515
23515
|
return false;
|
|
23516
23516
|
}
|
|
23517
23517
|
validateCurrencies(parsed1, parsed2);
|
|
23518
|
-
|
|
23518
|
+
const round2 = (n) => Math.round(n * 100) / 100;
|
|
23519
|
+
return round2(parsed1.amount) === round2(parsed2.amount);
|
|
23519
23520
|
}
|
|
23520
23521
|
|
|
23521
23522
|
// src/utils/csvParser.ts
|
|
@@ -26968,6 +26969,34 @@ function generateIbkrAdjustmentEntry(adjustment, logger) {
|
|
|
26968
26969
|
`;
|
|
26969
26970
|
return entry;
|
|
26970
26971
|
}
|
|
26972
|
+
function generateIbkrForexEntry(entry, logger) {
|
|
26973
|
+
const description = escapeDescription(entry.description);
|
|
26974
|
+
logger?.debug(`Generating IBKR Forex entry: ${entry.amount} ${entry.currency}`);
|
|
26975
|
+
const postings = [
|
|
26976
|
+
{
|
|
26977
|
+
account: `assets:broker:ibkr:${entry.currency.toLowerCase()}`,
|
|
26978
|
+
amount: formatAmount(entry.amount, entry.currency)
|
|
26979
|
+
}
|
|
26980
|
+
];
|
|
26981
|
+
if (entry.amount < 0) {
|
|
26982
|
+
postings.push({
|
|
26983
|
+
account: "expenses:fees:forex:ibkr",
|
|
26984
|
+
amount: formatAmount(Math.abs(entry.amount), entry.currency)
|
|
26985
|
+
});
|
|
26986
|
+
} else {
|
|
26987
|
+
postings.push({
|
|
26988
|
+
account: "income:fx-gains:ibkr",
|
|
26989
|
+
amount: formatAmount(-entry.amount, entry.currency)
|
|
26990
|
+
});
|
|
26991
|
+
}
|
|
26992
|
+
let result = `${entry.date} ${description}
|
|
26993
|
+
`;
|
|
26994
|
+
result += ` ; ibkr:account:${entry.account}
|
|
26995
|
+
`;
|
|
26996
|
+
result += formatPostings(postings) + `
|
|
26997
|
+
`;
|
|
26998
|
+
return result;
|
|
26999
|
+
}
|
|
26971
27000
|
|
|
26972
27001
|
// src/utils/ibkrCsvPreprocessor.ts
|
|
26973
27002
|
var TRADE_TYPES2 = new Set(["Buy", "Sell"]);
|
|
@@ -27064,7 +27093,7 @@ async function preprocessIbkr(csvPath, directory, currency, year, lotInventoryPa
|
|
|
27064
27093
|
trades: 0,
|
|
27065
27094
|
dividends: 0,
|
|
27066
27095
|
adjustments: 0,
|
|
27067
|
-
|
|
27096
|
+
forex: 0
|
|
27068
27097
|
},
|
|
27069
27098
|
alreadyPreprocessed: true
|
|
27070
27099
|
};
|
|
@@ -27076,7 +27105,7 @@ async function preprocessIbkr(csvPath, directory, currency, year, lotInventoryPa
|
|
|
27076
27105
|
const trades = [];
|
|
27077
27106
|
const dividendTxns = [];
|
|
27078
27107
|
const adjustments = [];
|
|
27079
|
-
|
|
27108
|
+
const forexTxns = [];
|
|
27080
27109
|
for (const txn of transactions) {
|
|
27081
27110
|
if (TRADE_TYPES2.has(txn.transactionType)) {
|
|
27082
27111
|
trades.push(txn);
|
|
@@ -27087,7 +27116,7 @@ async function preprocessIbkr(csvPath, directory, currency, year, lotInventoryPa
|
|
|
27087
27116
|
} else if (txn.transactionType === DEPOSIT_TYPE) {
|
|
27088
27117
|
deposits.push(txn);
|
|
27089
27118
|
} else if (txn.transactionType === FOREX_TYPE) {
|
|
27090
|
-
|
|
27119
|
+
forexTxns.push(txn);
|
|
27091
27120
|
} else {
|
|
27092
27121
|
logger?.warn(`Unknown IBKR transaction type: ${txn.transactionType}`);
|
|
27093
27122
|
}
|
|
@@ -27173,6 +27202,38 @@ async function preprocessIbkr(csvPath, directory, currency, year, lotInventoryPa
|
|
|
27173
27202
|
usedAccounts.add("income:fx-gains:ibkr");
|
|
27174
27203
|
}
|
|
27175
27204
|
}
|
|
27205
|
+
if (forexTxns.length > 0) {
|
|
27206
|
+
const forexByDate = new Map;
|
|
27207
|
+
for (const txn of forexTxns) {
|
|
27208
|
+
const existing = forexByDate.get(txn.date);
|
|
27209
|
+
if (existing) {
|
|
27210
|
+
existing.total += txn.netAmount;
|
|
27211
|
+
} else {
|
|
27212
|
+
forexByDate.set(txn.date, { account: txn.account, total: txn.netAmount });
|
|
27213
|
+
}
|
|
27214
|
+
}
|
|
27215
|
+
const sortedDates = [...forexByDate.keys()].sort();
|
|
27216
|
+
for (const date5 of sortedDates) {
|
|
27217
|
+
const { account, total } = forexByDate.get(date5);
|
|
27218
|
+
const amount = Math.round(total * 100) / 100;
|
|
27219
|
+
if (amount === 0)
|
|
27220
|
+
continue;
|
|
27221
|
+
const forexEntry = {
|
|
27222
|
+
date: date5,
|
|
27223
|
+
account,
|
|
27224
|
+
description: "Forex conversion cost",
|
|
27225
|
+
amount,
|
|
27226
|
+
currency: currency.toUpperCase()
|
|
27227
|
+
};
|
|
27228
|
+
journalEntries.push(generateIbkrForexEntry(forexEntry, logger));
|
|
27229
|
+
usedAccounts.add(`assets:broker:ibkr:${currency}`);
|
|
27230
|
+
if (amount < 0) {
|
|
27231
|
+
usedAccounts.add("expenses:fees:forex:ibkr");
|
|
27232
|
+
} else {
|
|
27233
|
+
usedAccounts.add("income:fx-gains:ibkr");
|
|
27234
|
+
}
|
|
27235
|
+
}
|
|
27236
|
+
}
|
|
27176
27237
|
saveLotInventory(directory, lotInventoryPath, inventory, logger);
|
|
27177
27238
|
let journalFilePath = null;
|
|
27178
27239
|
if (journalEntries.length > 0) {
|
|
@@ -27230,7 +27291,7 @@ async function preprocessIbkr(csvPath, directory, currency, year, lotInventoryPa
|
|
|
27230
27291
|
trades: trades.length,
|
|
27231
27292
|
dividends: dividendCount,
|
|
27232
27293
|
adjustments: adjustments.length,
|
|
27233
|
-
|
|
27294
|
+
forex: forexTxns.length
|
|
27234
27295
|
},
|
|
27235
27296
|
alreadyPreprocessed: false
|
|
27236
27297
|
};
|
|
@@ -27609,7 +27670,7 @@ async function executeIbkrPreprocessStep(context, contextIds, logger) {
|
|
|
27609
27670
|
trades: 0,
|
|
27610
27671
|
dividends: 0,
|
|
27611
27672
|
adjustments: 0,
|
|
27612
|
-
|
|
27673
|
+
forex: 0
|
|
27613
27674
|
};
|
|
27614
27675
|
let lastJournalFile = null;
|
|
27615
27676
|
ibkrContexts.sort((a, b) => {
|
|
@@ -27625,7 +27686,7 @@ async function executeIbkrPreprocessStep(context, contextIds, logger) {
|
|
|
27625
27686
|
totalStats.trades += result.stats.trades;
|
|
27626
27687
|
totalStats.dividends += result.stats.dividends;
|
|
27627
27688
|
totalStats.adjustments += result.stats.adjustments;
|
|
27628
|
-
totalStats.
|
|
27689
|
+
totalStats.forex += result.stats.forex;
|
|
27629
27690
|
if (result.journalFile) {
|
|
27630
27691
|
lastJournalFile = result.journalFile;
|
|
27631
27692
|
}
|
|
@@ -27635,9 +27696,9 @@ async function executeIbkrPreprocessStep(context, contextIds, logger) {
|
|
|
27635
27696
|
});
|
|
27636
27697
|
logger?.info(`Updated context ${ibkrCtx.contextId} to use filtered CSV: ${path18.basename(result.simpleTransactionsCsv)}`);
|
|
27637
27698
|
}
|
|
27638
|
-
logger?.logStep("IBKR Preprocess", "success", `Processed: ${result.stats.trades} trades, ${result.stats.dividends} dividends, ${result.stats.adjustments} adjustments, ${result.stats.
|
|
27699
|
+
logger?.logStep("IBKR Preprocess", "success", `Processed: ${result.stats.trades} trades, ${result.stats.dividends} dividends, ${result.stats.adjustments} adjustments, ${result.stats.forex} forex`);
|
|
27639
27700
|
}
|
|
27640
|
-
const message = `Preprocessed ${totalStats.totalRows} rows: ${totalStats.trades} trades, ${totalStats.dividends} dividends, ${totalStats.adjustments} adjustments, ${totalStats.deposits} deposits, ${totalStats.
|
|
27701
|
+
const message = `Preprocessed ${totalStats.totalRows} rows: ${totalStats.trades} trades, ${totalStats.dividends} dividends, ${totalStats.adjustments} adjustments, ${totalStats.deposits} deposits, ${totalStats.forex} forex`;
|
|
27641
27702
|
context.result.steps.ibkrPreprocess = buildStepResult(true, message, {
|
|
27642
27703
|
...totalStats,
|
|
27643
27704
|
journalFile: lastJournalFile
|
package/package.json
CHANGED