| import { Providers } from "@engine/common/schema"; |
| import { getType } from "@engine/utils/account"; |
| import { getLogoURL } from "@engine/utils/logo"; |
| import { capitalCase } from "change-case"; |
| import type { |
| Account as BaseAccount, |
| Transaction as BaseTransaction, |
| GetAccountBalanceResponse, |
| } from "../types"; |
| import type { |
| FormatAmount, |
| Transaction, |
| TransformAccount, |
| TransformAccountBalance, |
| TransformInstitution, |
| TransformTransaction, |
| } from "./types"; |
|
|
| export const mapTransactionMethod = (type?: string) => { |
| switch (type) { |
| case "payment": |
| case "bill_payment": |
| case "digital_payment": |
| return "payment"; |
| case "card_payment": |
| return "card_purchase"; |
| case "atm": |
| return "card_atm"; |
| case "transfer": |
| return "transfer"; |
| case "ach": |
| return "ach"; |
| case "interest": |
| return "interest"; |
| case "deposit": |
| return "deposit"; |
| case "wire": |
| return "wire"; |
| case "fee": |
| return "fee"; |
| default: |
| return "other"; |
| } |
| }; |
|
|
| type MapTransactionCategory = { |
| transaction: Transaction; |
| amount: number; |
| accountType: string; |
| }; |
|
|
| export const mapTransactionCategory = ({ |
| transaction, |
| amount, |
| accountType, |
| }: MapTransactionCategory) => { |
| if (transaction.type === "fee") { |
| return "fees"; |
| } |
|
|
| if (amount > 0) { |
| |
| |
| if (accountType === "credit") { |
| |
| if (transaction.details?.category === "income") { |
| return "income"; |
| } |
| |
| if ( |
| transaction.type === "payment" || |
| transaction.type === "bill_payment" || |
| transaction.type === "digital_payment" || |
| transaction.type === "ach" || |
| transaction.type === "transfer" |
| ) { |
| return "credit-card-payment"; |
| } |
| |
| return null; |
| } |
| return "income"; |
| } |
|
|
| switch (transaction?.details.category) { |
| case "bar": |
| case "dining": |
| case "groceries": |
| return "meals"; |
| case "transport": |
| case "transportation": |
| return "travel"; |
| case "tax": |
| return "taxes"; |
| case "office": |
| return "office-supplies"; |
| case "phone": |
| return "internet-and-telephone"; |
| case "software": |
| return "software"; |
| case "entertainment": |
| case "sport": |
| return "activity"; |
| case "utilities": |
| return "utilities"; |
| case "electronics": |
| return "equipment"; |
| case "accommodation": |
| return "travel"; |
| case "advertising": |
| return "advertising"; |
| case "charity": |
| return "charitable-donations"; |
| case "education": |
| return "training"; |
| case "health": |
| return "benefits"; |
| case "insurance": |
| return "insurance"; |
| case "fuel": |
| return "travel"; |
| case "home": |
| return "facilities-expenses"; |
| case "service": |
| return "professional-services-fees"; |
| default: |
| return null; |
| } |
| }; |
|
|
| export const transformDescription = (transaction: Transaction) => { |
| const description = |
| transaction?.details?.counterparty?.name && |
| capitalCase(transaction.details.counterparty.name); |
|
|
| if (transaction.description !== description && description) { |
| return capitalCase(description); |
| } |
|
|
| return null; |
| }; |
|
|
| const formatAmout = ({ amount, accountType }: FormatAmount) => { |
| |
| if (accountType === "credit") { |
| return +(amount * -1); |
| } |
|
|
| return +amount; |
| }; |
|
|
| export const transformTransaction = ({ |
| transaction, |
| accountType, |
| }: TransformTransaction): BaseTransaction => { |
| const method = mapTransactionMethod(transaction.type); |
| const description = transformDescription(transaction); |
| const amount = formatAmout({ |
| amount: +transaction.amount, |
| accountType, |
| }); |
|
|
| return { |
| id: transaction.id, |
| date: transaction.date, |
| name: transaction.description && capitalCase(transaction.description), |
| description: description ?? null, |
| currency_rate: null, |
| currency_source: null, |
| method, |
| amount, |
| currency: "USD", |
| category: mapTransactionCategory({ transaction, amount, accountType }), |
| balance: transaction?.running_balance ? +transaction.running_balance : null, |
| counterparty_name: transaction?.details?.counterparty?.name |
| ? capitalCase(transaction.details.counterparty.name) |
| : null, |
| merchant_name: null, |
| status: transaction?.status === "posted" ? "posted" : "pending", |
| }; |
| }; |
|
|
| type TransformAccountParams = TransformAccount & { |
| accountDetails?: { |
| account_number: string; |
| routing_numbers: { |
| ach: string | null; |
| wire: string | null; |
| bacs: string | null; |
| }; |
| } | null; |
| }; |
|
|
| export const transformAccount = ({ |
| id, |
| name, |
| currency, |
| enrollment_id, |
| type, |
| subtype, |
| institution, |
| balance, |
| last_four, |
| accountDetails, |
| }: TransformAccountParams): BaseAccount => { |
| const accountType = getType(type); |
|
|
| return { |
| id, |
| name, |
| currency: currency.toUpperCase(), |
| enrollment_id: enrollment_id, |
| institution: transformInstitution(institution), |
| type: accountType, |
| balance: transformAccountBalance({ balance, accountType }), |
| |
| resource_id: last_four, |
| expires_at: null, |
| iban: null, |
| subtype: subtype || null, |
| bic: null, |
| |
| routing_number: accountDetails?.routing_numbers?.ach || null, |
| wire_routing_number: accountDetails?.routing_numbers?.wire || null, |
| account_number: accountDetails?.account_number || null, |
| sort_code: accountDetails?.routing_numbers?.bacs || null, |
| available_balance: null, |
| credit_limit: null, |
| }; |
| }; |
|
|
| type TransformAccountBalanceParams = { |
| balance: TransformAccountBalance; |
| accountType?: string; |
| }; |
|
|
| |
| |
| |
| |
| |
| |
| |
| export const transformAccountBalance = ({ |
| balance, |
| accountType, |
| }: TransformAccountBalanceParams): GetAccountBalanceResponse => { |
| const rawAmount = +balance.amount; |
|
|
| |
| const amount = |
| accountType === "credit" && rawAmount < 0 ? Math.abs(rawAmount) : rawAmount; |
|
|
| return { |
| currency: balance.currency.toUpperCase(), |
| amount, |
| available_balance: null, |
| credit_limit: null, |
| }; |
| }; |
|
|
| export const transformInstitution = (institution: TransformInstitution) => ({ |
| id: institution.id, |
| name: institution.name, |
| logo: getLogoURL(institution.id), |
| provider: Providers.enum.teller, |
| }); |
|
|