@accounter/server
Version:
Accounter GraphQL server
212 lines • 11.2 kB
JavaScript
import { GraphQLError } from 'graphql';
import { Currency } from '../../../shared/enums.js';
import { dateToTimelessDateString, formatFinancialAmount } from '../../../shared/helpers/index.js';
import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js';
import { ChargesProvider } from '../../charges/providers/charges.provider.js';
import { LedgerProvider } from '../../ledger/providers/ledger.provider.js';
import { handleBusinessTransaction } from '../helpers/business-transactions.helper.js';
import { FinancialEntitiesProvider } from '../providers/financial-entities.provider.js';
import { businessTransactionsSumFromLedgerRecords } from './business-transactions-sum-from-ledger-records.resolver.js';
export const businessTransactionsResolvers = {
Query: {
businessTransactionsSumFromLedgerRecords,
businessTransactionsFromLedgerRecords: async (_, { filters }, context, _info) => {
const { injector } = context;
const { ownerIds, businessIDs, fromDate, toDate, type } = filters || {};
const shouldFetchAllFinancialEntities = !businessIDs?.length && !!type;
const financialEntities = await (shouldFetchAllFinancialEntities
? injector.get(FinancialEntitiesProvider).getAllFinancialEntities()
: injector
.get(FinancialEntitiesProvider)
.getFinancialEntityByIdLoader.loadMany(businessIDs ?? []));
const isFilteredByFinancialEntities = !!filters?.businessIDs?.length;
const financialEntitiesIDs = financialEntities
?.filter(fe => {
if (!fe || !('id' in fe)) {
return false;
}
if (type) {
return type.toLocaleLowerCase() === fe.type;
}
return true;
})
.map(business => business.id);
try {
const charges = await injector.get(ChargesProvider).getChargesByFilters({
ownerIds: ownerIds ?? undefined,
businessIds: businessIDs,
fromAnyDate: fromDate,
toAnyDate: toDate,
});
const ledgerRecordSets = await Promise.all(charges.map(charge => injector.get(LedgerProvider).getLedgerRecordsByChargesIdLoader.load(charge.id)));
const ledgerRecords = ledgerRecordSets.flat();
const rawTransactions = [];
for (const record of ledgerRecords) {
// re-filter ledger records by date (to prevent charge's out-of-range dates from affecting the sum)
if (!!fromDate && dateToTimelessDateString(record.invoice_date) < fromDate) {
continue;
}
if (!!toDate && dateToTimelessDateString(record.invoice_date) > toDate) {
continue;
}
if (record.credit_entity1 &&
(!isFilteredByFinancialEntities || financialEntitiesIDs.includes(record.credit_entity1))) {
const transaction = handleBusinessTransaction(record, record.credit_entity1, record.debit_entity1, true, record.credit_local_amount1, record.credit_foreign_amount1);
rawTransactions.push(transaction);
}
if (record.credit_entity2 &&
(!isFilteredByFinancialEntities || financialEntitiesIDs.includes(record.credit_entity2))) {
const transaction = handleBusinessTransaction(record, record.credit_entity2, record.debit_entity2 ?? record.debit_entity2, true, record.credit_local_amount2, record.credit_foreign_amount2);
rawTransactions.push(transaction);
}
if (record.debit_entity1 &&
(!isFilteredByFinancialEntities || financialEntitiesIDs.includes(record.debit_entity1))) {
const transaction = handleBusinessTransaction(record, record.debit_entity1, record.credit_entity1, false, record.debit_local_amount1, record.debit_foreign_amount1);
rawTransactions.push(transaction);
}
if (record.debit_entity2 &&
(!isFilteredByFinancialEntities || financialEntitiesIDs.includes(record.debit_entity2))) {
const transaction = handleBusinessTransaction(record, record.debit_entity2, record.credit_entity2 ?? record.credit_entity1, false, record.debit_local_amount2, record.debit_foreign_amount2);
rawTransactions.push(transaction);
}
}
return {
businessTransactions: rawTransactions.sort((a, b) => {
const chargeA = charges.find(charge => charge.id === a.chargeId);
const chargeB = charges.find(charge => charge.id === b.chargeId);
const dateA = Math.min(...[
chargeA?.documents_min_date?.getTime(),
chargeA?.transactions_min_event_date?.getTime(),
].filter(Boolean));
const dateB = Math.min(...[
chargeB?.documents_min_date?.getTime(),
chargeB?.transactions_min_event_date?.getTime(),
].filter(Boolean));
if (dateA < dateB)
return -1;
if (dateA > dateB)
return 1;
if (a.chargeId < b.chargeId)
return -1;
if (a.chargeId > b.chargeId)
return 1;
if (a.date.getTime() < b.date.getTime())
return -1;
if (a.date.getTime() > b.date.getTime())
return 1;
return 0;
}),
};
}
catch (e) {
console.error(e);
return {
__typename: 'CommonError',
message: 'Error fetching business transactions from ledger records',
};
}
},
},
BusinessTransactionsSumFromLedgerRecordsResult: {
__resolveType: (obj, _context, _info) => {
if ('__typename' in obj && obj.__typename === 'CommonError')
return 'CommonError';
return 'BusinessTransactionsSumFromLedgerRecordsSuccessfulResult';
},
},
BusinessTransactionSum: {
business: (rawSum, _, { injector }) => injector
.get(FinancialEntitiesProvider)
.getFinancialEntityByIdLoader.load(rawSum.businessId)
.then(res => {
if (!res) {
throw new GraphQLError(`Business with id ${rawSum.businessId} not found`);
}
return res;
}),
credit: async (rawSum, _, { injector }) => {
const { defaultLocalCurrency } = await injector
.get(AdminContextProvider)
.getVerifiedAdminContext();
return formatFinancialAmount(rawSum[defaultLocalCurrency].credit, defaultLocalCurrency);
},
debit: async (rawSum, _, { injector }) => {
const { defaultLocalCurrency } = await injector
.get(AdminContextProvider)
.getVerifiedAdminContext();
return formatFinancialAmount(rawSum[defaultLocalCurrency].debit, defaultLocalCurrency);
},
total: async (rawSum, _, { injector }) => {
const { defaultLocalCurrency } = await injector
.get(AdminContextProvider)
.getVerifiedAdminContext();
return formatFinancialAmount(rawSum[defaultLocalCurrency].total, defaultLocalCurrency);
},
foreignCurrenciesSum: async (rawSum, _, { injector }) => {
const { defaultLocalCurrency } = await injector
.get(AdminContextProvider)
.getVerifiedAdminContext();
const currencies = [];
for (const key in rawSum) {
if (!Object.values(Currency).includes(key))
continue;
const currency = key;
if (currency === defaultLocalCurrency)
continue;
const currencySum = rawSum[currency];
if (currencySum.credit || currencySum.debit) {
currencies.push({
credit: formatFinancialAmount(currencySum.credit, currency),
debit: formatFinancialAmount(currencySum.debit, currency),
total: formatFinancialAmount(currencySum.total, currency),
currency,
});
}
}
return currencies;
},
},
BusinessTransactionsFromLedgerRecordsResult: {
__resolveType: parent => 'businessTransactions' in parent
? 'BusinessTransactionsFromLedgerRecordsSuccessfulResult'
: 'CommonError',
},
BusinessTransaction: {
amount: async (parent, _, { injector }) => {
const { defaultLocalCurrency } = await injector
.get(AdminContextProvider)
.getVerifiedAdminContext();
return formatFinancialAmount(Number.isNaN(parent.foreignAmount)
? parent.amount
: Number(parent.amount) * (parent.isCredit ? 1 : -1), defaultLocalCurrency);
},
business: (parent, _, { injector }) => injector
.get(FinancialEntitiesProvider)
.getFinancialEntityByIdLoader.load(parent.businessId)
.then(res => {
if (!res) {
throw new GraphQLError(`Financial entity with id ${parent.businessId} not found`);
}
return res;
}),
foreignAmount: parent => formatFinancialAmount(Number.isNaN(parent.foreignAmount)
? parent.foreignAmount
: Number(parent.foreignAmount) * (parent.isCredit ? 1 : -1), parent.currency),
invoiceDate: parent => dateToTimelessDateString(parent.date),
reference: parent => parent.reference ?? null,
details: parent => parent.details ?? null,
counterAccount: (parent, _, { injector }) => parent.counterAccountId
? injector
.get(FinancialEntitiesProvider)
.getFinancialEntityByIdLoader.load(parent.counterAccountId)
.then(res => {
if (!res) {
throw new GraphQLError(`Financial entity with id ${parent.counterAccountId} not found`);
}
return res;
})
: null,
chargeId: parent => parent.chargeId,
},
};
//# sourceMappingURL=business-transactions.resolver.js.map