@fuzzle/opencode-accountant 0.0.12-next.1 → 0.0.12
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/README.md +25 -23
- package/agent/accountant.md +5 -105
- package/package.json +2 -3
- package/docs/tools/classify-statements.md +0 -404
- package/docs/tools/import-statements.md +0 -252
- package/docs/tools/update-prices.md +0 -581
|
@@ -1,252 +0,0 @@
|
|
|
1
|
-
# import-statements Tool
|
|
2
|
-
|
|
3
|
-
The `import-statements` tool imports classified CSV bank statements into hledger using rules files. It operates in two modes:
|
|
4
|
-
|
|
5
|
-
- **Check mode** (`checkOnly: true`, default): Validates transactions and reports any that cannot be categorized
|
|
6
|
-
- **Import mode** (`checkOnly: false`): Imports validated transactions and moves processed files to the done directory
|
|
7
|
-
|
|
8
|
-
## Arguments
|
|
9
|
-
|
|
10
|
-
| Argument | Type | Default | Description |
|
|
11
|
-
| ----------- | ------- | ------- | ------------------------------------------- |
|
|
12
|
-
| `provider` | string | - | Filter by provider (e.g., `revolut`, `ubs`) |
|
|
13
|
-
| `currency` | string | - | Filter by currency (e.g., `chf`, `eur`) |
|
|
14
|
-
| `checkOnly` | boolean | `true` | If true, only validate without importing |
|
|
15
|
-
|
|
16
|
-
## Output Format
|
|
17
|
-
|
|
18
|
-
**Note on paths:** All file paths in the examples below use `{paths.*}` variables. These are configured in `config/import/providers.yaml`. Default values are:
|
|
19
|
-
|
|
20
|
-
- `{paths.pending}` = `import/pending`
|
|
21
|
-
- `{paths.done}` = `import/done`
|
|
22
|
-
- `{paths.rules}` = `ledger/rules`
|
|
23
|
-
|
|
24
|
-
### Check Mode - All Transactions Matched
|
|
25
|
-
|
|
26
|
-
When all transactions have matching rules:
|
|
27
|
-
|
|
28
|
-
```json
|
|
29
|
-
{
|
|
30
|
-
"success": true,
|
|
31
|
-
"files": [
|
|
32
|
-
{
|
|
33
|
-
"csv": "{paths.pending}/ubs/chf/transactions-ubs-0235-90250546.0.csv",
|
|
34
|
-
"rulesFile": "{paths.rules}/ubs-0235-90250546.0.rules",
|
|
35
|
-
"transactions": 25,
|
|
36
|
-
"unknownPostings": []
|
|
37
|
-
}
|
|
38
|
-
],
|
|
39
|
-
"summary": {
|
|
40
|
-
"filesProcessed": 1,
|
|
41
|
-
"totalTransactions": 25,
|
|
42
|
-
"matched": 25,
|
|
43
|
-
"unknown": 0
|
|
44
|
-
},
|
|
45
|
-
"message": "All transactions matched. Ready to import with checkOnly: false"
|
|
46
|
-
}
|
|
47
|
-
```
|
|
48
|
-
|
|
49
|
-
### Check Mode - Unknown Postings Found
|
|
50
|
-
|
|
51
|
-
When transactions don't match any `if` pattern in the rules file, the tool returns the full CSV row data for each unknown posting to provide context for classification:
|
|
52
|
-
|
|
53
|
-
```json
|
|
54
|
-
{
|
|
55
|
-
"success": false,
|
|
56
|
-
"files": [
|
|
57
|
-
{
|
|
58
|
-
"csv": "{paths.pending}/ubs/chf/transactions-ubs-0235-90250546.0.csv",
|
|
59
|
-
"rulesFile": "{paths.rules}/ubs-0235-90250546.0.rules",
|
|
60
|
-
"transactions": 25,
|
|
61
|
-
"unknownPostings": [
|
|
62
|
-
{
|
|
63
|
-
"date": "2026-01-16",
|
|
64
|
-
"description": "Connor, John",
|
|
65
|
-
"amount": "CHF95.25",
|
|
66
|
-
"account": "income:unknown",
|
|
67
|
-
"csvRow": {
|
|
68
|
-
"trade_date": "2026-01-16",
|
|
69
|
-
"trade_time": "",
|
|
70
|
-
"booking_date": "2026-01-16",
|
|
71
|
-
"value_date": "2026-01-16",
|
|
72
|
-
"currency": "CHF",
|
|
73
|
-
"debit": "",
|
|
74
|
-
"credit": "95.25",
|
|
75
|
-
"individual_amount": "",
|
|
76
|
-
"balance": "4746.23",
|
|
77
|
-
"transaction_no": "ABC123",
|
|
78
|
-
"description1": "Connor, John",
|
|
79
|
-
"description2": "Twint deposit",
|
|
80
|
-
"description3": "Ref: TW-12345",
|
|
81
|
-
"footnotes": ""
|
|
82
|
-
}
|
|
83
|
-
},
|
|
84
|
-
{
|
|
85
|
-
"date": "2026-01-30",
|
|
86
|
-
"description": "Balance closing of service prices",
|
|
87
|
-
"amount": "CHF-10.00",
|
|
88
|
-
"account": "expenses:unknown",
|
|
89
|
-
"csvRow": {
|
|
90
|
-
"trade_date": "2026-01-30",
|
|
91
|
-
"trade_time": "",
|
|
92
|
-
"booking_date": "2026-01-30",
|
|
93
|
-
"value_date": "2026-01-30",
|
|
94
|
-
"currency": "CHF",
|
|
95
|
-
"debit": "10.00",
|
|
96
|
-
"credit": "",
|
|
97
|
-
"individual_amount": "",
|
|
98
|
-
"balance": "2364.69",
|
|
99
|
-
"transaction_no": "DEF456",
|
|
100
|
-
"description1": "Balance closing of service prices",
|
|
101
|
-
"description2": "",
|
|
102
|
-
"description3": "",
|
|
103
|
-
"footnotes": ""
|
|
104
|
-
}
|
|
105
|
-
}
|
|
106
|
-
]
|
|
107
|
-
}
|
|
108
|
-
],
|
|
109
|
-
"summary": {
|
|
110
|
-
"filesProcessed": 1,
|
|
111
|
-
"totalTransactions": 25,
|
|
112
|
-
"matched": 23,
|
|
113
|
-
"unknown": 2
|
|
114
|
-
}
|
|
115
|
-
}
|
|
116
|
-
```
|
|
117
|
-
|
|
118
|
-
### Check Mode - Missing Rules File
|
|
119
|
-
|
|
120
|
-
When a CSV file has no matching rules file:
|
|
121
|
-
|
|
122
|
-
```json
|
|
123
|
-
{
|
|
124
|
-
"success": false,
|
|
125
|
-
"files": [
|
|
126
|
-
{
|
|
127
|
-
"csv": "{paths.pending}/ubs/chf/transactions.csv",
|
|
128
|
-
"error": "No matching rules file found. Create a rules file with 'source' directive pointing to this CSV."
|
|
129
|
-
}
|
|
130
|
-
],
|
|
131
|
-
"summary": {
|
|
132
|
-
"filesProcessed": 1,
|
|
133
|
-
"filesWithoutRules": 1
|
|
134
|
-
}
|
|
135
|
-
}
|
|
136
|
-
```
|
|
137
|
-
|
|
138
|
-
### Import Mode - Success
|
|
139
|
-
|
|
140
|
-
When importing with all transactions matched:
|
|
141
|
-
|
|
142
|
-
```json
|
|
143
|
-
{
|
|
144
|
-
"success": true,
|
|
145
|
-
"files": [
|
|
146
|
-
{
|
|
147
|
-
"csv": "{paths.pending}/ubs/chf/transactions.csv",
|
|
148
|
-
"rulesFile": "{paths.rules}/ubs.rules",
|
|
149
|
-
"imported": true,
|
|
150
|
-
"movedTo": "{paths.done}/ubs/chf/transactions.csv"
|
|
151
|
-
}
|
|
152
|
-
],
|
|
153
|
-
"summary": {
|
|
154
|
-
"filesProcessed": 1,
|
|
155
|
-
"filesImported": 1,
|
|
156
|
-
"totalTransactions": 25
|
|
157
|
-
},
|
|
158
|
-
"message": "Successfully imported 1 file(s)"
|
|
159
|
-
}
|
|
160
|
-
```
|
|
161
|
-
|
|
162
|
-
### Import Mode - Blocked by Unknown Postings
|
|
163
|
-
|
|
164
|
-
Import mode runs a check first and aborts if any unknowns exist:
|
|
165
|
-
|
|
166
|
-
```json
|
|
167
|
-
{
|
|
168
|
-
"success": false,
|
|
169
|
-
"error": "Cannot import: 2 transactions have unknown accounts. Run with checkOnly: true to see details and add rules.",
|
|
170
|
-
"hint": "Run with checkOnly: true first to identify and fix unknown postings"
|
|
171
|
-
}
|
|
172
|
-
```
|
|
173
|
-
|
|
174
|
-
## Unknown Posting Types
|
|
175
|
-
|
|
176
|
-
hledger assigns transactions to `income:unknown` or `expenses:unknown` based on the direction:
|
|
177
|
-
|
|
178
|
-
| Transaction Type | Account Assigned |
|
|
179
|
-
| -------------------------- | ------------------ |
|
|
180
|
-
| Money coming in (positive) | `income:unknown` |
|
|
181
|
-
| Money going out (negative) | `expenses:unknown` |
|
|
182
|
-
|
|
183
|
-
## Fixing Unknown Postings
|
|
184
|
-
|
|
185
|
-
When the tool reports unknown postings, the `csvRow` field contains all available data from the original CSV to help determine the correct account. This includes additional description fields, transaction references, and other metadata that may help with classification.
|
|
186
|
-
|
|
187
|
-
Add `if` rules to the appropriate rules file based on the posting details:
|
|
188
|
-
|
|
189
|
-
```
|
|
190
|
-
# Example: Categorize a friend's reimbursement
|
|
191
|
-
# (csvRow showed description2: "Twint deposit" confirming it's a payment app transfer)
|
|
192
|
-
if Connor, John
|
|
193
|
-
account1 income:reimbursements
|
|
194
|
-
|
|
195
|
-
# Example: Categorize bank service charges
|
|
196
|
-
if Balance closing of service prices
|
|
197
|
-
account1 expenses:fees:bank
|
|
198
|
-
```
|
|
199
|
-
|
|
200
|
-
Then run the tool again with `checkOnly: true` to verify the rules work.
|
|
201
|
-
|
|
202
|
-
### CSV Row Field Names
|
|
203
|
-
|
|
204
|
-
The `csvRow` object uses field names from the `fields` directive in the rules file. Common fields include:
|
|
205
|
-
|
|
206
|
-
| Field | Description |
|
|
207
|
-
| ---------------- | ------------------------------------------------------- |
|
|
208
|
-
| `trade_date` | When the transaction occurred |
|
|
209
|
-
| `booking_date` | When it was booked |
|
|
210
|
-
| `description1` | Primary description |
|
|
211
|
-
| `description2` | Secondary description (often useful for classification) |
|
|
212
|
-
| `description3` | Additional reference information |
|
|
213
|
-
| `transaction_no` | Unique transaction identifier |
|
|
214
|
-
| `debit` | Debit amount (money out) |
|
|
215
|
-
| `credit` | Credit amount (money in) |
|
|
216
|
-
|
|
217
|
-
The exact field names depend on your rules file configuration.
|
|
218
|
-
|
|
219
|
-
## Error Handling
|
|
220
|
-
|
|
221
|
-
### hledger Errors
|
|
222
|
-
|
|
223
|
-
If hledger fails to parse a CSV or rules file:
|
|
224
|
-
|
|
225
|
-
```json
|
|
226
|
-
{
|
|
227
|
-
"success": false,
|
|
228
|
-
"files": [
|
|
229
|
-
{
|
|
230
|
-
"csv": "{paths.pending}/ubs/chf/transactions.csv",
|
|
231
|
-
"rulesFile": "{paths.rules}/ubs.rules",
|
|
232
|
-
"error": "hledger error: Parse error at line 5: invalid date format"
|
|
233
|
-
}
|
|
234
|
-
],
|
|
235
|
-
"summary": {
|
|
236
|
-
"filesProcessed": 1,
|
|
237
|
-
"filesWithErrors": 1
|
|
238
|
-
}
|
|
239
|
-
}
|
|
240
|
-
```
|
|
241
|
-
|
|
242
|
-
### Configuration Errors
|
|
243
|
-
|
|
244
|
-
If the config file is missing or invalid:
|
|
245
|
-
|
|
246
|
-
```json
|
|
247
|
-
{
|
|
248
|
-
"success": false,
|
|
249
|
-
"error": "Failed to load configuration: Configuration file not found: config/import/providers.yaml",
|
|
250
|
-
"hint": "Ensure config/import/providers.yaml exists with a 'rules' path configured"
|
|
251
|
-
}
|
|
252
|
-
```
|