@accounter/server
Version:
285 lines (263 loc) • 9.4 kB
text/typescript
import { GraphQLError } from 'graphql';
import { getMinDate } from '@modules/ledger/helpers/ledger-lock.js';
import { generateLedgerRecordsForFinancialCharge } from '@modules/ledger/resolvers/ledger-generation/financial-ledger-generation.resolver.js';
import { MiscExpensesProvider } from '@modules/misc-expenses/providers/misc-expenses.provider.js';
import { ChargeTypeEnum } from '@shared/enums';
import { dateToTimelessDateString } from '@shared/helpers';
import { getChargeType } from '../helpers/charge-type.js';
import { generateAndTagCharge } from '../helpers/financial-charge.helper.js';
import type { ChargesModule } from '../types.js';
import { commonChargeFields } from './common.js';
export const financialChargesResolvers: ChargesModule.Resolvers = {
Mutation: {
generateRevaluationCharge: async (_, { date, ownerId }, context, info) => {
const { injector, adminContext } = context;
if (adminContext.ledgerLock && date <= adminContext.ledgerLock) {
throw new GraphQLError('Cannot generate revaluation charge for locked period');
}
try {
const charge = await generateAndTagCharge(
injector,
ownerId,
adminContext.general.taxCategories.exchangeRevaluationTaxCategoryId,
`Revaluation charge for ${date}`,
);
await generateLedgerRecordsForFinancialCharge(
charge,
{ insertLedgerRecordsIfNotExists: true },
context,
info,
);
return charge;
} catch (e) {
console.error(e);
throw new GraphQLError('Error generating revaluation charge');
}
},
generateBankDepositsRevaluationCharge: async (_, { date, ownerId }, context, info) => {
const { injector, adminContext } = context;
if (adminContext.ledgerLock && date <= adminContext.ledgerLock) {
throw new GraphQLError('Cannot generate revaluation charge for locked period');
}
try {
const { bankDepositInterestIncomeTaxCategoryId } = adminContext.bankDeposits;
if (!bankDepositInterestIncomeTaxCategoryId) {
throw new GraphQLError('Bank deposit interest income tax category missing');
}
const charge = await generateAndTagCharge(
injector,
ownerId,
bankDepositInterestIncomeTaxCategoryId,
`Bank deposits revaluation charge for ${date}`,
);
await generateLedgerRecordsForFinancialCharge(
charge,
{ insertLedgerRecordsIfNotExists: true },
context,
info,
);
return charge;
} catch (e) {
console.error(e);
throw new GraphQLError('Error generating bank deposits revaluation charge');
}
},
generateTaxExpensesCharge: async (_, { year, ownerId }, context, info) => {
const {
injector,
adminContext: {
ledgerLock,
authorities: { taxExpensesTaxCategoryId },
},
} = context;
if (ledgerLock && `${year}-12-31` <= ledgerLock) {
throw new GraphQLError('Cannot generate revaluation charge for locked period');
}
try {
const charge = await generateAndTagCharge(
injector,
ownerId,
taxExpensesTaxCategoryId,
`Tax expenses charge for ${year.substring(0, 4)}`,
);
await generateLedgerRecordsForFinancialCharge(
charge,
{ insertLedgerRecordsIfNotExists: true },
context,
info,
);
return charge;
} catch (e) {
console.error(e);
throw new GraphQLError('Error generating tax expenses charge');
}
},
generateDepreciationCharge: async (_, { year, ownerId }, context, info) => {
const {
injector,
adminContext: {
ledgerLock,
depreciation: { accumulatedDepreciationTaxCategoryId },
},
} = context;
if (ledgerLock && `${year}-12-31` <= ledgerLock) {
throw new GraphQLError('Cannot generate revaluation charge for locked period');
}
if (!accumulatedDepreciationTaxCategoryId) {
throw new GraphQLError('Accumulated depreciation tax category missing');
}
try {
const charge = await generateAndTagCharge(
injector,
ownerId,
accumulatedDepreciationTaxCategoryId,
`Depreciation charge for ${year.substring(0, 4)}`,
);
await generateLedgerRecordsForFinancialCharge(
charge,
{ insertLedgerRecordsIfNotExists: true },
context,
info,
);
return charge;
} catch (e) {
console.error(e);
throw new GraphQLError('Error generating depreciation charge');
}
},
generateRecoveryReserveCharge: async (_, { year, ownerId }, context, info) => {
const {
injector,
adminContext: {
ledgerLock,
salaries: { recoveryReserveTaxCategoryId },
},
} = context;
if (ledgerLock && `${year}-12-31` <= ledgerLock) {
throw new GraphQLError('Cannot generate revaluation charge for locked period');
}
if (!recoveryReserveTaxCategoryId) {
throw new GraphQLError('Recovery reserve tax category missing');
}
try {
const charge = await generateAndTagCharge(
injector,
ownerId,
recoveryReserveTaxCategoryId,
`Recovery reserve charge for ${year.substring(0, 4)}`,
);
await generateLedgerRecordsForFinancialCharge(
charge,
{ insertLedgerRecordsIfNotExists: true },
context,
info,
);
return charge;
} catch (e) {
console.error(e);
throw new GraphQLError('Error generating recovery reserve charge');
}
},
generateVacationReserveCharge: async (_, { year, ownerId }, context, info) => {
const {
injector,
adminContext: {
ledgerLock,
salaries: { vacationReserveTaxCategoryId },
},
} = context;
if (ledgerLock && `${year}-12-31` <= ledgerLock) {
throw new GraphQLError('Cannot generate revaluation charge for locked period');
}
if (!vacationReserveTaxCategoryId) {
throw new GraphQLError('Vacation reserve tax category missing');
}
try {
const charge = await generateAndTagCharge(
injector,
ownerId,
vacationReserveTaxCategoryId,
`Vacation reserves charge for ${year.substring(0, 4)}`,
);
await generateLedgerRecordsForFinancialCharge(
charge,
{ insertLedgerRecordsIfNotExists: true },
context,
info,
);
return charge;
} catch (e) {
console.error(e);
throw new GraphQLError('Error generating vacation reserves charge');
}
},
generateBalanceCharge: async (_, { description, balanceRecords }, context, info) => {
const { injector, adminContext } = context;
if (!balanceRecords.length) {
throw new GraphQLError('Balance charge must include balance records');
}
const { defaultTaxCategoryId, defaultAdminBusinessId, ledgerLock } = adminContext;
if (!defaultTaxCategoryId) {
throw new GraphQLError('Default tax category missing');
}
if (ledgerLock) {
const minDate = getMinDate(
balanceRecords.map(record => [new Date(record.invoiceDate), record.valueDate]).flat(),
);
if (minDate && dateToTimelessDateString(minDate) <= ledgerLock) {
throw new GraphQLError('Cannot generate balance charge for locked period');
}
}
try {
const charge = await generateAndTagCharge(
injector,
defaultAdminBusinessId,
defaultTaxCategoryId,
description,
);
await Promise.all(
balanceRecords.map(async record => {
if (!record.debtorId && !record.creditorId) {
throw new GraphQLError(
'Balance record must include at least one counterparty (debtor or creditor)',
);
}
await injector
.get(MiscExpensesProvider)
.insertExpense({ ...record, chargeId: charge.id })
.catch(() => {
throw new GraphQLError('Error adding balance records');
});
}),
);
await generateLedgerRecordsForFinancialCharge(
charge,
{ insertLedgerRecordsIfNotExists: true },
context,
info,
);
return charge;
} catch (e) {
console.error(e);
throw new GraphQLError('Error generating balance charge');
}
},
},
FinancialCharge: {
__isTypeOf: (DbCharge, context) =>
getChargeType(DbCharge, context) === ChargeTypeEnum.Financial,
...commonChargeFields,
vat: () => null,
totalAmount: () => null,
property: () => false,
conversion: () => false,
salary: () => false,
isInvoicePaymentDifferentCurrency: () => false,
minEventDate: DbCharge => DbCharge.ledger_min_invoice_date,
minDebitDate: DbCharge => DbCharge.ledger_min_value_date,
// minDocumentsDate:
// validationData:
// metadata:
yearsOfRelevance: () => null,
},
};