-
-
Notifications
You must be signed in to change notification settings - Fork 2
/
run.ts
154 lines (123 loc) · 4.13 KB
/
run.ts
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
// github:lunch-money/lunch-money-js
import { LunchMoney, DraftTransaction } from "lunch-money";
import { readCSV, writeCSV } from "./util.js";
import {
transformAccountCategories,
addLunchMoneyCategoryIds,
createLunchMoneyCategories,
} from "./categories.js";
import {
useArchiveForOldAccounts,
addLunchMoneyAccountIds,
createLunchMoneyAccounts,
} from "./accounts.js";
import { applyStandardTransformations } from "./transformations.js";
import dotenv from "dotenv";
import humanInterval from "human-interval";
import dateFns from "date-fns";
(async () => {
dotenv.config();
if (!process.env.LUNCH_MONEY_API_KEY) {
console.error("Lunch Money API key not set");
process.exit(1);
}
const mintTransactions = await readCSV("./data.csv");
// TODO this should be an input parameter to the script
// TODO this isn't really the import date, this is only used to determine when transactions should be treated as old
function determineStartImportDate() {
let range = humanInterval("1 year");
if (!range) {
console.log("Invalid date to search for active accounts");
process.exit(1);
}
// range is in milliseconds
range /= 1000;
const oneYearAgo = dateFns.subSeconds(new Date(), range);
return oneYearAgo;
}
const startImportDate = determineStartImportDate();
const mintTransactionsWithArchiveAccount = useArchiveForOldAccounts(
mintTransactions,
startImportDate,
"./account_mapping.json"
);
const lunchMoney = new LunchMoney({ token: process.env.LUNCH_MONEY_API_KEY });
const mintTransactionsWithTransformedCategories =
await transformAccountCategories(
mintTransactionsWithArchiveAccount,
lunchMoney,
"./category_mapping.json"
);
await createLunchMoneyCategories(
mintTransactionsWithTransformedCategories,
lunchMoney
);
await createLunchMoneyAccounts(
mintTransactionsWithTransformedCategories,
lunchMoney
);
const mintTransactionsTransformed = applyStandardTransformations(
mintTransactionsWithTransformedCategories
);
const mintTransactionsWithLunchMoneyIds = await addLunchMoneyCategoryIds(
await addLunchMoneyAccountIds(mintTransactionsTransformed, lunchMoney),
lunchMoney
);
writeCSV(mintTransactionsWithLunchMoneyIds, "./data_transformed.csv");
// TODO should confirm the user actually wants to send everything to LM
// TODO we should extract this out into a separate function
// TODO unsure if we can increase the batch size
// TODO some unknowns about the API that we are guessing on right now:
// - https://github.com/lunch-money/developers/issues/11
// - https://github.com/lunch-money/developers/issues/10
const BATCH_SIZE = 100;
console.log(
`Pushing ${mintTransactionsWithLunchMoneyIds.length} transactions to LunchMoney`
);
console.log(
`This will be done in ${Math.ceil(
mintTransactionsWithLunchMoneyIds.length / BATCH_SIZE
)}`
);
// page through transactions
for (
let i = 0;
i * BATCH_SIZE < mintTransactionsWithLunchMoneyIds.length;
i += 1
) {
const batch = mintTransactionsWithLunchMoneyIds.slice(
i * BATCH_SIZE,
(i + 1) * BATCH_SIZE
);
console.log(
`Pushing batch ${i} transactions (${batch.length}) to LunchMoney`
);
const formattedTransactions = batch.map(
(transaction) =>
({
payee: transaction.Description,
notes: transaction.Notes,
date: transaction.LunchMoneyDate,
category_id: transaction.LunchMoneyCategoryId,
amount: transaction.LunchMoneyAmount,
asset_id: transaction.LunchMoneyAccountId,
external_id: transaction.LunchMoneyExtId,
tags: transaction.LunchMoneyTags,
currency: "usd",
status: "cleared",
} as DraftTransaction)
);
const result = await lunchMoney.createTransactions(
formattedTransactions,
// don't apply rules, user can apply manually
false,
// check for recurring expenses
true,
// treat negative amounts as debit
true
);
if (result.error) {
debugger;
}
}
})().catch((e) => console.error(e));