UNPKG

@accounter/server

Version:
164 lines (143 loc) 5.05 kB
import { Injectable, Scope } from 'graphql-modules'; // eslint-disable-next-line no-restricted-imports import type { PoolClient } from 'pg'; import { sql } from '@pgtyped/runtime'; import { UUID_REGEX } from '../../../shared/constants.js'; import { makeUUID } from '../../../shared/helpers/deterministic-uuid.js'; import { TenantAwareDBClient } from '../../app-providers/tenant-db-client.js'; import type { IEnsureBusinessQuery, IEnsureCountryQuery, IEnsureFinancialEntityQuery, IEnsureTaxCategoryQuery, } from '../types.js'; export type FinancialEntityType = 'business' | 'tax_category' | 'tag'; const VALID_ENTITY_TYPES: readonly FinancialEntityType[] = ['business', 'tax_category', 'tag']; export interface EnsureFinancialEntityParams { id?: string; name: string; type: FinancialEntityType; ownerId?: string; } export interface EnsureBusinessOptions { ownerId?: string; country?: string; isDocumentsOptional?: boolean; hebrewName?: string; address?: string; city?: string; zipCode?: string; email?: string; website?: string; phoneNumber?: string; governmentId?: string; exemptDealer?: boolean; optionalVat?: boolean; isReceiptEnough?: boolean; } export interface EnsureTaxCategoryOptions { ownerId?: string; hashavshevetName?: string; taxExcluded?: boolean; } const ensureFinancialEntity = sql<IEnsureFinancialEntityQuery>` INSERT INTO accounter_schema.financial_entities (id, name, type, owner_id) VALUES ($id, $name, $type, $ownerId) ON CONFLICT (id) DO NOTHING; `; const ensureBusiness = sql<IEnsureBusinessQuery>` INSERT INTO accounter_schema.businesses ( id, hebrew_name, address, city, zip_code, email, website, phone_number, vat_number, exempt_dealer, optional_vat, country, can_settle_with_receipt, no_invoices_required, owner_id ) VALUES ( $id, $hebrewName, $address, $city, $zipCode, $email, $website, $phoneNumber, $governmentId, $exemptDealer, $optionalVat, $country, $isReceiptEnough, $isDocumentsOptional, $ownerId ) ON CONFLICT (id) DO NOTHING; `; const ensureTaxCategory = sql<IEnsureTaxCategoryQuery>` INSERT INTO accounter_schema.tax_categories (id, hashavshevet_name, tax_excluded, owner_id) VALUES ($id, $hashavshevetName, $taxExcluded, $ownerId) ON CONFLICT (id) DO NOTHING; `; const ensureCountry = sql<IEnsureCountryQuery>` INSERT INTO accounter_schema.countries (code, name) VALUES ($code, $name) ON CONFLICT (code) DO NOTHING; `; @Injectable({ scope: Scope.Operation, global: true }) export class EntityEnsureProvider { constructor(private db: TenantAwareDBClient) {} async ensureFinancialEntity( params: EnsureFinancialEntityParams, client?: PoolClient, ): Promise<{ id: string }> { const { name, type, ownerId, id: originId } = params; if (!name || name.trim() === '') { throw new Error('ensureFinancialEntity: name is required'); } if (!VALID_ENTITY_TYPES.includes(type)) { throw new Error(`ensureFinancialEntity: invalid type "${type}"`); } const compositeKey = ownerId ? `${name}:owner=${ownerId}` : name; const id = originId ?? makeUUID(type, compositeKey); await ensureFinancialEntity.run( { id, name, type, ownerId: ownerId ?? null }, client ?? this.db, ); return { id }; } async ensureBusinessForEntity( entityId: string, options?: EnsureBusinessOptions, client?: PoolClient, ): Promise<void> { if (!UUID_REGEX.test(entityId)) { throw new Error(`ensureBusinessForEntity: invalid entityId "${entityId}"`); } await ensureBusiness.run( { id: entityId, hebrewName: options?.hebrewName ?? null, address: options?.address ?? null, city: options?.city ?? null, zipCode: options?.zipCode ?? null, email: options?.email ?? null, website: options?.website ?? null, phoneNumber: options?.phoneNumber ?? null, governmentId: options?.governmentId ?? null, exemptDealer: options?.exemptDealer ?? false, optionalVat: options?.optionalVat ?? false, country: options?.country ?? 'ISR', isReceiptEnough: options?.isReceiptEnough ?? false, isDocumentsOptional: options?.isDocumentsOptional ?? false, ownerId: options?.ownerId ?? null, }, client ?? this.db, ); } async ensureTaxCategoryForEntity( entityId: string, options?: EnsureTaxCategoryOptions, client?: PoolClient, ): Promise<void> { if (!UUID_REGEX.test(entityId)) { throw new Error(`ensureTaxCategoryForEntity: invalid entityId "${entityId}"`); } await ensureTaxCategory.run( { id: entityId, hashavshevetName: options?.hashavshevetName ?? null, taxExcluded: options?.taxExcluded ?? false, ownerId: options?.ownerId ?? null, }, client ?? this.db, ); } async ensureCountry(code: string, name: string, client?: PoolClient): Promise<void> { await ensureCountry.run({ code, name }, client ?? this.db); } }