UNPKG

@accounter/server

Version:
107 lines 5.55 kB
import { DECREASED_VAT_RATIO } from '../../../shared/constants.js'; import { DocumentType } from '../../../shared/enums.js'; import { dateToTimelessDateString, formatCurrency } from '../../../shared/helpers/index.js'; import { AdminContextProvider } from '../../admin-context/providers/admin-context.provider.js'; import { getChargeDocumentsMeta, getChargeTransactionsMeta, } from '../../charges/helpers/common.helper.js'; import { DepreciationProvider } from '../../depreciation/providers/depreciation.provider.js'; import { ExchangeProvider } from '../../exchange-rates/providers/exchange.provider.js'; import { VatProvider } from '../../vat/providers/vat.provider.js'; export async function adjustTaxRecord(rawRecord, injector) { const { defaultLocalCurrency, locality } = await injector .get(AdminContextProvider) .getVerifiedAdminContext(); try { const { charge, doc, business } = rawRecord; const currency = formatCurrency(doc.currency_code); if (!doc.total_amount) { throw new Error(`Amount missing for invoice ID=${doc.id}`); } if (!doc.currency_code) { throw new Error(`Currency missing for invoice ID=${doc.id}`); } if (!doc.date) { throw new Error(`Date is missing for invoice ID=${doc.id}`); } const [isProperty, { transactionsMinEventDate }, { documentsMinDate }] = await Promise.all([ injector .get(DepreciationProvider) .getDepreciationRecordsByChargeIdLoader.load(charge.id) .then(records => records.length > 0), getChargeTransactionsMeta(charge.id, injector), getChargeDocumentsMeta(charge.id, injector), ]); const isDecreasedVat = charge.is_property; if (isDecreasedVat && !isProperty) { throw new Error(`Charge ${charge.id} is marked as property, but has no depreciation records.`); } // get exchange rate let rate = 1; if (doc.exchange_rate_override) { rate = Number(doc.exchange_rate_override); } else { rate = await injector .get(ExchangeProvider) .getExchangeRates(currency, defaultLocalCurrency, doc.date); } const creditInvoiceFactor = doc.type === DocumentType.CreditInvoice ? -1 : 1; const vatAmount = doc.vat_amount ? doc.vat_amount * creditInvoiceFactor : 0; const totalAmount = doc.total_amount * creditInvoiceFactor; const noVatAmount = doc.no_vat_amount ? Number(doc.no_vat_amount) * creditInvoiceFactor : 0; const isLocal = business.country === locality; const partialRecord = { businessId: business.id, chargeAccountantStatus: charge.accountant_status, chargeDate: transactionsMinEventDate ?? documentsMinDate, // must have min_date, as will throw if local doc is missing date chargeId: charge.id, currencyCode: currency, documentDate: doc.date, documentId: doc.id, documentSerial: doc.serial_number, documentUrl: doc.image_url, documentAmount: String(creditInvoiceFactor * totalAmount), foreignVat: doc.currency_code === defaultLocalCurrency ? null : vatAmount, localVat: doc.currency_code === defaultLocalCurrency ? vatAmount : null, isProperty, vatNumber: isLocal ? business.vat_number : undefined, isExpense: doc.type === DocumentType.CreditInvoice ? doc.debtor_id !== doc.owner_id : doc.debtor_id === doc.owner_id, allocationNumber: doc.allocation_number, pcn874RecordType: business.pcn874_record_type_override ?? undefined, }; // set default amountBeforeVAT if (!vatAmount) { partialRecord.localAmountBeforeVAT = (totalAmount - noVatAmount) * rate; } else if (partialRecord.businessId) { const vatValue = await injector .get(VatProvider) .getVatValueByDateLoader.load(dateToTimelessDateString(doc.date)); if (!vatValue) { throw new Error(`VAT value is missing for invoice ID=${doc.id}`); } const convertedVat = vatValue / (1 + vatValue); const tiplessTotalAmount = totalAmount - noVatAmount; const vatDiff = Math.abs(tiplessTotalAmount * convertedVat - vatAmount); if (vatDiff > 0.005) { console.error(`Expected VAT amount is not ${vatValue * 100}%, but got ${vatAmount / (tiplessTotalAmount - vatAmount)} for invoice ID=${doc.id}`); } // decorate record with additional fields const vatAfterDeduction = vatAmount * (isDecreasedVat ? DECREASED_VAT_RATIO : 1); const amountBeforeVAT = totalAmount - vatAfterDeduction; partialRecord.foreignVatAfterDeduction = vatAfterDeduction; partialRecord.localVatAfterDeduction = vatAfterDeduction * rate; partialRecord.foreignAmountBeforeVAT = amountBeforeVAT; partialRecord.localAmountBeforeVAT = amountBeforeVAT * rate; partialRecord.roundedVATToAdd = Math.round(vatAfterDeduction * rate); partialRecord.eventLocalAmount = totalAmount * rate; } return partialRecord; } catch (e) { console.error(e); throw e; } } //# sourceMappingURL=vat-report.helper.js.map