@fuzzle/opencode-accountant 0.12.0 → 0.12.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.
Files changed (2) hide show
  1. package/dist/index.js +22 -23
  2. package/package.json +1 -1
package/dist/index.js CHANGED
@@ -23936,17 +23936,7 @@ function determineClosingBalance(csvFile, config2, importContext, manualClosingB
23936
23936
  if (analysisBalance) {
23937
23937
  return { closingBalance: analysisBalance, metadata, fromCSVAnalysis: true };
23938
23938
  }
23939
- const currency = importContext.currency?.toUpperCase() || "CHF";
23940
- const exampleBalance = `${currency} <amount>`;
23941
- const retryCmd = buildRetryCommand(importContext.id, exampleBalance);
23942
- return {
23943
- error: buildErrorResult2({
23944
- csvFile: relativeCsvPath,
23945
- error: "No closing balance found in CSV metadata or data",
23946
- hint: `Provide closingBalance parameter manually. Example retry: ${retryCmd}`,
23947
- metadata
23948
- })
23949
- };
23939
+ return { notAvailable: true, metadata };
23950
23940
  }
23951
23941
  function buildRetryCommand(contextId, closingBalance, account) {
23952
23942
  const parts = ["reconcile-statement", `--contextId ${contextId}`];
@@ -24071,6 +24061,14 @@ async function reconcileStatement(directory, agent, options, configLoader = load
24071
24061
  }
24072
24062
  const { csvFile, relativePath: relativeCsvPath } = csvResult;
24073
24063
  const balanceResult = determineClosingBalance(csvFile, config2, importContext, options.closingBalance, relativeCsvPath, rulesDir);
24064
+ if ("notAvailable" in balanceResult) {
24065
+ return JSON.stringify({
24066
+ success: true,
24067
+ skipped: true,
24068
+ csvFile: relativeCsvPath,
24069
+ note: "No closing balance available \u2014 reconciliation skipped"
24070
+ });
24071
+ }
24074
24072
  if ("error" in balanceResult) {
24075
24073
  return balanceResult.error;
24076
24074
  }
@@ -25915,9 +25913,9 @@ function parseExchangeRows(csvPath) {
25915
25913
  if (fields.length < 9)
25916
25914
  continue;
25917
25915
  const [type2, , startedDate, , description, amountStr, , currency] = fields;
25918
- if (type2 !== "EXCHANGE")
25916
+ if (type2?.toUpperCase() !== "EXCHANGE")
25919
25917
  continue;
25920
- if (!description?.startsWith("Exchanged to"))
25918
+ if (!/^Exchanged to [A-Z]{3}$/.test(description ?? ""))
25921
25919
  continue;
25922
25920
  const rawAmount = parseFloat(amountStr);
25923
25921
  const date5 = parseRevolutDatetime(startedDate);
@@ -25939,8 +25937,8 @@ function matchExchangePairs(rowsByCsv) {
25939
25937
  for (const rows of rowsByCsv.values()) {
25940
25938
  allRows.push(...rows);
25941
25939
  }
25942
- const sources = allRows.filter((r) => r.amount > 0);
25943
- const targets = allRows.filter((r) => r.amount < 0);
25940
+ const sources = allRows.filter((r) => r.amount < 0);
25941
+ const targets = allRows.filter((r) => r.amount > 0);
25944
25942
  const matches = [];
25945
25943
  const matchedSourceIndices = new Set;
25946
25944
  const matchedTargetIndices = new Set;
@@ -25958,8 +25956,8 @@ function matchExchangePairs(rowsByCsv) {
25958
25956
  if (!source.description.includes(targetCurrency))
25959
25957
  continue;
25960
25958
  matches.push({
25961
- source,
25962
- target: { ...target, amount: Math.abs(target.amount) }
25959
+ source: { ...source, amount: Math.abs(source.amount) },
25960
+ target
25963
25961
  });
25964
25962
  matchedSourceIndices.add(si);
25965
25963
  matchedTargetIndices.add(ti);
@@ -25979,11 +25977,9 @@ function formatExchangeEntry(match2) {
25979
25977
  const targetCurrency = target.currency;
25980
25978
  const sourceAmount = formatAmount3(source.amount);
25981
25979
  const targetAmount = formatAmount3(target.amount);
25982
- const rate = target.amount / source.amount;
25983
- const rateStr = formatRate(rate);
25984
25980
  return [
25985
25981
  `${date5} ${description}`,
25986
- ` assets:bank:revolut:${sourceCurrency.toLowerCase()} -${sourceAmount} ${sourceCurrency} @ ${rateStr} ${targetCurrency}`,
25982
+ ` assets:bank:revolut:${sourceCurrency.toLowerCase()} -${sourceAmount} ${sourceCurrency}`,
25987
25983
  ` equity:currency:conversion ${sourceAmount} ${sourceCurrency}`,
25988
25984
  ` equity:currency:conversion -${targetAmount} ${targetCurrency}`,
25989
25985
  ` assets:bank:revolut:${targetCurrency.toLowerCase()} ${targetAmount} ${targetCurrency}`
@@ -25993,9 +25989,6 @@ function formatExchangeEntry(match2) {
25993
25989
  function formatAmount3(amount) {
25994
25990
  return amount.toFixed(2);
25995
25991
  }
25996
- function formatRate(rate) {
25997
- return rate.toFixed(4);
25998
- }
25999
25992
  function isDuplicate2(match2, journalContent) {
26000
25993
  const date5 = match2.source.dateStr;
26001
25994
  const description = match2.source.description;
@@ -26639,6 +26632,12 @@ async function executeReconcileStep(context, contextId, logger) {
26639
26632
  account: context.options.account
26640
26633
  }, context.configLoader, context.hledgerExecutor);
26641
26634
  const reconcileParsed = JSON.parse(reconcileResult);
26635
+ if (reconcileParsed.skipped) {
26636
+ logger?.logStep("Reconcile", "success", "Skipped \u2014 no closing balance available");
26637
+ context.result.steps.reconcile = buildStepResult(true, "Reconciliation skipped \u2014 no closing balance available", { success: true, skipped: true, note: reconcileParsed.note });
26638
+ logger?.endSection();
26639
+ return;
26640
+ }
26642
26641
  const message = reconcileParsed.success ? `Balance reconciled: ${reconcileParsed.actualBalance}` : `Balance mismatch: expected ${reconcileParsed.expectedBalance}, got ${reconcileParsed.actualBalance}`;
26643
26642
  logger?.logStep("Reconcile", reconcileParsed.success ? "success" : "error", message);
26644
26643
  if (reconcileParsed.success) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@fuzzle/opencode-accountant",
3
- "version": "0.12.0",
3
+ "version": "0.12.1-next.1",
4
4
  "description": "An OpenCode accounting agent, specialized in double-entry-bookkepping with hledger",
5
5
  "author": {
6
6
  "name": "ali bengali",