UNPKG

@accounter/server

Version:
148 lines (132 loc) 4.82 kB
import DataLoader from 'dataloader'; import { Injectable, Scope } from 'graphql-modules'; import { sql } from '@pgtyped/runtime'; import { TimelessDateString } from '../../../shared/types/index.js'; import { TenantAwareDBClient } from '../../app-providers/tenant-db-client.js'; import { AuthContextProvider } from '../../auth/providers/auth-context.provider.js'; import type { IDeleteCorporateTaxParams, IDeleteCorporateTaxQuery, IGetCorporateTaxesByCorporateIdsQuery, IGetCorporateTaxesByCorporateIdsResult, IInsertCorporateTaxParams, IInsertCorporateTaxQuery, IUpdateCorporateTaxParams, IUpdateCorporateTaxQuery, } from '../types.js'; const getCorporateTaxesByCorporateIds = sql<IGetCorporateTaxesByCorporateIdsQuery>` SELECT * FROM accounter_schema.corporate_tax_variables WHERE corporate_id IN $$corporateIds ORDER BY date DESC;`; const updateCorporateTax = sql<IUpdateCorporateTaxQuery>` UPDATE accounter_schema.corporate_tax_variables SET date = COALESCE( $date, date ), tax_rate = COALESCE( $taxRate, tax_rate ), original_tax_rate = COALESCE( $originalTaxRate, original_tax_rate ) WHERE corporate_id = $corporateId AND date = $originalDate RETURNING *;`; const insertCorporateTax = sql<IInsertCorporateTaxQuery>` INSERT INTO accounter_schema.corporate_tax_variables (corporate_id, date, tax_rate, original_tax_rate, owner_id) VALUES ($corporateId, $date, $taxRate, $originalTaxRate, $ownerId) RETURNING *`; const deleteCorporateTax = sql<IDeleteCorporateTaxQuery>` DELETE FROM accounter_schema.corporate_tax_variables WHERE corporate_id = $corporateId AND date = $date RETURNING *`; @Injectable({ scope: Scope.Operation, global: true, }) export class CorporateTaxesProvider { private businessIdCache: string | null = null; constructor( private db: TenantAwareDBClient, private authContextProvider: AuthContextProvider, ) {} private async getBusinessId(): Promise<string> { if (this.businessIdCache !== null) { return this.businessIdCache; } const authContext = await this.authContextProvider.getAuthContext(); this.businessIdCache = authContext?.tenant.businessId ?? null; if (!this.businessIdCache) { throw new Error('Missing businessId in AuthContext'); } return this.businessIdCache; } private allCorporateTaxesCache = new Map< string, Promise<IGetCorporateTaxesByCorporateIdsResult[]> >(); public getAllCorporateTaxes(corporateId: string) { if (this.allCorporateTaxesCache.has(corporateId)) { return this.allCorporateTaxesCache.get(corporateId)!; } this.allCorporateTaxesCache.set( corporateId, getCorporateTaxesByCorporateIds.run({ corporateIds: [corporateId] }, this.db), ); return this.allCorporateTaxesCache.get(corporateId)!; } private async batchCorporateTaxesByDates( taxRates: readonly { date: TimelessDateString; corporateId: string }[], ) { const corporateIds = [...new Set(taxRates.map(t => t.corporateId))]; const rates = (await Promise.all(corporateIds.map(id => this.getAllCorporateTaxes(id)))).flat(); return taxRates.map(({ date, corporateId }) => { const time = new Date(date).getTime(); return rates .filter(rate => rate.corporate_id === corporateId) .sort((a, b) => b.date.getTime() - a.date.getTime()) .find(rate => rate.date.getTime() <= time); }); } public getCorporateTaxesByDateLoader = new DataLoader( async (dates: readonly TimelessDateString[]) => { const businessId = await this.getBusinessId(); return this.batchCorporateTaxesByDates( dates.map(date => ({ date, corporateId: businessId })), ); }, ); private async batchCorporateTaxesByCorporateIds(corporateIds: readonly string[]) { const taxes = await getCorporateTaxesByCorporateIds.run({ corporateIds }, this.db); return corporateIds.map(id => taxes.filter(expense => expense.corporate_id === id)); } public getCorporateTaxesByCorporateIdLoader = new DataLoader((corporateIds: readonly string[]) => this.batchCorporateTaxesByCorporateIds(corporateIds), ); public updateCorporateTax(params: IUpdateCorporateTaxParams) { this.allCorporateTaxesCache = new Map(); return updateCorporateTax.run(params, this.db); } public async insertCorporateTax(params: IInsertCorporateTaxParams) { this.allCorporateTaxesCache = new Map(); const ownerId = params.ownerId ?? (await this.getBusinessId()); return insertCorporateTax.run( { ...params, ownerId, }, this.db, ); } public deleteCorporateTax(params: IDeleteCorporateTaxParams) { this.allCorporateTaxesCache = new Map(); return deleteCorporateTax.run(params, this.db); } }