Add support for Amex importer
This commit is contained in:
@@ -2,11 +2,13 @@ export { BaseTransactionParser } from "./base";
|
||||
import { ProfileConfig, ParserConfig, ServerConfig } from "@/types/config";
|
||||
import { BaseTransactionParser } from "./base";
|
||||
import { default as PlIng } from "./pl/ing";
|
||||
import { default as PlAmex } from "./pl/amex";
|
||||
|
||||
type Constructor<T extends BaseTransactionParser<ParserConfig>> = new (name: string) => T;
|
||||
|
||||
const PARSERS: Record<string, Constructor<BaseTransactionParser<ParserConfig>>> = {
|
||||
"pl.ing": PlIng
|
||||
"pl.ing": PlIng,
|
||||
"pl.amex": PlAmex,
|
||||
};
|
||||
|
||||
export function createParser(config: ProfileConfig, serverConfig: ServerConfig): BaseTransactionParser<ParserConfig> {
|
||||
|
||||
94
src/parser/pl/amex/index.ts
Normal file
94
src/parser/pl/amex/index.ts
Normal file
@@ -0,0 +1,94 @@
|
||||
import { BaseTransactionParser } from "@/parser/base";
|
||||
import { ParserConfig } from "@/types/config";
|
||||
import { Transaction } from "@/types/transaction";
|
||||
import { parseAmount } from "@/util/parser";
|
||||
|
||||
type AmexTransaction = {
|
||||
[K in typeof headers[number]]: string;
|
||||
};
|
||||
|
||||
type ValidatedAmexTransaction = Omit<AmexTransaction, 'originalAmount' | 'billedAmount'> & {
|
||||
originalAmount: number;
|
||||
billedAmount: number;
|
||||
};
|
||||
|
||||
const headers = [
|
||||
'posted',
|
||||
'occurred',
|
||||
'merchantName',
|
||||
'merchantCity',
|
||||
'merchantState',
|
||||
'merchantZipCode',
|
||||
'mCC/SICCode',
|
||||
'mCCDescription',
|
||||
'originalAmount',
|
||||
'currencyDesc',
|
||||
'conversionRate',
|
||||
'billedAmount',
|
||||
'accountAppliedTo',
|
||||
'debitCredit',
|
||||
'referenceNumber',
|
||||
'statementCycle',
|
||||
'accountName',
|
||||
'accountNumber'
|
||||
];
|
||||
|
||||
export default class extends BaseTransactionParser<ParserConfig> {
|
||||
protected requiredFields = [];
|
||||
#transactions: ValidatedAmexTransaction[] = [];
|
||||
|
||||
async pushTransaction(data: string[]): Promise<boolean> {
|
||||
if (data.length !== headers.length) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const transaction: AmexTransaction = {};
|
||||
headers.forEach((key, index) => {
|
||||
transaction[key] = data[index].trim();
|
||||
})
|
||||
|
||||
if (!/^\d{4}-\d{2}-\d{2}$/.test(data[0])) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const originalAmount = parseAmount(transaction.originalAmount);
|
||||
const billedAmount = parseAmount(transaction.billedAmount);
|
||||
|
||||
if (originalAmount === undefined && billedAmount === undefined) {
|
||||
return false;
|
||||
}
|
||||
|
||||
this.#transactions.push({
|
||||
...transaction,
|
||||
originalAmount,
|
||||
billedAmount
|
||||
} as ValidatedAmexTransaction);
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
async reconcile(): Promise<Transaction[]> {
|
||||
return this.#transactions.map(transaction => {
|
||||
const amount = transaction.billedAmount;
|
||||
|
||||
if (!amount) {
|
||||
throw new Error(`Undefined amount for transaction: ${transaction}`);
|
||||
}
|
||||
|
||||
const to = [transaction.merchantName, transaction.merchantCity, transaction.merchantState, transaction.merchantZipCode]
|
||||
.filter(x => x !== undefined)
|
||||
.map(x => x.trim())
|
||||
.filter(x => x !== "")
|
||||
.join(" ");
|
||||
|
||||
return {
|
||||
kind: 'regular',
|
||||
from: transaction.accountName,
|
||||
to,
|
||||
date: transaction.posted,
|
||||
title: `${transaction.mCCDescription} (${transaction.originalAmount} ${transaction.currencyDesc}, conv. rate: ${transaction.conversionRate})`,
|
||||
amount: -amount,
|
||||
};
|
||||
});
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user