UNPKG

@accounter/server

Version:

220 lines • 8.37 kB
import { __decorate, __metadata } from "tslib"; import DataLoader from 'dataloader'; import { Injectable, Scope } from 'graphql-modules'; import { DBProvider } from '../../app-providers/db.provider.js'; import { sql } from '@pgtyped/runtime'; import { getCacheInstance } from '../../../shared/helpers/index.js'; import { BusinessesProvider } from './businesses.provider.js'; import { TaxCategoriesProvider } from './tax-categories.provider.js'; const getFinancialEntitiesByIds = sql ` SELECT * FROM accounter_schema.financial_entities WHERE id IN $$ids;`; const getAllFinancialEntities = sql ` SELECT * FROM accounter_schema.financial_entities;`; const updateFinancialEntity = sql ` UPDATE accounter_schema.financial_entities SET name = COALESCE( $name, name ), owner_id = COALESCE( $ownerId, owner_id ), sort_code = COALESCE( $sortCode, sort_code ), type = COALESCE( $type, type ), irs_code = COALESCE( $irsCode, irs_code ) WHERE id = $financialEntityId RETURNING *; `; const insertFinancialEntities = sql ` INSERT INTO accounter_schema.financial_entities (type, owner_id, name, sort_code, irs_code) VALUES $$financialEntities(type, ownerId, name, sortCode, irsCode) RETURNING *;`; const deleteFinancialEntity = sql ` DELETE FROM accounter_schema.financial_entities WHERE id = $financialEntityId RETURNING id; `; const replaceFinancialEntities = sql ` WITH ledger_debit1 AS ( UPDATE accounter_schema.ledger_records SET debit_entity1 = $targetEntityId WHERE debit_entity1 = $entityIdToReplace RETURNING id ), ledger_debit2 AS ( UPDATE accounter_schema.ledger_records SET debit_entity2 = $targetEntityId WHERE debit_entity2 = $entityIdToReplace RETURNING id ), ledger_credit1 AS ( UPDATE accounter_schema.ledger_records SET credit_entity1 = $targetEntityId WHERE credit_entity1 = $entityIdToReplace RETURNING id ), ledger_credit2 AS ( UPDATE accounter_schema.ledger_records SET credit_entity2 = $targetEntityId WHERE credit_entity2 = $entityIdToReplace RETURNING id ), misc_expenses_creditor AS ( UPDATE accounter_schema.misc_expenses SET creditor_id = $targetEntityId WHERE creditor_id = $entityIdToReplace RETURNING id ) UPDATE accounter_schema.misc_expenses SET debtor_id = $targetEntityId WHERE debtor_id = $entityIdToReplace RETURNING id; `; let FinancialEntitiesProvider = class FinancialEntitiesProvider { dbProvider; businessesProvider; taxCategoriesProvider; cache = getCacheInstance({ stdTTL: 60 * 5, }); constructor(dbProvider, businessesProvider, taxCategoriesProvider) { this.dbProvider = dbProvider; this.businessesProvider = businessesProvider; this.taxCategoriesProvider = taxCategoriesProvider; } async batchFinancialEntitiesByIds(ids) { const financialEntities = await getFinancialEntitiesByIds.run({ ids, }, this.dbProvider); return ids.map(id => financialEntities.find(fe => fe.id === id)); } getFinancialEntityByIdLoader = new DataLoader((keys) => this.batchFinancialEntitiesByIds(keys), { cacheKeyFn: key => `financial-entity-id-${key}`, cacheMap: this.cache, }); getAllFinancialEntities() { const data = this.cache.get('all-financial-entities'); if (data) { return data; } return getAllFinancialEntities.run(undefined, this.dbProvider).then(data => { this.cache.set('all-financial-entities', data); data.map(fe => { this.cache.set(`financial-entity-id-${fe.id}`, fe); }); return data; }); } updateFinancialEntity(params) { if (params.financialEntityId) { this.invalidateFinancialEntityById(params.financialEntityId); } return updateFinancialEntity.run(params, this.dbProvider); } insertFinancialEntity(params) { this.cache.delete('all-financial-entities'); return insertFinancialEntities.run({ financialEntities: [params] }, this.dbProvider); } async batchInsertFinancialEntities(newFinancialEntities) { const financialEntities = await insertFinancialEntities.run({ financialEntities: newFinancialEntities, }, this.dbProvider); return newFinancialEntities.map(fe => financialEntities.find(f => f.name === fe.name) ?? null); } insertFinancialEntitiesLoader = new DataLoader((financialEntities) => this.batchInsertFinancialEntities(financialEntities), { cache: false, }); async deleteFinancialEntityById(financialEntityId) { const entity = await this.getFinancialEntityByIdLoader.load(financialEntityId); if (!entity) { throw new Error(`Financial entity with id ${financialEntityId} not found`); } if (entity.id === entity.owner_id) { throw new Error('Cannot delete owner entity'); } this.invalidateFinancialEntityById(financialEntityId); // remove business const deleteBusiness = entity.type === 'business' ? this.businessesProvider.deleteBusinessById(financialEntityId) : Promise.resolve(); // remove tax category const deleteTaxCategory = entity.type === 'tax_category' ? this.taxCategoriesProvider.deleteTaxCategoryById(financialEntityId) : Promise.resolve(); await Promise.all([deleteBusiness, deleteTaxCategory]); // TODO: should remove ledger, misc expenses? // delete entity deleteFinancialEntity.run({ financialEntityId }, this.dbProvider); } async replaceFinancialEntity(targetEntityId, entityIdToReplace, deleteEntity = false) { const [entityToReplace, entity] = await Promise.all([ this.getFinancialEntityByIdLoader.load(entityIdToReplace), this.getFinancialEntityByIdLoader.load(targetEntityId), ]); if (!entityToReplace) { throw new Error(`Financial entity with id ${entityIdToReplace} not found`); } if (!entity) { throw new Error(`Financial entity with id ${targetEntityId} not found`); } if (entityToReplace.type !== entity.type) { throw new Error('Cannot replace entities of different types'); } if (entity.id === entity.owner_id) { throw new Error('Cannot replace owner entity'); } this.invalidateFinancialEntityById(entityIdToReplace); this.invalidateFinancialEntityById(targetEntityId); // convert ledger, misc expenses await replaceFinancialEntities.run({ targetEntityId, entityIdToReplace }, this.dbProvider); // convert business const businessReplacementPromise = entity.type === 'business' ? this.businessesProvider.replaceBusiness(targetEntityId, entityIdToReplace, deleteEntity) : Promise.resolve(); // convert tax category const taxCategoryReplacementPromise = entity.type === 'tax_category' ? this.taxCategoriesProvider.replaceTaxCategory(targetEntityId, entityIdToReplace, deleteEntity) : Promise.resolve(); await Promise.all([businessReplacementPromise, taxCategoryReplacementPromise]); if (deleteEntity) { await this.deleteFinancialEntityById(entityIdToReplace); } } invalidateFinancialEntityById(financialEntityId) { this.businessesProvider.invalidateBusinessById(financialEntityId); this.taxCategoriesProvider.invalidateTaxCategoryById(financialEntityId); this.cache.delete('all-financial-entities'); this.cache.delete(`financial-entity-id-${financialEntityId}`); } clearCache() { this.taxCategoriesProvider.clearCache(); this.businessesProvider.clearCache(); this.cache.clear(); } }; FinancialEntitiesProvider = __decorate([ Injectable({ scope: Scope.Operation, global: true, }), __metadata("design:paramtypes", [DBProvider, BusinessesProvider, TaxCategoriesProvider]) ], FinancialEntitiesProvider); export { FinancialEntitiesProvider }; //# sourceMappingURL=financial-entities.provider.js.map