UNPKG

@accounter/server

Version:

The test suite is split into three Vitest projects for efficiency and isolation:

319 lines • 12.4 kB
import { __decorate, __metadata } from "tslib"; import DataLoader from 'dataloader'; import { Injectable, Scope } from 'graphql-modules'; import { sql } from '@pgtyped/runtime'; import { getCacheInstance } from '../../../shared/helpers/index.js'; import { DBProvider } from '../../app-providers/db.provider.js'; const getChargesByIds = sql ` SELECT * FROM accounter_schema.charges WHERE id IN $$chargeIds;`; const getChargesByTransactionIds = sql ` SELECT t.id AS transaction_id, c.* FROM accounter_schema.transactions t LEFT JOIN accounter_schema.charges c ON t.charge_id = c.id WHERE t.id IN $$transactionIds;`; const getChargesByMissingRequiredInfo = sql ` SELECT c.* FROM accounter_schema.charges c LEFT JOIN accounter_schema.charge_tags t ON t.charge_id = c.id WHERE c.user_description IS NULL OR t.tag_id IS NULL;`; const updateCharge = sql ` UPDATE accounter_schema.charges SET owner_id = COALESCE( $ownerId, owner_id ), user_description = COALESCE( $userDescription, user_description ), type = COALESCE( $type, type ), invoice_payment_currency_diff = COALESCE( $isInvoicePaymentDifferentCurrency, invoice_payment_currency_diff ), accountant_status = COALESCE( $accountantStatus, accountant_status ), tax_category_id = COALESCE( $taxCategoryId, tax_category_id ), optional_vat = COALESCE( $optionalVAT, optional_vat ), documents_optional_flag = COALESCE( $optionalDocuments, documents_optional_flag ), is_property = COALESCE( $isProperty, is_property ) WHERE id = $chargeId RETURNING *; `; const batchUpdateCharges = sql ` UPDATE accounter_schema.charges SET owner_id = COALESCE( $ownerId, owner_id ), user_description = COALESCE( $userDescription, user_description ), type = COALESCE( $type, type ), invoice_payment_currency_diff = COALESCE( $isInvoicePaymentDifferentCurrency, invoice_payment_currency_diff ), accountant_status = COALESCE( $accountantStatus, accountant_status ), tax_category_id = COALESCE( $taxCategoryId, tax_category_id ), optional_vat = COALESCE( $optionalVAT, optional_vat ), documents_optional_flag = COALESCE( $optionalDocuments, documents_optional_flag ), is_property = COALESCE( $isProperty, is_property ) WHERE id in $$chargeIds RETURNING *; `; const updateAccountantApproval = sql ` UPDATE accounter_schema.charges SET accountant_status = $accountantStatus WHERE id = $chargeId RETURNING *; `; const generateCharge = sql ` INSERT INTO accounter_schema.charges (owner_id, type, accountant_status, user_description, tax_category_id, optional_vat, documents_optional_flag, is_property) VALUES ($ownerId, $type, $accountantStatus, $userDescription, $taxCategoryId, $optionalVAT, $optionalDocuments, $isProperty) RETURNING *; `; const getChargesByFilters = sql ` SELECT ec.*, ABS(ec.event_amount) as abs_event_amount FROM accounter_schema.charges c LEFT JOIN accounter_schema.extended_charges ec ON c.id = ec.id WHERE ($isIDs = 0 OR c.id IN $$IDs) AND ($isOwnerIds = 0 OR c.owner_id IN $$ownerIds) AND ($isBusinessIds = 0 OR ec.business_array && $businessIds) AND ($fromDate ::TEXT IS NULL OR COALESCE(ec.documents_min_date, ec.transactions_min_event_date)::TEXT::DATE >= date_trunc('day', $fromDate ::DATE)) AND ($fromAnyDate ::TEXT IS NULL OR GREATEST(ec.documents_max_date, ec.transactions_max_event_date, ec.transactions_max_debit_date, ec.ledger_max_invoice_date, ec.ledger_max_value_date)::TEXT::DATE >= date_trunc('day', $fromAnyDate ::DATE)) AND ($toDate ::TEXT IS NULL OR COALESCE(ec.documents_max_date, ec.transactions_max_event_date)::TEXT::DATE <= date_trunc('day', $toDate ::DATE)) AND ($toAnyDate ::TEXT IS NULL OR LEAST(ec.documents_min_date, ec.transactions_min_event_date, ec.transactions_min_debit_date, ec.ledger_min_invoice_date, ec.ledger_min_value_date)::TEXT::DATE <= date_trunc('day', $toAnyDate ::DATE)) AND ($chargeType = 'ALL' OR ($chargeType = 'INCOME' AND ec.transactions_event_amount > 0) OR ($chargeType = 'EXPENSE' AND ec.transactions_event_amount <= 0)) AND ($withoutInvoice = FALSE OR COALESCE(ec.invoices_count, 0) = 0) AND ($withoutReceipt = FALSE OR (COALESCE(ec.receipts_count, 0) = 0 AND (ec.no_invoices_required IS FALSE))) AND ($withoutDocuments = FALSE OR COALESCE(ec.documents_count, 0) = 0) AND ($withoutTransactions = FALSE OR COALESCE(ec.transactions_count, 0) = 0) AND ($withOpenDocuments = FALSE OR ec.open_docs_flag IS TRUE) AND ($withoutLedger = FALSE OR COALESCE(ec.ledger_count, 0) = 0) AND ($isAccountantStatuses = 0 OR ec.accountant_status = ANY ($accountantStatuses::accounter_schema.accountant_status[])) AND ($isTags = 0 OR ec.tags && $tags) ORDER BY CASE WHEN $asc = true AND $sortColumn = 'event_date' THEN (COALESCE(ec.transactions_min_debit_date, ec.transactions_min_event_date, ec.documents_min_date, ec.ledger_min_value_date, ec.ledger_min_invoice_date), COALESCE(ec.documents_min_date, ec.transactions_min_event_date), ec.id) END ASC, CASE WHEN $asc = false AND $sortColumn = 'event_date' THEN (COALESCE(ec.transactions_min_debit_date, ec.transactions_min_event_date, ec.documents_min_date, ec.ledger_min_value_date, ec.ledger_min_invoice_date), COALESCE(ec.documents_min_date, ec.transactions_min_event_date), ec.id) END DESC, CASE WHEN $asc = true AND $sortColumn = 'event_amount' THEN (ec.event_amount, ec.id) END ASC, CASE WHEN $asc = false AND $sortColumn = 'event_amount' THEN (ec.event_amount, ec.id) END DESC, CASE WHEN $asc = true AND $sortColumn = 'abs_event_amount' THEN ABS(cast(ec.event_amount as DECIMAL)) END ASC, CASE WHEN $asc = false AND $sortColumn = 'abs_event_amount' THEN ABS(cast(ec.event_amount as DECIMAL)) END DESC, ID; `; const getSimilarCharges = sql ` SELECT * FROM accounter_schema.extended_charges WHERE (CASE WHEN $withMissingTags IS TRUE THEN tags IS NULL ELSE TRUE END) AND (CASE WHEN $withMissingDescription IS TRUE THEN user_description IS NULL ELSE TRUE END) AND (CASE WHEN $tagsDifferentThan::UUID[] IS NOT NULL THEN NOT((tags @> $tagsDifferentThan) AND (tags <@ $tagsDifferentThan)) ELSE TRUE END) AND (CASE WHEN $descriptionDifferentThan::TEXT IS NOT NULL THEN NOT(user_description = $descriptionDifferentThan) ELSE TRUE END) AND ( (business_id IS NOT NULL AND business_id = $businessId) OR (business_array IS NOT NULL AND business_array @> $businessArray AND business_array <@ $businessArray) ) AND owner_id = $ownerId ORDER BY (COALESCE(documents_min_date, transactions_min_debit_date, transactions_min_event_date, ledger_min_value_date, ledger_min_invoice_date), COALESCE(transactions_min_event_date, documents_min_date), id) DESC;`; const deleteChargesByIds = sql ` DELETE FROM accounter_schema.charges WHERE id IN $$chargeIds;`; let ChargesProvider = class ChargesProvider { dbProvider; cache = getCacheInstance({ stdTTL: 60 * 60, // 1 hours }); constructor(dbProvider) { this.dbProvider = dbProvider; } async batchChargesByIds(ids) { const charges = await getChargesByIds.run({ chargeIds: ids, }, this.dbProvider); return ids.map(id => charges.find(charge => charge.id === id)); } getChargeByIdLoader = new DataLoader((keys) => this.batchChargesByIds(keys), { cacheKeyFn: id => `charge-${id}`, cacheMap: this.cache, }); async batchChargesByTransactionIds(transactionIds) { const charges = await getChargesByTransactionIds.run({ transactionIds, }, this.dbProvider); charges.map(c => this.getChargeByIdLoader.prime(c.id, c)); return transactionIds.map(id => charges.find(charge => charge.transaction_id === id)); } getChargeByTransactionIdLoader = new DataLoader((transactionIds) => this.batchChargesByTransactionIds(transactionIds), { cache: false }); async getChargesByMissingRequiredInfo() { return getChargesByMissingRequiredInfo.run(undefined, this.dbProvider).then(charges => charges.map(c => { this.getChargeByIdLoader.prime(c.id, c); return c; })); } updateCharge(params) { return updateCharge.run(params, this.dbProvider).then(([newCharge]) => { if (newCharge) { this.invalidateCharge(newCharge.id); this.getChargeByIdLoader.prime(newCharge.id, newCharge); } return newCharge; }); } batchUpdateCharges(params) { return batchUpdateCharges.run(params, this.dbProvider).then(charges => { charges.map(charge => this.getChargeByIdLoader.prime(charge.id, charge)); return charges; }); } updateAccountantApproval(params) { return updateAccountantApproval.run(params, this.dbProvider).then(([newCharge]) => { if (newCharge) { this.getChargeByIdLoader.prime(newCharge.id, newCharge); } return newCharge; }); } generateCharge(params) { const fullParams = { isProperty: false, userDescription: null, optionalVAT: false, optionalDocuments: false, accountantStatus: 'UNAPPROVED', ...params, }; return generateCharge.run(fullParams, this.dbProvider).then(([newCharge]) => { if (newCharge) { this.getChargeByIdLoader.prime(newCharge.id, newCharge); } return newCharge; }); } getChargesByFilters(params) { const isOwnerIds = !!params?.ownerIds?.filter(Boolean).length; const isBusinessIds = !!params?.businessIds?.filter(Boolean).length; const isIDs = !!params?.IDs?.length; const isTags = !!params?.tags?.length; const isAccountantStatuses = !!params?.accountantStatuses?.length; const defaults = { asc: false, sortColumn: 'event_date', }; const fullParams = { ...defaults, isOwnerIds: isOwnerIds ? 1 : 0, isBusinessIds: isBusinessIds ? 1 : 0, isIDs: isIDs ? 1 : 0, isTags: isTags ? 1 : 0, isAccountantStatuses: isAccountantStatuses ? 1 : 0, ...params, fromDate: params.fromDate ?? null, toDate: params.toDate ?? null, ownerIds: isOwnerIds ? params.ownerIds : [null], businessIds: isBusinessIds ? params.businessIds : null, IDs: isIDs ? params.IDs : [null], tags: isTags ? params.tags : null, chargeType: params.chargeType ?? 'ALL', withoutInvoice: params.withoutInvoice ?? false, withoutReceipt: params.withoutReceipt ?? false, withoutDocuments: params.withoutDocuments ?? false, withOpenDocuments: params.withOpenDocuments ?? false, withoutTransactions: params.withoutTransactions ?? false, withoutLedger: params.withoutLedger ?? false, accountantStatuses: isAccountantStatuses ? params.accountantStatuses : null, }; return getChargesByFilters.run(fullParams, this.dbProvider); } async getSimilarCharges(params) { try { return getSimilarCharges.run(params, this.dbProvider); } catch (error) { const message = 'Failed to fetch similar charges'; console.error(message, error); throw new Error(message); } } deleteChargesByIds(params) { return deleteChargesByIds.run(params, this.dbProvider); } async invalidateCharge(chargeId) { this.getChargeByIdLoader.clear(chargeId); } clearCache() { this.cache.clear(); } }; ChargesProvider = __decorate([ Injectable({ scope: Scope.Singleton, global: true, }), __metadata("design:paramtypes", [DBProvider]) ], ChargesProvider); export { ChargesProvider }; //# sourceMappingURL=charges.provider.js.map