@fuzzle/opencode-accountant 0.12.2-next.1 → 0.13.0-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 +49 -4
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -24745,8 +24745,18 @@ function generateBtcPurchaseJournal(fiatCsvPaths, btcCsvPath, yearJournalPath, l
|
|
|
24745
24745
|
}
|
|
24746
24746
|
const newEntries = [];
|
|
24747
24747
|
let skippedDuplicates = 0;
|
|
24748
|
+
const accountsUsed = new Set;
|
|
24748
24749
|
const sortedMatches = [...matches].sort((a, b) => a.fiatRow.date.getTime() - b.fiatRow.date.getTime());
|
|
24749
24750
|
for (const match2 of sortedMatches) {
|
|
24751
|
+
const fiat = match2.fiatRow.currency.toLowerCase();
|
|
24752
|
+
const pair = `${fiat}-btc`;
|
|
24753
|
+
accountsUsed.add(`assets:bank:revolut:${fiat}`);
|
|
24754
|
+
accountsUsed.add(`equity:conversion:${pair}:${fiat}`);
|
|
24755
|
+
accountsUsed.add(`equity:conversion:${pair}:btc`);
|
|
24756
|
+
accountsUsed.add("assets:bank:revolut:btc");
|
|
24757
|
+
if (match2.btcRow.fees.amount > 0) {
|
|
24758
|
+
accountsUsed.add("expenses:fees:btc");
|
|
24759
|
+
}
|
|
24750
24760
|
if (isDuplicate(match2, journalContent)) {
|
|
24751
24761
|
skippedDuplicates++;
|
|
24752
24762
|
logger?.debug(`Skipping duplicate: ${match2.fiatRow.dateStr} ${formatAmount(match2.fiatRow.amount)} ${match2.fiatRow.currency}`);
|
|
@@ -24770,7 +24780,8 @@ function generateBtcPurchaseJournal(fiatCsvPaths, btcCsvPath, yearJournalPath, l
|
|
|
24770
24780
|
entriesAdded: newEntries.length,
|
|
24771
24781
|
skippedDuplicates,
|
|
24772
24782
|
unmatchedFiat,
|
|
24773
|
-
unmatchedBtc
|
|
24783
|
+
unmatchedBtc,
|
|
24784
|
+
accountsUsed
|
|
24774
24785
|
};
|
|
24775
24786
|
}
|
|
24776
24787
|
|
|
@@ -26054,7 +26065,13 @@ function generateCurrencyExchangeJournal(fiatCsvPaths, yearJournalPath, logger)
|
|
|
26054
26065
|
}
|
|
26055
26066
|
if (rowsByCsv.size < 2) {
|
|
26056
26067
|
logger?.info("Need at least 2 CSVs with EXCHANGE rows to match pairs, skipping");
|
|
26057
|
-
return {
|
|
26068
|
+
return {
|
|
26069
|
+
matchCount: 0,
|
|
26070
|
+
entriesAdded: 0,
|
|
26071
|
+
skippedDuplicates: 0,
|
|
26072
|
+
matchedRowIndices: new Map,
|
|
26073
|
+
accountsUsed: new Set
|
|
26074
|
+
};
|
|
26058
26075
|
}
|
|
26059
26076
|
logger?.info("Matching exchange pairs across CSVs...");
|
|
26060
26077
|
const matches = matchExchangePairs(rowsByCsv);
|
|
@@ -26065,8 +26082,16 @@ function generateCurrencyExchangeJournal(fiatCsvPaths, yearJournalPath, logger)
|
|
|
26065
26082
|
}
|
|
26066
26083
|
const newEntries = [];
|
|
26067
26084
|
let skippedDuplicates = 0;
|
|
26085
|
+
const accountsUsed = new Set;
|
|
26068
26086
|
const sortedMatches = [...matches].sort((a, b) => a.source.date.getTime() - b.source.date.getTime());
|
|
26069
26087
|
for (const match2 of sortedMatches) {
|
|
26088
|
+
const source = match2.source.currency.toLowerCase();
|
|
26089
|
+
const target = match2.target.currency.toLowerCase();
|
|
26090
|
+
const pair = `${source}-${target}`;
|
|
26091
|
+
accountsUsed.add(`assets:bank:revolut:${source}`);
|
|
26092
|
+
accountsUsed.add(`equity:conversion:${pair}:${source}`);
|
|
26093
|
+
accountsUsed.add(`equity:conversion:${pair}:${target}`);
|
|
26094
|
+
accountsUsed.add(`assets:bank:revolut:${target}`);
|
|
26070
26095
|
if (isDuplicate2(match2, journalContent)) {
|
|
26071
26096
|
skippedDuplicates++;
|
|
26072
26097
|
logger?.debug(`Skipping duplicate: ${match2.source.dateStr} ${formatAmount3(match2.source.amount)} ${match2.source.currency} \u2192 ${formatAmount3(match2.target.amount)} ${match2.target.currency}`);
|
|
@@ -26098,7 +26123,8 @@ function generateCurrencyExchangeJournal(fiatCsvPaths, yearJournalPath, logger)
|
|
|
26098
26123
|
matchCount: matches.length,
|
|
26099
26124
|
entriesAdded: newEntries.length,
|
|
26100
26125
|
skippedDuplicates,
|
|
26101
|
-
matchedRowIndices
|
|
26126
|
+
matchedRowIndices,
|
|
26127
|
+
accountsUsed
|
|
26102
26128
|
};
|
|
26103
26129
|
}
|
|
26104
26130
|
|
|
@@ -26270,6 +26296,9 @@ async function executeBtcPurchaseStep(context, contextIds, logger) {
|
|
|
26270
26296
|
const year = yearMatch ? parseInt(yearMatch[1], 10) : new Date().getFullYear();
|
|
26271
26297
|
const yearJournalPath = ensureYearJournalExists(context.directory, year);
|
|
26272
26298
|
const result = generateBtcPurchaseJournal(fiatCsvPaths, btcCsvPath, yearJournalPath, logger);
|
|
26299
|
+
for (const account of result.accountsUsed) {
|
|
26300
|
+
context.generatedAccounts.add(account);
|
|
26301
|
+
}
|
|
26273
26302
|
const message = result.entriesAdded > 0 ? `Generated ${result.entriesAdded} BTC purchase entries (${result.matchCount} matched, ${result.skippedDuplicates} skipped)` : `No new BTC purchase entries (${result.matchCount} matched, ${result.skippedDuplicates} duplicates)`;
|
|
26274
26303
|
logger?.logStep("BTC Purchases", "success", message);
|
|
26275
26304
|
logger?.endSection();
|
|
@@ -26304,6 +26333,9 @@ async function executeCurrencyExchangeStep(context, contextIds, logger) {
|
|
|
26304
26333
|
const yearJournalPath = ensureYearJournalExists(context.directory, year);
|
|
26305
26334
|
const fiatCsvPaths = fiatContexts.map((c) => c.csvPath);
|
|
26306
26335
|
const result = generateCurrencyExchangeJournal(fiatCsvPaths, yearJournalPath, logger);
|
|
26336
|
+
for (const account of result.accountsUsed) {
|
|
26337
|
+
context.generatedAccounts.add(account);
|
|
26338
|
+
}
|
|
26307
26339
|
if (result.matchedRowIndices.size > 0) {
|
|
26308
26340
|
for (const { contextId, csvPath } of fiatContexts) {
|
|
26309
26341
|
const indices = result.matchedRowIndices.get(csvPath);
|
|
@@ -26706,7 +26738,8 @@ async function importPipeline(directory, agent, options, configLoader = loadImpo
|
|
|
26706
26738
|
options,
|
|
26707
26739
|
configLoader,
|
|
26708
26740
|
hledgerExecutor,
|
|
26709
|
-
result
|
|
26741
|
+
result,
|
|
26742
|
+
generatedAccounts: new Set
|
|
26710
26743
|
};
|
|
26711
26744
|
try {
|
|
26712
26745
|
const contextIds = await executeClassifyStep(context, logger);
|
|
@@ -26719,6 +26752,18 @@ async function importPipeline(directory, agent, options, configLoader = loadImpo
|
|
|
26719
26752
|
await executeBtcPurchaseStep(context, contextIds, logger);
|
|
26720
26753
|
await executeCurrencyExchangeStep(context, contextIds, logger);
|
|
26721
26754
|
await executeSwissquotePreprocessStep(context, contextIds, logger);
|
|
26755
|
+
if (context.generatedAccounts.size > 0) {
|
|
26756
|
+
const firstCtx = contextIds.map((id) => loadContext(context.directory, id)).find((c) => c.provider === "revolut");
|
|
26757
|
+
if (firstCtx) {
|
|
26758
|
+
const yearMatch = firstCtx.filePath.match(/(\d{4})-\d{2}-\d{2}/);
|
|
26759
|
+
const year = yearMatch ? parseInt(yearMatch[1], 10) : new Date().getFullYear();
|
|
26760
|
+
const yearJournalPath = ensureYearJournalExists(context.directory, year);
|
|
26761
|
+
const declResult = ensureAccountDeclarations(yearJournalPath, context.generatedAccounts);
|
|
26762
|
+
if (declResult.added.length > 0) {
|
|
26763
|
+
logger.info(`Declared ${declResult.added.length} account(s) from generated entries: ${declResult.added.join(", ")}`);
|
|
26764
|
+
}
|
|
26765
|
+
}
|
|
26766
|
+
}
|
|
26722
26767
|
const importConfig = loadImportConfig(context.directory);
|
|
26723
26768
|
const orderedContextIds = [...contextIds].sort((a, b) => {
|
|
26724
26769
|
const ctxA = loadContext(context.directory, a);
|
package/package.json
CHANGED