UNPKG

@accounter/server

Version:
187 lines • 8.99 kB
import { endOfDay, lastDayOfMonth, startOfDay, startOfMonth } from 'date-fns'; import { GraphQLError } from 'graphql'; import { DocumentType } from '../../../shared/enums.js'; import { dateToTimelessDateString } from '../../../shared/helpers/index.js'; import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js'; import { BusinessTripsProvider } from '../../business-trips/providers/business-trips.provider.js'; import { getChargeBusinesses } from '../../charges/helpers/common.helper.js'; import { validateCharge } from '../../charges/helpers/validate.helper.js'; import { ChargesProvider } from '../../charges/providers/charges.provider.js'; import { DocumentsProvider } from '../../documents/providers/documents.provider.js'; import { BusinessesProvider } from '../../financial-entities/providers/businesses.provider.js'; import { isRefundCharge } from '../../ledger/helpers/common-charge-ledger.helper.js'; import { adjustTaxRecord, } from '../helpers/vat-report.helper.js'; export const getVatRecords = async ({ filters }, injector) => { const { authorities: { vatReportExcludedBusinessNames }, } = await injector.get(AdminContextProvider).getVerifiedAdminContext(); try { const response = { income: [], expenses: [], missingInfo: [], differentMonthDoc: [], businessTrips: [], }; const docsChargesIDs = new Set(); const reportIssuerId = filters?.financialEntityId; const fromDate = filters?.monthDate ? dateToTimelessDateString(startOfMonth(new Date(filters.monthDate))) : undefined; const toDate = filters?.monthDate ? dateToTimelessDateString(lastDayOfMonth(new Date(filters.monthDate))) : undefined; // get all documents by date filters const relevantDocumentsPromise = injector .get(DocumentsProvider) .getDocumentsByFilters({ fromVatDate: fromDate, toVatDate: toDate, }) .then(documents => documents.filter(doc => { if (doc.charge_id) { docsChargesIDs.add(doc.charge_id); } // filter documents with vat_report_date_override outside of the date range if (doc.vat_report_date_override) { const isBeforeFromDate = fromDate && doc.vat_report_date_override < startOfDay(fromDate); const isAfterToDate = toDate && doc.vat_report_date_override > endOfDay(toDate); if (isBeforeFromDate || isAfterToDate) { return false; } } if (!doc.charge_id || !doc.creditor_id || !doc.debtor_id) { // filter invoice documents with linked charge return false; } const isRelevantDoc = ['INVOICE', 'INVOICE_RECEIPT', 'CREDIT_INVOICE'].includes(doc.type); return isRelevantDoc; })); // get all businesses const businessesPromise = injector.get(BusinessesProvider).getAllBusinesses(); const chargesPromise = injector.get(ChargesProvider).getChargesByFilters({ fromDate, toDate, ownerIds: reportIssuerId ? [reportIssuerId] : undefined, chargeType: filters?.chargesType, }); const [relevantDocuments, businesses, charges] = await Promise.all([ relevantDocumentsPromise, businessesPromise, chargesPromise, ]); let docsCharges = charges.filter(charge => docsChargesIDs.has(charge.id)); if (docsCharges.length < docsChargesIDs.size) { const moreDocsCharges = await injector.get(ChargesProvider).getChargesByFilters({ IDs: Array.from(docsChargesIDs).filter(id => !docsCharges.find(charge => charge.id === id)), ownerIds: [reportIssuerId], }); charges.push(...moreDocsCharges); docsCharges.push(...moreDocsCharges); } const extendedCharges = await Promise.all(charges.map(async (charge) => { const { allBusinessIds } = await getChargeBusinesses(charge.id, injector); return { ...charge, allBusinessIds, }; })); docsCharges = extendedCharges.filter(charge => { for (const businessId of charge.allBusinessIds) { if (vatReportExcludedBusinessNames.includes(businessId)) { return false; } } return true; }); const incomeRecords = []; const expenseRecords = []; const includedChargeIDs = new Set(); relevantDocuments.map(doc => { // filter charge linked to document const charge = docsCharges.find(charge => charge.id === doc.charge_id); if (!charge) { throw new GraphQLError(`for some weird reason no charge found for document ID=${doc.id}`); } // filter business linked to document const counterpartyId = doc.creditor_id === doc.owner_id ? doc.debtor_id : doc.debtor_id === doc.owner_id ? doc.creditor_id : null; const business = businesses.find(business => business.id === counterpartyId); if (!business) { throw new GraphQLError(`for some weird reason no counterparty found for document ID=${doc.id}`); } const isReimbursement = isRefundCharge(charge.user_description); // add charge to income/expense records if (doc.vat_amount && (doc.type === DocumentType.CreditInvoice ? doc.creditor_id : doc.debtor_id) === reportIssuerId) { includedChargeIDs.add(charge.id); if (filters?.chargesType !== 'EXPENSE') { expenseRecords.push({ charge, doc, business }); } } else if (doc.vat_amount != null && (doc.type === DocumentType.CreditInvoice ? doc.debtor_id === reportIssuerId : doc.creditor_id === reportIssuerId) && Number(doc.total_amount) > 0 && !isReimbursement) { includedChargeIDs.add(charge.id); if (filters?.chargesType !== 'INCOME') { incomeRecords.push({ charge, doc, business }); } } }); if (incomeRecords.length + expenseRecords.length > 0) { // TODO: what if no exchange dates found? await Promise.all([ ...incomeRecords.map(async (rawRecord) => adjustTaxRecord(rawRecord, injector).then(res => { response.income.push(res); })), ...expenseRecords.map(async (rawRecord) => adjustTaxRecord(rawRecord, injector).then(res => { response.expenses.push(res); })), ]); } // validate charges for missing info const validatedCharges = await Promise.all(charges.map(async (charge) => { const [validation, businessTrip] = await Promise.all([ validateCharge(charge, injector), injector.get(BusinessTripsProvider).getBusinessTripsByChargeIdLoader.load(charge.id), ]); if (!('isValid' in validation)) { throw new Error('Error validating charge'); } return { charge, isValid: validation.isValid, businessTripId: businessTrip?.id ?? null, }; })); for (const { charge, isValid, businessTripId } of validatedCharges) { if (businessTripId) { // If valid and has business trip, add to business trips response.businessTrips.push(charge); } else if (isValid) { if (!includedChargeIDs.has(charge.id)) { // If valid but not yet included, add to charges with different month doc response.differentMonthDoc.push(charge); } } else { // add to charges with missing info response.missingInfo.push(charge); } } response.income = response.income.sort((a, b) => (b.documentDate?.getDate() ?? 0) - (a.documentDate?.getDate() ?? 0)); response.expenses = response.expenses.sort((a, b) => (b.documentDate?.getDate() ?? 0) - (a.documentDate?.getDate() ?? 0)); return response; } catch (e) { console.error('Error fetching vat report records:', e); throw new GraphQLError(e?.message ?? 'Error fetching vat report records'); } }; //# sourceMappingURL=get-vat-records.resolver.js.map