israeli-banks-actual-budget-importer 1.5.3 → 1.6.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/CHANGELOG.md +7 -0
- package/package.json +1 -1
- package/src/utils.ts +52 -11
package/CHANGELOG.md
CHANGED
|
@@ -1,3 +1,10 @@
|
|
|
1
|
+
# [1.6.0](https://github.com/tomerh2001/israeli-banks-actual-budget-importer/compare/v1.5.3...v1.6.0) (2025-12-02)
|
|
2
|
+
|
|
3
|
+
|
|
4
|
+
### Features
|
|
5
|
+
|
|
6
|
+
* enhance reconciliation process ([5ebf9a6](https://github.com/tomerh2001/israeli-banks-actual-budget-importer/commit/5ebf9a6453aa8db1e6f23fd81d114fbef5c85e5c))
|
|
7
|
+
|
|
1
8
|
## [1.5.3](https://github.com/tomerh2001/israeli-banks-actual-budget-importer/compare/v1.5.2...v1.5.3) (2025-11-24)
|
|
2
9
|
|
|
3
10
|
|
package/package.json
CHANGED
package/src/utils.ts
CHANGED
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
/* eslint-disable @typescript-eslint/no-unsafe-argument */
|
|
1
2
|
/* eslint-disable @typescript-eslint/no-unsafe-assignment */
|
|
2
3
|
/* eslint-disable @typescript-eslint/naming-convention */
|
|
3
4
|
/* eslint-disable @typescript-eslint/no-unsafe-call */
|
|
@@ -74,27 +75,68 @@ export async function scrapeAndImportTransactions({companyId, bank}: ScrapeTrans
|
|
|
74
75
|
|
|
75
76
|
const currentBalance = actual.utils.integerToAmount(await actual.getAccountBalance(bank.actualAccountId));
|
|
76
77
|
const balanceDiff = accountBalance - currentBalance;
|
|
78
|
+
|
|
79
|
+
// Use a stable imported_id per account so we can find and update/delete the same
|
|
80
|
+
// reconciliation transaction instead of creating a new one every run.
|
|
81
|
+
const reconciliationImportedId = `reconciliation-${bank.actualAccountId}`;
|
|
82
|
+
|
|
83
|
+
// Fetch all transactions for this account and look for an existing reconciliation.
|
|
84
|
+
// Use a wide date range so we always find it if it exists.
|
|
85
|
+
const allAccountTxns: TransactionEntity[] = await actual.getTransactions(
|
|
86
|
+
bank.actualAccountId,
|
|
87
|
+
'2000-01-01',
|
|
88
|
+
moment().add(1, 'year').format('YYYY-MM-DD'),
|
|
89
|
+
);
|
|
90
|
+
|
|
91
|
+
const existingReconciliation = allAccountTxns.find(txn => txn.imported_id === reconciliationImportedId);
|
|
92
|
+
|
|
93
|
+
// If balances are already in sync, remove any existing reconciliation and exit.
|
|
77
94
|
if (balanceDiff === 0) {
|
|
95
|
+
if (existingReconciliation) {
|
|
96
|
+
stdout.mute();
|
|
97
|
+
await actual.deleteTransaction(existingReconciliation.id);
|
|
98
|
+
stdout.unmute();
|
|
99
|
+
log('RECONCILIATION_REMOVED');
|
|
100
|
+
}
|
|
101
|
+
|
|
78
102
|
return;
|
|
79
103
|
}
|
|
80
104
|
|
|
81
|
-
log('RECONCILIATION', {
|
|
105
|
+
log('RECONCILIATION', {
|
|
106
|
+
from: currentBalance,
|
|
107
|
+
to: accountBalance,
|
|
108
|
+
diff: balanceDiff,
|
|
109
|
+
});
|
|
82
110
|
|
|
83
|
-
|
|
84
|
-
|
|
111
|
+
const reconciliationTxn = {
|
|
112
|
+
account: bank.actualAccountId,
|
|
85
113
|
date: moment().format('YYYY-MM-DD'),
|
|
86
114
|
amount: actual.utils.amountToInteger(balanceDiff),
|
|
87
|
-
payee:
|
|
115
|
+
payee: undefined,
|
|
88
116
|
imported_payee: 'Reconciliation',
|
|
89
117
|
notes: `Reconciliation from ${currentBalance.toLocaleString()} to ${accountBalance.toLocaleString()}`,
|
|
90
|
-
imported_id:
|
|
91
|
-
}
|
|
92
|
-
stdout.unmute();
|
|
118
|
+
imported_id: reconciliationImportedId,
|
|
119
|
+
};
|
|
93
120
|
|
|
94
|
-
|
|
95
|
-
|
|
121
|
+
stdout.mute();
|
|
122
|
+
if (existingReconciliation) {
|
|
123
|
+
// Update the single reconciliation transaction
|
|
124
|
+
await actual.updateTransaction(existingReconciliation.id, reconciliationTxn);
|
|
125
|
+
stdout.unmute();
|
|
126
|
+
log('RECONCILIATION_UPDATED', {transactionId: existingReconciliation.id});
|
|
96
127
|
} else {
|
|
97
|
-
|
|
128
|
+
// Create the reconciliation transaction for the first time
|
|
129
|
+
const reconciliationResult = await actual.importTransactions(
|
|
130
|
+
bank.actualAccountId,
|
|
131
|
+
[reconciliationTxn],
|
|
132
|
+
);
|
|
133
|
+
stdout.unmute();
|
|
134
|
+
|
|
135
|
+
if (!reconciliationResult || _.isEmpty(reconciliationResult.added)) {
|
|
136
|
+
console.error('Reconciliation errors', reconciliationResult?.errors);
|
|
137
|
+
} else {
|
|
138
|
+
log('RECONCILIATION_ADDED', {transactions: reconciliationResult.added.length});
|
|
139
|
+
}
|
|
98
140
|
}
|
|
99
141
|
} catch (error) {
|
|
100
142
|
console.error('Error', companyId, error);
|
|
@@ -102,4 +144,3 @@ export async function scrapeAndImportTransactions({companyId, bank}: ScrapeTrans
|
|
|
102
144
|
log('DONE');
|
|
103
145
|
}
|
|
104
146
|
}
|
|
105
|
-
|