UNPKG

@accounter/server

Version:
137 lines 7.42 kB
import { GraphQLError } from 'graphql'; import { AdminContextProvider } from '../../../admin-context/providers/admin-context.provider.js'; import { getChargeBusinesses } from '../../../charges/helpers/common.helper.js'; import { ExchangeProvider } from '../../../exchange-rates/providers/exchange.provider.js'; import { FinancialAccountsProvider } from '../../../financial-accounts/providers/financial-accounts.provider.js'; import { TransactionsProvider } from '../../../transactions/providers/transactions.provider.js'; import { ledgerEntryFromMainTransaction } from '../../helpers/common-charge-ledger.helper.js'; import { splitFeeTransactions } from '../../helpers/fee-transactions.js'; import { storeInitialGeneratedRecords } from '../../helpers/ledgrer-storage.helper.js'; import { generateMiscExpensesLedger } from '../../helpers/misc-expenses-ledger.helper.js'; import { getFinancialAccountTaxCategoryId, getLedgerBalanceInfo, LedgerError, ledgerProtoToRecordsConverter, updateLedgerBalanceByEntry, validateTransactionBasicVariables, } from '../../helpers/utils.helper.js'; export const generateLedgerRecordsForForeignSecurities = async (charge, { insertLedgerRecordsIfNotExists }, { injector }) => { const chargeId = charge.id; const { ownerId, defaultLocalCurrency, foreignSecurities: { foreignSecuritiesFeesCategoryId }, } = await injector.get(AdminContextProvider).getVerifiedAdminContext(); const errors = new Set(); try { // validate ledger records are balanced const ledgerBalance = new Map(); const transactionsPromise = injector .get(TransactionsProvider) .transactionsByChargeIDLoader.load(chargeId); const financialAccountsPromise = injector .get(FinancialAccountsProvider) .getFinancialAccountsByOwnerIdLoader.load(ownerId); const [transactions, financialAccounts, { mainBusinessId }] = await Promise.all([ transactionsPromise, financialAccountsPromise, getChargeBusinesses(chargeId, injector), ]); const foreignSecuritiesAccountId = financialAccounts.find(account => account.type === 'FOREIGN_SECURITIES')?.id; if (!foreignSecuritiesAccountId) { throw new GraphQLError('Foreign securities account is missing'); } const entriesPromises = []; const financialAccountLedgerEntries = []; const feeFinancialAccountLedgerEntries = []; const miscExpensesLedgerEntries = []; // generate ledger from transactions const { mainTransactions, feeTransactions } = splitFeeTransactions(transactions); const mainTransactionsPromises = mainTransactions.map(async (transaction) => await ledgerEntryFromMainTransaction({ ...transaction, source_reference: 'foreign_securities' }, injector, chargeId, charge.owner_id, mainBusinessId ?? undefined) .then(ledgerEntry => { financialAccountLedgerEntries.push(ledgerEntry); updateLedgerBalanceByEntry(ledgerEntry, ledgerBalance, defaultLocalCurrency); }) .catch(e => { if (e instanceof LedgerError) { errors.add(e.message); } else { throw e; } })); // create a ledger record for fee transactions const feeTransactionsPromises = feeTransactions.map(async (transaction) => { if (!foreignSecuritiesFeesCategoryId) { errors.add(`Foreign securities fees category ID is missing`); return; } // for each transaction, create a ledger record const { currency, valueDate } = validateTransactionBasicVariables(transaction); let amount = Number(transaction.amount); let foreignAmount = undefined; if (currency !== defaultLocalCurrency) { // get exchange rate for currency const exchangeRate = await injector .get(ExchangeProvider) .getExchangeRates(currency, defaultLocalCurrency, valueDate); foreignAmount = amount; // calculate amounts in ILS: amount = exchangeRate * amount; } const accountTaxCategoryId = await getFinancialAccountTaxCategoryId(injector, transaction); const isCreditorCounterparty = amount > 0; const ledgerEntry = { id: transaction.id, invoiceDate: transaction.event_date, valueDate, currency, creditAccountID1: isCreditorCounterparty ? foreignSecuritiesFeesCategoryId : accountTaxCategoryId, creditAmount1: foreignAmount ? Math.abs(foreignAmount) : undefined, localCurrencyCreditAmount1: Math.abs(amount), debitAccountID1: isCreditorCounterparty ? accountTaxCategoryId : foreignSecuritiesFeesCategoryId, debitAmount1: foreignAmount ? Math.abs(foreignAmount) : undefined, localCurrencyDebitAmount1: Math.abs(amount), description: transaction.source_description ?? undefined, reference: transaction.origin_key, isCreditorCounterparty, ownerId: charge.owner_id, currencyRate: transaction.currency_rate ? Number(transaction.currency_rate) : undefined, chargeId, }; feeFinancialAccountLedgerEntries.push(ledgerEntry); updateLedgerBalanceByEntry(ledgerEntry, ledgerBalance, defaultLocalCurrency); }); // generate ledger from misc expenses const expensesLedgerPromise = generateMiscExpensesLedger(charge, injector).then(entries => { entries.map(entry => { entry.ownerId = charge.owner_id; miscExpensesLedgerEntries.push(entry); updateLedgerBalanceByEntry(entry, ledgerBalance, defaultLocalCurrency); }); }); entriesPromises.push(...mainTransactionsPromises, ...feeTransactionsPromises, expensesLedgerPromise); await Promise.all(entriesPromises); const records = [ ...financialAccountLedgerEntries, ...feeFinancialAccountLedgerEntries, ...miscExpensesLedgerEntries, ]; if (insertLedgerRecordsIfNotExists) { await storeInitialGeneratedRecords(charge.id, records, injector); } const allowedUnbalancedBusinesses = new Set(); const mainLedgerEntry = financialAccountLedgerEntries[0]; if (!mainLedgerEntry.isCreditorCounterparty) { allowedUnbalancedBusinesses.add(mainLedgerEntry.debitAccountID1); } const ledgerBalanceInfo = await getLedgerBalanceInfo(injector, ledgerBalance, errors, allowedUnbalancedBusinesses); return { records: ledgerProtoToRecordsConverter(records), charge, balance: ledgerBalanceInfo, errors: Array.from(errors), }; } catch (e) { return { __typename: 'CommonError', message: `Failed to generate ledger records for charge ID="${chargeId}"\n${e}`, }; } }; //# sourceMappingURL=foreign-securities-ledger-generation.resolver.js.map