UNPKG

@accounter/server

Version:
269 lines • 12.7 kB
import { subDays } from 'date-fns'; import { dateToTimelessDateString } from '../../../shared/helpers/index.js'; import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js'; import { isCryptoCurrency } from '../../exchange-rates/helpers/exchange.helper.js'; import { AdminBusinessesProvider } from '../../financial-entities/providers/admin-businesses.provider.js'; import { BusinessesProvider } from '../../financial-entities/providers/businesses.provider.js'; import { FinancialEntitiesProvider } from '../../financial-entities/providers/financial-entities.provider.js'; import { businessTransactionsSumFromLedgerRecords } from '../../financial-entities/resolvers/business-transactions-sum-from-ledger-records.resolver.js'; import { LedgerProvider } from '../../ledger/providers/ledger.provider.js'; import { SortCodesProvider } from '../../sort-codes/providers/sort-codes.provider.js'; export async function businessForUniformFormat(injector, fromDate, toDate) { const { ownerId } = await injector.get(AdminContextProvider).getVerifiedAdminContext(); const adminBusiness = await injector .get(AdminBusinessesProvider) .getAdminBusinessByIdLoader.load(ownerId); if (!adminBusiness) { throw new Error('Admin business not found'); } if (!adminBusiness.vat_number) { throw new Error('Admin business has no VAT number'); } return { businessId: adminBusiness.id, name: adminBusiness.name, taxId: adminBusiness.vat_number, reportingPeriod: { startDate: fromDate, endDate: toDate, }, }; } export async function journalEntriesForUniformFormat(injector, fromDate, toDate) { const { ownerId } = await injector.get(AdminContextProvider).getVerifiedAdminContext(); const ledgerRecords = await injector .get(LedgerProvider) .getLedgerRecordsByDates({ ownerId, fromDate, toDate }); const entries = []; for (const record of ledgerRecords) { const isCrypto = isCryptoCurrency(record.currency.toUpperCase()); const commonEntry = { id: record.id, date: dateToTimelessDateString(record.invoice_date), description: record.description ?? '', transactionNumber: Number(record.id.replace(/\D/g, '').slice(-10)), batchNumber: 1, // "transactionType": '', referenceDocument: record.reference1 ?? undefined, // "referenceDocumentType": '', referenceDocument2: undefined, // "referenceDocumentType2": '', valueDate: dateToTimelessDateString(record.value_date), currencyCode: isCrypto ? 'ILS' : record.currency, transactionAmount: Math.max(Math.abs(Number(record.credit_local_amount1)), Math.abs(Number(record.debit_local_amount1))), // "quantityField": '', matchingField1: record.charge_id, matchingField2: undefined, // "branchId": '', entryDate: dateToTimelessDateString(record.created_at), // "operatorUsername": '', }; let lineNumber = 1; // for credit1 if (record.credit_entity1 && Math.abs(Number(record.credit_local_amount1)) > 0) { entries.push({ ...commonEntry, id: `c1-${commonEntry.id}`, accountId: record.credit_entity1, amount: Math.abs(Number(record.credit_local_amount1)), counterAccountKey: record.debit_entity1 ?? undefined, debitCreditIndicator: '2', // 2 for credit foreignCurrencyAmount: record.credit_foreign_amount1 && !isCrypto ? Math.abs(Number(record.credit_foreign_amount1)) : undefined, transactionLineNumber: lineNumber, }); lineNumber++; } // for credit2 if (record.credit_entity2 && Math.abs(Number(record.credit_local_amount1)) > 0) { entries.push({ ...commonEntry, id: `c2-${commonEntry.id}`, accountId: record.credit_entity2, amount: Math.abs(Number(record.credit_local_amount2)), counterAccountKey: record.debit_entity1 ?? undefined, debitCreditIndicator: '2', // 2 for credit foreignCurrencyAmount: record.credit_foreign_amount2 && !isCrypto ? Math.abs(Number(record.credit_foreign_amount2)) : undefined, transactionLineNumber: lineNumber, }); lineNumber++; } // for debit1 if (record.debit_entity1 && Math.abs(Number(record.debit_local_amount1)) > 0) { entries.push({ ...commonEntry, id: `d1-${commonEntry.id}`, accountId: record.debit_entity1, amount: Math.abs(Number(record.debit_local_amount1)), counterAccountKey: record.credit_entity1 ?? undefined, debitCreditIndicator: '1', // 1 for debit foreignCurrencyAmount: record.debit_foreign_amount1 && !isCrypto ? Math.abs(Number(record.debit_foreign_amount1)) : undefined, transactionLineNumber: lineNumber, }); lineNumber++; } // for debit2 if (record.debit_entity2 && Math.abs(Number(record.debit_local_amount2)) > 0) { entries.push({ ...commonEntry, id: `d2-${commonEntry.id}`, accountId: record.debit_entity2, amount: Math.abs(Number(record.debit_local_amount2)), counterAccountKey: record.credit_entity1 ?? undefined, debitCreditIndicator: '1', // 1 for debit foreignCurrencyAmount: record.debit_foreign_amount2 && !isCrypto ? Math.abs(Number(record.debit_foreign_amount2)) : undefined, transactionLineNumber: lineNumber, }); } } return entries; } export async function accountsForUniformFormat(context, info, fromDate, toDate) { const { injector } = context; const { ownerId } = await injector.get(AdminContextProvider).getVerifiedAdminContext(); const financialEntitiesPromise = injector .get(FinancialEntitiesProvider) .getAllFinancialEntities(); // get admin business info const adminBusinessPromise = injector .get(AdminBusinessesProvider) .getAdminBusinessByIdLoader.load(ownerId); const [financialEntities, adminBusiness, sortCodes] = await Promise.all([ financialEntitiesPromise, adminBusinessPromise, injector.get(SortCodesProvider).getSortCodesByOwnerIdLoader.load(ownerId), ]); if (!adminBusiness) { throw new Error('Admin business not found'); } const openingBalances = await businessTransactionsSumFromLedgerRecords({}, { filters: { ownerIds: [ownerId], toDate: dateToTimelessDateString(subDays(new Date(fromDate), 1)), includeRevaluation: true, }, }, context, info); const businessesBalance = new Map(); if (openingBalances.__typename === 'CommonError') { throw new Error(`Failed to fetch opening balances: ${openingBalances.message}`); } else if (openingBalances.__typename === 'BusinessTransactionsSumFromLedgerRecordsSuccessfulResult') { await Promise.all(openingBalances.businessTransactionsSum.map(async (businessSumPromise) => { const businessSum = await businessSumPromise; for (const [code, amounts] of Object.entries(businessSum)) { if (isCryptoCurrency(code.toUpperCase()) || code === 'ILS' || code === 'businessId') { continue; } if (typeof amounts !== 'string' && amounts.total !== 0) { businessesBalance.set(businessSum.businessId, { ILS: { opening: businessSum.ILS.total, credit: 0, debit: 0, }, foreign: { currency: code, total: amounts.total }, }); return; } } if (businessSum.ILS.total !== 0) { businessesBalance.set(businessSum.businessId, { ILS: { opening: businessSum.ILS.total, credit: 0, debit: 0, }, }); } })); } const totalDebitCredit = await businessTransactionsSumFromLedgerRecords({}, { filters: { ownerIds: [ownerId], fromDate, toDate, includeRevaluation: true, }, }, context, info); if (totalDebitCredit.__typename === 'CommonError') { throw new Error(`Failed to fetch opening balances: ${totalDebitCredit.message}`); } else if (totalDebitCredit.__typename === 'BusinessTransactionsSumFromLedgerRecordsSuccessfulResult') { await Promise.all(totalDebitCredit.businessTransactionsSum.map(async (businessSumPromise) => { const businessSum = await businessSumPromise; const existing = businessesBalance.get(businessSum.businessId); if (existing) { existing.ILS.credit += businessSum.ILS.credit; existing.ILS.debit += businessSum.ILS.debit; } else { businessesBalance.set(businessSum.businessId, { ILS: { opening: 0, credit: businessSum.ILS.credit, debit: businessSum.ILS.debit, }, }); } })); } const businesses = await injector .get(BusinessesProvider) .getBusinessByIdLoader.loadMany(Array.from(businessesBalance.keys())); const businessesMap = new Map(businesses.filter(b => b && !(b instanceof Error)).map(business => [business.id, business])); const sortCodesMap = new Map(sortCodes.map(code => [code.key, code.name ?? ''])); const financialEntitiesMap = new Map(financialEntities.map(entity => [entity.id, entity])); const accounts = []; for (const [businessId, balance] of Array.from(businessesBalance.entries())) { const financialEntity = financialEntitiesMap.get(businessId); if (!financialEntity) { throw new Error(`Financial entity not found for business ID: ${businessId}`); } if (!financialEntity.sort_code) { throw new Error(`Financial entity ${financialEntity.id} has no sort code`); } const sortCodeName = financialEntity.sort_code ? sortCodesMap.get(financialEntity.sort_code) : undefined; if (!sortCodeName) { throw new Error(`Sort code not found for business ID: ${businessId}`); } accounts.push({ id: businessId, name: financialEntity.name, sortCode: { key: financialEntity.sort_code.toString(), name: sortCodeName, }, address: { // street: businessesMap.get(businessId)?.address?.street, // houseNumber: businessesMap.get(businessId)?.address?.houseNumber, // city: businessesMap.get(businessId)?.address?.city, // zip: businessesMap.get(businessId)?.address?.zip, country: businessesMap.get(businessId)?.country === 'ISR' ? 'IL' : undefined, }, // countryCode: businessesMap.get(businessId)?.countryCode, // parentAccountKey: businessesMap.get(businessId)?.parentAccountKey, vatId: businessesMap.get(businessId)?.vat_number ?? undefined, accountOpeningBalance: balance.ILS.opening, totalDebits: balance.ILS.debit || undefined, totalCredits: balance.ILS.credit || undefined, // accountingClassificationCode: // businessesMap.get(businessId)?.accountingClassificationCode ?? '', // branchId: businessesMap.get(businessId)?.branchId ?? '', openingBalanceForeignCurrency: balance.foreign?.total, // TODO: handle foreign currency foreignCurrencyCode: balance.foreign?.currency, }); } return accounts; } //# sourceMappingURL=uniform-format.helper.js.map