diff options
| author | ivar <i@oiee.no> | 2026-03-09 23:05:38 +0100 |
|---|---|---|
| committer | ivar <i@oiee.no> | 2026-03-09 23:05:38 +0100 |
| commit | 69448e29a85cad3a94b3be3ad33efbc52764528f (patch) | |
| tree | c32b8c817322fdf26edbbb3fa75b9505a7020ae8 /cli/src/actual.ts | |
| parent | b35302fa020ec82a9d67a6cb34379d42983d3cfc (diff) | |
| download | sparebank1-actualbudget-69448e29a85cad3a94b3be3ad33efbc52764528f.tar.xz sparebank1-actualbudget-69448e29a85cad3a94b3be3ad33efbc52764528f.zip | |
Diffstat (limited to 'cli/src/actual.ts')
| -rw-r--r-- | cli/src/actual.ts | 51 |
1 files changed, 51 insertions, 0 deletions
diff --git a/cli/src/actual.ts b/cli/src/actual.ts new file mode 100644 index 0000000..a236013 --- /dev/null +++ b/cli/src/actual.ts @@ -0,0 +1,51 @@ +import * as actualApi from "@actual-app/api" +import { existsSync, mkdirSync } from "node:fs" +import { join } from "node:path" +import { Temporal } from "temporal-polyfill" +import { CONFIG_DIR } from "./config" +import type { Config } from "./config" +import type { Sb1Transaction, ActualAccount } from "./types" +import type { ImportTransactionEntity } from "@actual-app/api/@types/loot-core/src/types/models/import-transaction" + +let inited = false + +export async function initActual(config: Config["actual"]) { + if (inited) return + const dataDir = join(CONFIG_DIR, "actualDataDir") + if (!existsSync(dataDir)) mkdirSync(dataDir, { recursive: true }) + process.env.ACTUAL_DATA_DIR = dataDir + await actualApi.init({ password: config.password, serverURL: config.host, dataDir }) + await actualApi.downloadBudget(config.fileId) + await actualApi.sync() + inited = true +} + +export async function getAccounts(config: Config["actual"]): Promise<ActualAccount[]> { + await initActual(config) + return actualApi.getAccounts() as Promise<ActualAccount[]> +} + +export async function importTransactions( + config: Config["actual"], + accountId: string, + transactions: Sb1Transaction[], + dryRun: boolean +) { + await initActual(config) + + const mapped: ImportTransactionEntity[] = transactions + .filter(t => t.bookingStatus === "BOOKED") + .map(t => ({ + account: accountId, + date: Temporal.Instant.fromEpochMilliseconds(t.date) + .toString({ timeZone: "Europe/Oslo" }) + .split("T")[0], + amount: Math.round(t.amount * 100), + payee_name: t.cleanedDescription, + notes: t.description?.toLowerCase().trim() !== t.cleanedDescription?.toLowerCase().trim() + ? t.description + : undefined + })) + + return actualApi.importTransactions(accountId, mapped, { dryRun }) +} |
