UNPKG

@accounter/server

Version:

148 lines (127 loc) 5.1 kB
import { GraphQLError } from 'graphql'; import type { IGetChargesByIdsResult } from '@modules/charges/types'; import { ExchangeProvider } from '@modules/exchange-rates/providers/exchange.provider.js'; import { FinancialAccountsProvider } from '@modules/financial-accounts/providers/financial-accounts.provider.js'; import { TaxCategoriesProvider } from '@modules/financial-entities/providers/tax-categories.provider.js'; import type { IGetTransactionsByChargeIdsResult } from '@modules/transactions/types'; import { DEFAULT_LOCAL_CURRENCY, FEE_TAX_CATEGORY_ID, INTERNAL_WALLETS_IDS, SWIFT_BUSINESS_ID, } from '@shared/constants'; import type { LedgerProto } from '@shared/types'; import { getTaxCategoryNameByAccountCurrency, validateTransactionBasicVariables, } from './utils.helper.js'; export function splitFeeTransactions(transactions: Array<IGetTransactionsByChargeIdsResult>) { const feeTransactions = []; const mainTransactions = []; for (const transaction of transactions) { if (transaction.is_fee) { feeTransactions.push(transaction); } else { mainTransactions.push(transaction); } } return { feeTransactions, mainTransactions }; } export function isSupplementalFeeTransaction( transaction: IGetTransactionsByChargeIdsResult, ): boolean { if (!transaction.is_fee) { return false; } if (!transaction.business_id) { throw new Error( `Transaction ID="${transaction.id}" is missing business_id, which is required to figure if fee is supplemental`, ); } if (INTERNAL_WALLETS_IDS.includes(transaction.business_id)) { return true; } const fundamentalFeeBusinesses: string[] = [SWIFT_BUSINESS_ID]; if (fundamentalFeeBusinesses.includes(transaction.business_id)) { return false; } throw new Error( `Unable to determine if business ID="${transaction.business_id}" is supplemental or fundamental fee`, ); } export async function getEntriesFromFeeTransaction( transaction: IGetTransactionsByChargeIdsResult, charge: IGetChargesByIdsResult, context: GraphQLModules.Context, ): Promise<Array<LedgerProto>> { const { injector } = context; const ledgerEntries: Array<LedgerProto> = []; if (!transaction.is_fee) { throw new GraphQLError( `Who did a non-fee transaction marked as fee? (Transaction ID="${transaction.id}")`, ); } const isSupplementalFee = isSupplementalFeeTransaction(transaction); const { currency, valueDate, transactionBusinessId } = validateTransactionBasicVariables(transaction); let amount = Number(transaction.amount); let foreignAmount: number | undefined = undefined; if (currency !== DEFAULT_LOCAL_CURRENCY) { // get exchange rate for currency const exchangeRate = await injector .get(ExchangeProvider) .getExchangeRates(currency, DEFAULT_LOCAL_CURRENCY, valueDate); foreignAmount = amount; // calculate amounts in ILS amount = exchangeRate * amount; } const isCreditorCounterparty = amount > 0; let mainAccount = transactionBusinessId; const partialLedgerEntry: LedgerProto = { id: transaction.id, invoiceDate: transaction.event_date, valueDate, currency, creditAmount1: foreignAmount ? Math.abs(foreignAmount) : undefined, localCurrencyCreditAmount1: Math.abs(amount), debitAmount1: foreignAmount ? Math.abs(foreignAmount) : undefined, localCurrencyDebitAmount1: Math.abs(amount), description: transaction.source_description ?? undefined, reference1: transaction.source_id, isCreditorCounterparty: isSupplementalFee ? isCreditorCounterparty : !isCreditorCounterparty, ownerId: charge.owner_id, currencyRate: transaction.currency_rate ? Number(transaction.currency_rate) : undefined, chargeId: transaction.charge_id, }; if (isSupplementalFee) { const account = await injector .get(FinancialAccountsProvider) .getFinancialAccountByAccountIDLoader.load(transaction.account_id); if (!account) { throw new GraphQLError(`Transaction ID="${transaction.id}" is missing account`); } const taxCategoryName = getTaxCategoryNameByAccountCurrency(account, currency); const businessTaxCategory = await injector .get(TaxCategoriesProvider) .taxCategoryByNamesLoader.load(taxCategoryName); if (!businessTaxCategory) { throw new GraphQLError(`Account ID="${account.id}" is missing tax category`); } mainAccount = businessTaxCategory.id; } else { const mainBusiness = charge.business_id ?? undefined; const ledgerEntry: LedgerProto = { ...partialLedgerEntry, creditAccountID1: isCreditorCounterparty ? mainAccount : mainBusiness, debitAccountID1: isCreditorCounterparty ? mainBusiness : mainAccount, }; ledgerEntries.push(ledgerEntry); } const ledgerEntry: LedgerProto = { ...partialLedgerEntry, creditAccountID1: isCreditorCounterparty ? FEE_TAX_CATEGORY_ID : mainAccount, debitAccountID1: isCreditorCounterparty ? mainAccount : FEE_TAX_CATEGORY_ID, }; ledgerEntries.push(ledgerEntry); return ledgerEntries; }