refactor: tenant models to nestjs

This commit is contained in:
Ahmed Bouhuolia
2025-03-30 21:22:54 +02:00
parent 682be715ae
commit caff6ce47c
13 changed files with 92 additions and 70 deletions

View File

@@ -11,6 +11,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
import { events } from '@/common/events/events';
import { BankRule } from '../models/BankRule';
import { CreateBankRuleDto } from '../dtos/BankRule.dto';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
@Injectable()
export class CreateBankRuleService {
@@ -18,7 +19,8 @@ export class CreateBankRuleService {
private readonly uow: UnitOfWork,
private readonly eventPublisher: EventEmitter2,
@Inject(BankRule.name) private readonly bankRuleModel: typeof BankRule,
@Inject(BankRule.name)
private readonly bankRuleModel: TenantModelProxy<typeof BankRule>,
) {}
/**
@@ -48,9 +50,11 @@ export class CreateBankRuleService {
trx,
} as IBankRuleEventCreatingPayload);
const bankRule = await this.bankRuleModel.query(trx).upsertGraphAndFetch({
...transformDTO,
});
const bankRule = await this.bankRuleModel()
.query(trx)
.upsertGraphAndFetch({
...transformDTO,
});
// Triggers `onBankRuleCreated` event.
await this.eventPublisher.emitAsync(events.bankRules.onCreated, {
createRuleDTO,

View File

@@ -5,6 +5,7 @@ import { RevertRecognizedTransactionsCriteria } from '../_types';
import { RecognizedBankTransaction } from '../models/RecognizedBankTransaction';
import { UncategorizedBankTransaction } from '@/modules/BankingTransactions/models/UncategorizedBankTransaction';
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
@Injectable()
export class RevertRecognizedTransactionsService {
@@ -12,10 +13,14 @@ export class RevertRecognizedTransactionsService {
private readonly uow: UnitOfWork,
@Inject(RecognizedBankTransaction.name)
private readonly recognizedBankTransactionModel: typeof RecognizedBankTransaction,
private readonly recognizedBankTransactionModel: TenantModelProxy<
typeof RecognizedBankTransaction
>,
@Inject(UncategorizedBankTransaction.name)
private readonly uncategorizedBankTransactionModel: typeof UncategorizedBankTransaction,
private readonly uncategorizedBankTransactionModel: TenantModelProxy<
typeof UncategorizedBankTransaction
>,
) {}
/**
@@ -36,32 +41,34 @@ export class RevertRecognizedTransactionsService {
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
// Retrieves all the recognized transactions of the banbk rule.
const uncategorizedTransactions =
await this.uncategorizedBankTransactionModel.query(trx).onBuild((q) => {
q.withGraphJoined('recognizedTransaction');
q.whereNotNull('recognizedTransaction.id');
await this.uncategorizedBankTransactionModel()
.query(trx)
.onBuild((q) => {
q.withGraphJoined('recognizedTransaction');
q.whereNotNull('recognizedTransaction.id');
if (rulesIds.length > 0) {
q.whereIn('recognizedTransaction.bankRuleId', rulesIds);
}
if (transactionsCriteria?.accountId) {
q.where('accountId', transactionsCriteria.accountId);
}
if (transactionsCriteria?.batch) {
q.where('batch', transactionsCriteria.batch);
}
});
if (rulesIds.length > 0) {
q.whereIn('recognizedTransaction.bankRuleId', rulesIds);
}
if (transactionsCriteria?.accountId) {
q.where('accountId', transactionsCriteria.accountId);
}
if (transactionsCriteria?.batch) {
q.where('batch', transactionsCriteria.batch);
}
});
const uncategorizedTransactionIds = uncategorizedTransactions.map(
(r) => r.id,
);
// Unlink the recongized transactions out of uncategorized transactions.
await this.uncategorizedBankTransactionModel
// Unlink the recognized transactions out of un-categorized transactions.
await this.uncategorizedBankTransactionModel()
.query(trx)
.whereIn('id', uncategorizedTransactionIds)
.patch({
recognizedTransactionId: null,
});
// Delete the recognized bank transactions that assocaited to bank rule.
await this.recognizedBankTransactionModel
// Delete the recognized bank transactions that associated to bank rule.
await this.recognizedBankTransactionModel()
.query(trx)
.whereIn('uncategorizedTransactionId', uncategorizedTransactionIds)
.delete();

View File

@@ -21,7 +21,9 @@ export class FeaturesSettingsDriver {
* @returns {Promise<void>}
*/
async turnOn(feature: string) {
this.settings().set({ group: 'features', key: feature, value: true });
const settingsStore = await this.settings();
settingsStore.set({ group: 'features', key: feature, value: true });
}
/**
@@ -30,24 +32,24 @@ export class FeaturesSettingsDriver {
* @returns {Promise<void>}
*/
async turnOff(feature: string) {
this.settings().set({ group: 'features', key: feature, value: false });
const settingsStore = await this.settings();
settingsStore.set({ group: 'features', key: feature, value: false });
}
/**
* Detarmines the given feature name is accessible.
* Determines the given feature name is accessible.
* @param {string} feature - The feature name.
* @returns {Promise<boolean|null|undefined>}
*/
async accessible(feature: string) {
const settingsStore = await this.settings();
const defaultValue = this.configure.getFeatureConfigure(
feature,
'defaultValue',
);
const settingValue = this.settings().get(
{ group: 'features', key: feature },
defaultValue,
);
return settingValue;
return settingsStore.get({ group: 'features', key: feature }, defaultValue);
}
/**
@@ -55,11 +57,13 @@ export class FeaturesSettingsDriver {
* @returns {Promise<IFeatureAllItem>}
*/
async all(): Promise<IFeatureAllItem[]> {
const mappedOpers = this.featuresConfigure.getConfigure().map(async (featureConfigure) => {
const { name, defaultValue } = featureConfigure;
const isAccessible = await this.accessible(featureConfigure.name);
return { name, isAccessible, defaultAccessible: defaultValue };
});
const mappedOpers = this.featuresConfigure
.getConfigure()
.map(async (featureConfigure) => {
const { name, defaultValue } = featureConfigure;
const isAccessible = await this.accessible(featureConfigure.name);
return { name, isAccessible, defaultAccessible: defaultValue };
});
return Promise.all(mappedOpers);
}
}

View File

@@ -1,6 +1,6 @@
// @ts-nocheck
import { Knex } from 'knex';
import { Inject } from '@nestjs/common';
import { Inject, Injectable } from '@nestjs/common';
import { EventEmitter2 } from '@nestjs/event-emitter';
import {
IInventoryTransactionsDeletedPayload,
@@ -14,6 +14,7 @@ import { transformItemEntriesToInventory } from '../utils';
import { IItemEntryTransactionType } from '../../TransactionItemEntry/ItemEntry.types';
import { ItemEntry } from '../../TransactionItemEntry/models/ItemEntry';
@Injectable()
export class InventoryTransactionsService {
/**
* @param {EventEmitter2} eventEmitter - Event emitter.
@@ -143,7 +144,7 @@ export class InventoryTransactionsService {
trx?: Knex.Transaction,
): Promise<{ oldInventoryTransactions: InventoryTransaction[] }> {
// Retrieve the inventory transactions of the given sale invoice.
const oldInventoryTransactions = await this.inventoryTransactionModel
const oldInventoryTransactions = await this.inventoryTransactionModel()
.query(trx)
.where({ transactionId, transactionType });

View File

@@ -5,6 +5,7 @@ import { TenancyContext } from '../Tenancy/TenancyContext.service';
import { Customer } from '../Customers/models/Customer';
import { CommonMailOptions } from './MailNotification.types';
import { formatMessage } from '@/utils/format-message';
import { TenantModelProxy } from '../System/models/TenantBaseModel';
@Injectable()
export class ContactMailNotification {
@@ -13,7 +14,7 @@ export class ContactMailNotification {
private readonly tenantContext: TenancyContext,
@Inject(Customer.name)
private readonly customerModel: typeof Customer,
private readonly customerModel: TenantModelProxy<typeof Customer>,
) {}
/**
@@ -26,7 +27,7 @@ export class ContactMailNotification {
): Promise<
Pick<CommonMailOptions, 'to' | 'from' | 'toOptions' | 'fromOptions'>
> {
const customer = await this.customerModel
const customer = await this.customerModel()
.query()
.findById(customerId)
.throwIfNotFound();

View File

@@ -8,6 +8,7 @@ import { Injectable } from '@nestjs/common';
import { Inject } from '@nestjs/common';
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
import { Account } from '@/modules/Accounts/models/Account.model';
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
@Injectable()
export class PaymentReceivedGLEntries {
@@ -17,7 +18,9 @@ export class PaymentReceivedGLEntries {
private readonly tenancyContext: TenancyContext,
@Inject(PaymentReceived.name)
private readonly paymentReceivedModel: typeof PaymentReceived,
private readonly paymentReceivedModel: TenantModelProxy<
typeof PaymentReceived
>,
) {}
/**
@@ -28,13 +31,13 @@ export class PaymentReceivedGLEntries {
*/
public writePaymentGLEntries = async (
paymentReceiveId: number,
trx?: Knex.Transaction
trx?: Knex.Transaction,
): Promise<void> => {
// Retrieves the given tenant metadata.
const tenantMeta = await this.tenancyContext.getTenantMetadata();
// Retrieves the payment receive with associated entries.
const paymentReceive = await this.paymentReceivedModel
const paymentReceive = await this.paymentReceivedModel()
.query(trx)
.findById(paymentReceiveId)
.withGraphFetched('entries.invoice');
@@ -55,12 +58,12 @@ export class PaymentReceivedGLEntries {
*/
public revertPaymentGLEntries = async (
paymentReceiveId: number,
trx?: Knex.Transaction
trx?: Knex.Transaction,
) => {
await this.ledgerStorage.deleteByReference(
paymentReceiveId,
'PaymentReceive',
trx
trx,
);
};
@@ -71,7 +74,7 @@ export class PaymentReceivedGLEntries {
*/
public rewritePaymentGLEntries = async (
paymentReceiveId: number,
trx?: Knex.Transaction
trx?: Knex.Transaction,
) => {
// Reverts the payment GL entries.
await this.revertPaymentGLEntries(paymentReceiveId, trx);
@@ -94,12 +97,12 @@ export class PaymentReceivedGLEntries {
// Retrieve the A/R account of the given currency.
const receivableAccount =
await this.accountRepository.findOrCreateAccountReceivable(
paymentReceive.currencyCode
paymentReceive.currencyCode,
);
// Exchange gain/loss account.
const exGainLossAccount = await this.accountRepository.findBySlug(
'exchange-grain-loss'
) as Account;
const exGainLossAccount = (await this.accountRepository.findBySlug(
'exchange-grain-loss',
)) as Account;
const paymentReceivedGL = new PaymentReceivedGL(paymentReceive)
.setARAccountId(receivableAccount.id)
@@ -108,5 +111,4 @@ export class PaymentReceivedGLEntries {
return paymentReceivedGL.getLedger();
};
}

View File

@@ -1,8 +1,6 @@
// import { getUploadedObjectUri } from '@/services/Attachments/utils';
import { BaseModel } from '@/models/Model';
// import TenantModel from 'models/TenantModel';
import { TenantBaseModel } from '@/modules/System/models/TenantBaseModel';
export class PdfTemplateModel extends BaseModel {
export class PdfTemplateModel extends TenantBaseModel {
public resource!: string;
public templateName!: string;
public predefined!: boolean;

View File

@@ -151,7 +151,7 @@ export class SaleInvoicesController {
return this.saleInvoiceApplication.getSaleInvoiceState();
}
@Post(':id/deliver')
@Put(':id/deliver')
@ApiOperation({ summary: 'Deliver the given sale invoice.' })
@ApiResponse({
status: 200,

View File

@@ -2,6 +2,7 @@ import { ItemEntryDto } from '@/modules/TransactionItemEntry/dto/ItemEntry.dto';
import { ApiProperty } from '@nestjs/swagger';
import { Type } from 'class-transformer';
import {
ArrayMinSize,
IsArray,
IsBoolean,
IsDate,
@@ -12,7 +13,6 @@ import {
IsOptional,
IsString,
Min,
MinLength,
ValidateNested,
} from 'class-validator';
@@ -130,7 +130,7 @@ class CommandSaleInvoiceDto {
@IsArray()
@ValidateNested({ each: true })
@Type(() => ItemEntryDto)
@MinLength(1)
@ArrayMinSize(1)
@ApiProperty({
description: 'Invoice line items',
type: [ItemEntryDto],

View File

@@ -16,7 +16,7 @@ export class SaveSettingsService {
*/
public async saveSettings(settingsDTO: ISettingsDTO) {
const settingsStore = await this.settingsStore();
const notDefinedOptions = this.validateNotDefinedSettings(
const notDefinedOptions = await this.validateNotDefinedSettings(
settingsDTO.options,
);
const errorReasons: { type: string; code: number; keys: any[] }[] = [];
@@ -41,11 +41,12 @@ export class SaveSettingsService {
* @param {Array} options
* @return {Boolean}
*/
private validateNotDefinedSettings(options) {
private async validateNotDefinedSettings(options) {
const notDefined = [];
const settingStore = await this.settingsStore();
options.forEach((option) => {
const setting = this.settingsStore().config.getMetaConfig(
const setting = settingStore.config.getMetaConfig(
option.key,
option.group,
);

View File

@@ -19,9 +19,13 @@ import { SaleInvoiceTaxRateValidateSubscriber } from './subscribers/SaleInvoiceT
import { SyncItemTaxRateOnEditTaxSubscriber } from './subscribers/SyncItemTaxRateOnEditTaxSubscriber';
import { WriteTaxTransactionsItemEntries } from './WriteTaxTransactionsItemEntries';
import { SyncItemTaxRateOnEditTaxRate } from './SyncItemTaxRateOnEditTaxRate';
import { RegisterTenancyModel } from '../Tenancy/TenancyModels/Tenancy.module';
import { TaxRateTransaction } from './models/TaxRateTransaction.model';
const models = [RegisterTenancyModel(TaxRateTransaction)];
@Module({
imports: [],
imports: [...models],
controllers: [TaxRatesController],
providers: [
CreateTaxRate,
@@ -42,8 +46,8 @@ import { SyncItemTaxRateOnEditTaxRate } from './SyncItemTaxRateOnEditTaxRate';
SaleInvoiceTaxRateValidateSubscriber,
SyncItemTaxRateOnEditTaxSubscriber,
WriteTaxTransactionsItemEntries,
SyncItemTaxRateOnEditTaxRate
SyncItemTaxRateOnEditTaxRate,
],
exports: [ItemEntriesTaxTransactions],
exports: [ItemEntriesTaxTransactions, ...models],
})
export class TaxRatesModule {}

View File

@@ -1,19 +1,18 @@
import { sumBy, chain, keyBy } from 'lodash';
import { Knex } from 'knex';
import { SaleInvoice } from '../SaleInvoices/models/SaleInvoice';
import { ModelObject } from 'objection';
import { TenantModelProxy } from '../System/models/TenantBaseModel';
import { TaxRateModel } from './models/TaxRate.model';
import { Inject, Injectable } from '@nestjs/common';
import { ModelObject } from 'objection';
import { ItemEntry } from '../TransactionItemEntry/models/ItemEntry';
import { TaxRateTransaction } from './models/TaxRateTransaction.model';
@Injectable()
export class WriteTaxTransactionsItemEntries {
constructor(
@Inject(SaleInvoice.name)
@Inject(TaxRateTransaction.name)
private readonly taxRateTransactionModel: TenantModelProxy<
typeof SaleInvoice
typeof TaxRateTransaction
>,
@Inject(TaxRateModel.name)

View File

@@ -4,8 +4,9 @@ import { AppModule } from '../src/modules/App/App.module';
let app: INestApplication;
let orgainzationId = 'fxdo7u419m5ryy4tb';
let authenticationToken = '';
let orgainzationId = 'hpgpqhanm8s4921m';
let authenticationToken =
'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6MSwiZXhwIjoxNzQ4MzExOTc5LjIzOCwiaWF0IjoxNzQzMTI3OTc5fQ.h3xvmuNjeyFeshEZRVRLCsARgTpx4xeZQHQuZzESm2U';
beforeAll(async () => {
const moduleFixture: TestingModule = await Test.createTestingModule({