Skip to content

Commit 2bd44f8

Browse files
authored
feat: add Amex translator, docs updates
Make sample config json valid
2 parents 82fdc26 + a37d13e commit 2bd44f8

File tree

7 files changed

+81
-35
lines changed

7 files changed

+81
-35
lines changed

docs/configuration.md

Lines changed: 29 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -40,44 +40,45 @@ This tool can be configured using a `.budget-cli.json` file in the root of this
4040
},
4141
"moveFilesAfterImport": {
4242
"AccountTranslatorName1": "/path/to/destination/directory/for/TranslatorName1",
43-
"AccountTranslatorName2": "/path/to/destination/directory/for/TranslatorName2",
43+
"AccountTranslatorName2": "/path/to/destination/directory/for/TranslatorName2"
4444
},
4545
"defaultImportDir": "/path/to/default/import/directory",
4646
"autoCategorization": [
47-
{
48-
"descriptions": [
49-
"Description 1",
50-
"Description 2"
51-
],
52-
"amount": {
53-
"lt": 150,
54-
"lte": 125,
55-
"gte": 75,
56-
"gt": 50,
57-
},
58-
"categorization": {
59-
"category": "expense",
60-
"subCategory": "family",
61-
"expenseType": "need",
62-
"notes": "Notes here"
63-
}
64-
}
47+
{
48+
"descriptions": [
49+
"Description 1",
50+
"Description 2"
51+
],
52+
"amount": {
53+
"lt": 150,
54+
"lte": 125,
55+
"gte": 75,
56+
"gt": 50
57+
},
58+
"categorization": {
59+
"category": "expense",
60+
"subCategory": "family",
61+
"expenseType": "need",
62+
"notes": "Notes here"
63+
}
64+
}
65+
]
6566
}
6667
```
6768

68-
All keys are optional and will provide defaults.
69+
All keys are optional and will provide defaults.
6970

70-
- `outputFile`: This can be set to a string to use a single file for all transactions or an object with years as keys and paths as values to set a different file for different years.
71+
- `outputFile`: This can be set to a string to use a single file for all transactions or an object with years as keys and paths as values to set a different file for different years.
7172
- `subCategories`: This can be set to an object with `income` and `expense` as keys. Each of those keys must be set to an array of strings indicating the sub-categories to use for each. When importing transactions, the tool will prompt you to select one.
7273
- `expenseTypeMapping`: The keys in the object are expense categories and the values are an expense type of "need" or "want" to automatically map expense categories to types.
7374
- `expenseAllowance`: This can be set to an object with keys indicating a specific year. Each year should be set to an object with expense sub-categories as keys. Each sub-category should be set to an object with the keys `allowance`, indicating how much is allowed per month, and `carryover`, indicating any rollover from the previous year (or `0` if none).
7475
- `moveFilesAfterImport`: This can be set to an object with keys indicating an account name and values indicating an absolute path to a local directory. If a destination path is set for a specific account, the CSV file will be moved there after successful import.
7576
- `defaultImportDir`: This can be set to a directory where the import command will look for CSV files. If this is not present then the command will require a directory path in the `input` flag.
7677
- `autoCategorization`: This can be set to a specifically-shaped object that will be used to auto-categorize transactions.
77-
- `descriptions` is an array of one or more strings that are used to match the incoming transaction description in an "or" strategy.
78-
- `amount` is an object that should have at least one of the following keys:
79-
- `gt` (greater than)
80-
- `gte` (greater than or equals)
81-
- `lt` (less than)
82-
- `lte` (less than or equals)
83-
- `categorization` is the object that is merged with the transaction data if the conditions are met.
78+
- `descriptions` is an array of one or more strings that are used to match the incoming transaction description in an "or" strategy.
79+
- `amount` is an object that should have at least one of the following keys:
80+
- `gt` (greater than)
81+
- `gte` (greater than or equals)
82+
- `lt` (less than)
83+
- `lte` (less than or equals)
84+
- `categorization` is the object that is merged with the transaction data if the conditions are met.

docs/usage.md

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,20 +2,20 @@
22

33
### Importing Transactions
44

5-
The first thing you will need for this to do anything for you are some transactions in the database. Transactions are imported from CSV files and translated from their original format to the CSV database. The translators currently available are the [translators](src/translators) folder. See the [Contributing](#Contributing) section for how to add or request new translators.
5+
The first thing you will need for this to do anything for you are some transactions in the database. Transactions are imported from CSV files and translated from their original format to the CSV database. The translators currently available are the [translators](../src/translators) folder. See the [Contributing](#Contributing) section for how to add or request new translators.
66

77
Assuming we have a CSV from one of the supported banks, we can run the importer, indicating a specific file or a directory containing one or more CSV files.
88

99
```bash
10-
$ ./bin/run.js import --input='/path/to/directory'
10+
$ ./bin/run.js import "/path/to/directory"
1111
# ... or
12-
$ ./bin/run.js import --input='/path/to/directory/transactions.csv'
12+
$ ./bin/run.js import "/path/to/directory/transactions.csv"
1313
```
1414

1515
By default, the script will only import transactions for the current year. To import from a year in the past (or, I guess, the future), add a `year` argument to the command.
1616

1717
```bash
18-
$ ./bin/run.js import --input='/path/to/directory' --year='2022'
18+
$ ./bin/run.js import "/path/to/directory" --year=2022
1919
```
2020

2121
If the command checks out, you will be prompted to confirm the import file. This will help you determine if the configuration file is working. Next, it will prompt you for the first CSV it finds from your import path. Answering `n` will move on to the next CSV found, if there is one.

package-lock.json

Lines changed: 1 addition & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

package.json

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -43,4 +43,4 @@
4343
"dirname": "money",
4444
"topicSeparator": ":"
4545
}
46-
}
46+
}

src/translators/amex.ts

Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
import { getFormattedDate } from "../utils/date.js";
2+
import { generateHash } from "../utils/index.js";
3+
import { convertStringCurrencyToNumber } from "../utils/money.js";
4+
import { TransactionImported } from "../utils/transaction.js";
5+
import { Translator } from "./index.js";
6+
7+
/*
8+
* American Express credit card statement parser
9+
* https://global.americanexpress.com/activity/statement
10+
*/
11+
export const amexTranslator: Translator = {
12+
name: "American Express",
13+
14+
translate: (record: string[]): TransactionImported | null => {
15+
// Skip header row
16+
// TODO validate that all columns are in the expected places
17+
if (record[4] === "Amount") {
18+
return null;
19+
}
20+
21+
// TODO allow customizing input format
22+
const datePosted = new Date(record[0]);
23+
24+
// Don't hash Card Member as it's implied by Account #
25+
const hashValues = [
26+
datePosted.toISOString(),
27+
record[1], // Description
28+
record[4], // Amount
29+
record[3], // Account #
30+
];
31+
const transactionId = generateHash(hashValues.join("\n"));
32+
33+
return {
34+
account: "amex",
35+
id: transactionId,
36+
datePosted: getFormattedDate(datePosted),
37+
description: record[1],
38+
amount: convertStringCurrencyToNumber(record[4]),
39+
comments: `Card member: ${record[2]} (${record[3]})`,
40+
};
41+
},
42+
};

src/translators/example.ts

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -3,8 +3,8 @@ import { Translator } from "./index.js";
33
import { convertStringCurrencyToNumber } from "../utils/money.js";
44
import { getFormattedDate } from "../utils/date.js";
55

6-
// TODO: Change the const name here and import ir in ../index.ts
7-
export const boaTranslator: Translator = {
6+
// TODO: Change the const name here and import it in ../index.ts
7+
export const exampleTranslator: Translator = {
88
// TODO: Change this to something useful
99
name: "Name that appears during import",
1010

src/translators/index.ts

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
import { TransactionComplete, TransactionImported } from "../utils/transaction.js";
2+
import { amexTranslator } from "./amex.js";
23
import { boaTranslator } from "./boa.js";
34
import { chaseTranslator } from "./chase.js";
45
import { nordstromsTranslator } from "./nordstroms.js";
@@ -13,6 +14,7 @@ export interface Translator {
1314
}
1415

1516
const availableTranslators: Translator[] = [
17+
amexTranslator,
1618
boaTranslator,
1719
chaseTranslator,
1820
nordstromsTranslator,

0 commit comments

Comments
 (0)