mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 21:30:31 +00:00
refactor(nestjs): e2e test cases
This commit is contained in:
@@ -2,6 +2,7 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { pick } from 'lodash';
|
||||
import { Knex } from 'knex';
|
||||
import * as R from 'ramda';
|
||||
import * as composeAsync from 'async/compose';
|
||||
import { CASHFLOW_TRANSACTION_TYPE } from '../constants';
|
||||
import { transformCashflowTransactionType } from '../utils';
|
||||
import { CommandBankTransactionValidator } from './CommandCasflowValidator.service';
|
||||
@@ -104,7 +105,7 @@ export class CreateBankTransactionService {
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
return R.compose(this.branchDTOTransform.transformDTO<BankTransaction>)(
|
||||
return composeAsync(this.branchDTOTransform.transformDTO<BankTransaction>)(
|
||||
initialDTO,
|
||||
) as BankTransaction;
|
||||
};
|
||||
|
||||
@@ -27,6 +27,7 @@ export class BillDTOTransformer {
|
||||
|
||||
@Inject(ItemEntry.name)
|
||||
private itemEntryModel: TenantModelProxy<typeof ItemEntry>,
|
||||
|
||||
@Inject(Item.name) private itemModel: TenantModelProxy<typeof Item>,
|
||||
) {}
|
||||
|
||||
@@ -114,12 +115,16 @@ export class BillDTOTransformer {
|
||||
}),
|
||||
userId: authorizedUser.id,
|
||||
};
|
||||
|
||||
const asyncDto = await composeAsync(
|
||||
this.branchDTOTransform.transformDTO<Bill>,
|
||||
this.warehouseDTOTransform.transformDTO<Bill>,
|
||||
)(initialDTO);
|
||||
|
||||
return R.compose(
|
||||
// Associates tax amount withheld to the model.
|
||||
this.taxDTOTransformer.assocTaxAmountWithheldFromEntries,
|
||||
this.branchDTOTransform.transformDTO<Bill>,
|
||||
this.warehouseDTOTransform.transformDTO<Bill>,
|
||||
)(initialDTO) as Bill;
|
||||
)(asyncDto) as Bill;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -1,23 +1,30 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { SettingsStore } from '../Settings/SettingsStore';
|
||||
import { SETTINGS_PROVIDER } from '../Settings/Settings.types';
|
||||
import { Features } from '@/common/types/Features';
|
||||
|
||||
@Injectable()
|
||||
export class BranchesSettingsService {
|
||||
constructor(
|
||||
@Inject(SETTINGS_PROVIDER)
|
||||
private readonly settingsStore: () => SettingsStore,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Marks multi-branches as activated.
|
||||
*/
|
||||
public markMultiBranchesAsActivated = () => {
|
||||
// const settings = this.tenancy.settings(tenantId);
|
||||
public markMultiBranchesAsActivated = async () => {
|
||||
const settingsStore = await this.settingsStore();
|
||||
|
||||
// settings.set({ group: 'features', key: Features.BRANCHES, value: 1 });
|
||||
settingsStore.set({ group: 'features', key: Features.BRANCHES, value: 1 });
|
||||
};
|
||||
|
||||
/**
|
||||
* Retrieves whether multi-branches is active.
|
||||
*/
|
||||
public isMultiBranchesActive = () => {
|
||||
// const settings = this.tenancy.settings(tenantId);
|
||||
public isMultiBranchesActive = async () => {
|
||||
const settingsStore = await this.settingsStore();
|
||||
|
||||
// return settings.get({ group: 'features', key: Features.BRANCHES });
|
||||
return false;
|
||||
return settingsStore.get({ group: 'features', key: Features.BRANCHES });
|
||||
};
|
||||
}
|
||||
|
||||
@@ -49,8 +49,8 @@ export class ActivateBranches {
|
||||
* Activate multi-branches feature.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public activateBranches = (): Promise<void> => {
|
||||
const isActivated = this.branchesSettings.isMultiBranchesActive();
|
||||
public activateBranches = async (): Promise<void> => {
|
||||
const isActivated = await this.branchesSettings.isMultiBranchesActive();
|
||||
|
||||
// Throw error if mutli-branches is already activated.
|
||||
this.throwIfMultiBranchesActivated(isActivated);
|
||||
|
||||
@@ -10,22 +10,24 @@ export class BranchTransactionDTOTransformer {
|
||||
* Excludes DTO branch id when mutli-warehouses feature is inactive.
|
||||
* @returns {any}
|
||||
*/
|
||||
private excludeDTOBranchIdWhenInactive = <T extends { branchId?: number }>(
|
||||
private excludeDTOBranchIdWhenInactive = async <
|
||||
T extends { branchId?: number },
|
||||
>(
|
||||
DTO: T,
|
||||
): Omit<T, 'branchId'> | T => {
|
||||
const isActive = this.branchesSettings.isMultiBranchesActive();
|
||||
): Promise<Omit<T, 'branchId'> | T> => {
|
||||
const isActive = await this.branchesSettings.isMultiBranchesActive();
|
||||
|
||||
return !isActive ? omit(DTO, ['branchId']) : DTO;
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformes the input DTO for branches feature.
|
||||
* Transforms the input DTO for branches feature.
|
||||
* @param {T} DTO -
|
||||
* @returns {Omit<T, 'branchId'> | T}
|
||||
*/
|
||||
public transformDTO = <T extends { branchId?: number }>(
|
||||
public transformDTO = async <T extends { branchId?: number }>(
|
||||
DTO: T,
|
||||
): Omit<T, 'branchId'> | T => {
|
||||
): Promise<Omit<T, 'branchId'> | T> => {
|
||||
return this.excludeDTOBranchIdWhenInactive<T>(DTO);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -11,17 +11,18 @@ export class ManualJournalBranchesDTOTransformer {
|
||||
) {}
|
||||
|
||||
/**
|
||||
*
|
||||
* @param DTO
|
||||
* @returns
|
||||
*
|
||||
* @param DTO
|
||||
* @returns
|
||||
*/
|
||||
private excludeDTOBranchIdWhenInactive = (
|
||||
private excludeDTOBranchIdWhenInactive = async (
|
||||
DTO: IManualJournalDTO,
|
||||
): IManualJournalDTO => {
|
||||
const isActive = this.branchesSettings.isMultiBranchesActive();
|
||||
|
||||
if (isActive) return DTO;
|
||||
): Promise<IManualJournalDTO> => {
|
||||
const isActive = await this.branchesSettings.isMultiBranchesActive();
|
||||
|
||||
if (isActive) {
|
||||
return DTO;
|
||||
}
|
||||
return {
|
||||
...DTO,
|
||||
entries: DTO.entries.map((e) => omit(e, ['branchId'])),
|
||||
@@ -29,9 +30,11 @@ export class ManualJournalBranchesDTOTransformer {
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
*/
|
||||
public transformDTO = (DTO: IManualJournalDTO): IManualJournalDTO => {
|
||||
return this.excludeDTOBranchIdWhenInactive(DTO);
|
||||
};
|
||||
public transformDTO = async (
|
||||
DTO: IManualJournalDTO,
|
||||
): Promise<IManualJournalDTO> => {
|
||||
return this.excludeDTOBranchIdWhenInactive(DTO);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -17,7 +17,11 @@ import { BrandingTemplateDTOTransformer } from '../../PdfTemplate/BrandingTempla
|
||||
import { assocItemEntriesDefaultIndex } from '@/utils/associate-item-entries-index';
|
||||
import { CreditNoteAutoIncrementService } from './CreditNoteAutoIncrement.service';
|
||||
import { CreditNote } from '../models/CreditNote';
|
||||
import { CreateCreditNoteDto, CreditNoteEntryDto, EditCreditNoteDto } from '../dtos/CreditNote.dto';
|
||||
import {
|
||||
CreateCreditNoteDto,
|
||||
CreditNoteEntryDto,
|
||||
EditCreditNoteDto,
|
||||
} from '../dtos/CreditNote.dto';
|
||||
|
||||
@Injectable()
|
||||
export class CommandCreditNoteDTOTransform {
|
||||
@@ -33,11 +37,11 @@ export class CommandCreditNoteDTOTransform {
|
||||
private readonly branchDTOTransform: BranchTransactionDTOTransformer,
|
||||
private readonly warehouseDTOTransform: WarehouseTransactionDTOTransform,
|
||||
private readonly brandingTemplatesTransformer: BrandingTemplateDTOTransformer,
|
||||
private readonly creditNoteAutoIncrement: CreditNoteAutoIncrementService
|
||||
private readonly creditNoteAutoIncrement: CreditNoteAutoIncrementService,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Transformes the credit/edit DTO to model.
|
||||
* Transforms the credit/edit DTO to model.
|
||||
* @param {ICreditNoteNewDTO | ICreditNoteEditDTO} creditNoteDTO
|
||||
* @param {string} customerCurrencyCode -
|
||||
*/
|
||||
@@ -61,10 +65,10 @@ export class CommandCreditNoteDTOTransform {
|
||||
})),
|
||||
)(creditNoteDTO.entries);
|
||||
|
||||
// Retreive the next credit note number.
|
||||
// Retrieves the next credit note number.
|
||||
const autoNextNumber = this.creditNoteAutoIncrement.getNextCreditNumber();
|
||||
|
||||
// Detarmines the credit note number.
|
||||
// Determines the credit note number.
|
||||
const creditNoteNumber =
|
||||
creditNoteDTO.creditNoteNumber ||
|
||||
oldCreditNote?.creditNoteNumber ||
|
||||
@@ -84,17 +88,17 @@ export class CommandCreditNoteDTOTransform {
|
||||
refundedAmount: 0,
|
||||
invoicesAmount: 0,
|
||||
};
|
||||
const initialAsyncDTO = await composeAsync(
|
||||
const asyncDto = (await composeAsync(
|
||||
this.branchDTOTransform.transformDTO<CreditNote>,
|
||||
this.warehouseDTOTransform.transformDTO<CreditNote>,
|
||||
|
||||
// Assigns the default branding template id to the invoice DTO.
|
||||
this.brandingTemplatesTransformer.assocDefaultBrandingTemplate(
|
||||
'CreditNote',
|
||||
),
|
||||
)(initialDTO);
|
||||
)(initialDTO)) as CreditNote;
|
||||
|
||||
return R.compose(
|
||||
this.branchDTOTransform.transformDTO<CreditNote>,
|
||||
this.warehouseDTOTransform.transformDTO<CreditNote>,
|
||||
)(initialAsyncDTO) as CreditNote;
|
||||
return asyncDto;
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
@@ -88,7 +89,7 @@ export class CommandCreditNoteDto {
|
||||
@IsArray()
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => CreditNoteEntryDto)
|
||||
@Min(1)
|
||||
@ArrayMinSize(1)
|
||||
@ApiProperty({
|
||||
example: [
|
||||
{
|
||||
|
||||
@@ -2,6 +2,7 @@ import { Injectable } from '@nestjs/common';
|
||||
import { omit, sumBy } from 'lodash';
|
||||
import * as moment from 'moment';
|
||||
import * as R from 'ramda';
|
||||
import * as composeAsync from 'async/compose';
|
||||
import { BranchTransactionDTOTransformer } from '@/modules/Branches/integrations/BranchTransactionDTOTransform';
|
||||
import { Expense } from '../models/Expense.model';
|
||||
import { assocItemEntriesDefaultIndex } from '@/utils/associate-item-entries-index';
|
||||
@@ -48,9 +49,9 @@ export class ExpenseDTOTransformer {
|
||||
* @param {ISystemUser} authorizedUser
|
||||
* @return {IExpense}
|
||||
*/
|
||||
private expenseDTOToModel(
|
||||
private async expenseDTOToModel(
|
||||
expenseDTO: CreateExpenseDto | EditExpenseDto,
|
||||
): Expense {
|
||||
): Promise<Expense> {
|
||||
const landedCostAmount = this.getExpenseLandedCostAmount(expenseDTO);
|
||||
const totalAmount = this.getExpenseCategoriesTotal(expenseDTO.categories);
|
||||
|
||||
@@ -71,20 +72,22 @@ export class ExpenseDTOTransformer {
|
||||
}
|
||||
: {}),
|
||||
};
|
||||
return R.compose(this.branchDTOTransform.transformDTO<Expense>)(
|
||||
initialDTO,
|
||||
) as Expense;
|
||||
const asyncDto = await composeAsync(
|
||||
this.branchDTOTransform.transformDTO<Expense>,
|
||||
)(initialDTO);
|
||||
|
||||
return asyncDto as Expense;
|
||||
}
|
||||
|
||||
/**
|
||||
* Transformes the expense create DTO.
|
||||
* Transforms the expense create DTO.
|
||||
* @param {IExpenseCreateDTO} expenseDTO
|
||||
* @returns {Promise<Expense>}
|
||||
*/
|
||||
public expenseCreateDTO = async (
|
||||
expenseDTO: CreateExpenseDto | EditExpenseDto,
|
||||
): Promise<Partial<Expense>> => {
|
||||
const initialDTO = this.expenseDTOToModel(expenseDTO);
|
||||
const initialDTO = await this.expenseDTOToModel(expenseDTO);
|
||||
const tenant = await this.tenancyContext.getTenant(true);
|
||||
|
||||
return {
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import * as R from 'ramda';
|
||||
import * as moment from 'moment';
|
||||
import * as composeAsync from 'async/compose';
|
||||
import { omit } from 'lodash';
|
||||
import { events } from '@/common/events/events';
|
||||
import { InventoryAdjustment } from '../models/InventoryAdjustment';
|
||||
@@ -79,7 +79,7 @@ export class CreateQuickInventoryAdjustmentService {
|
||||
: {}),
|
||||
entries,
|
||||
};
|
||||
return R.compose(
|
||||
return composeAsync(
|
||||
this.warehouseDTOTransform.transformDTO<InventoryAdjustment>,
|
||||
this.branchDTOTransform.transformDTO<InventoryAdjustment>,
|
||||
)(initialDTO) as InventoryAdjustment;
|
||||
|
||||
@@ -3,6 +3,7 @@ import * as moment from 'moment';
|
||||
import * as R from 'ramda';
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import * as composeAsync from 'async/compose';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
IManualJournalDTO,
|
||||
@@ -73,7 +74,7 @@ export class CreateManualJournalService {
|
||||
entries,
|
||||
userId: authorizedUser.id,
|
||||
};
|
||||
return R.compose(
|
||||
return composeAsync(
|
||||
// Omits the `branchId` from entries if multiply branches feature not active.
|
||||
this.branchesDTOTransformer.transformDTO,
|
||||
)(initialDTO) as ManualJournal;
|
||||
|
||||
@@ -71,15 +71,15 @@ export class PaymentReceiveDTOTransformer {
|
||||
exchangeRate: paymentReceiveDTO.exchangeRate || 1,
|
||||
entries,
|
||||
};
|
||||
const initialAsyncDTO = await composeAsync(
|
||||
const asyncDto = await composeAsync(
|
||||
this.branchDTOTransform.transformDTO<PaymentReceived>,
|
||||
|
||||
// Assigns the default branding template id to the invoice DTO.
|
||||
this.brandingTemplatesTransformer.assocDefaultBrandingTemplate(
|
||||
'SaleInvoice',
|
||||
),
|
||||
)(initialDTO);
|
||||
|
||||
return R.compose(this.branchDTOTransform.transformDTO<PaymentReceived>)(
|
||||
initialAsyncDTO,
|
||||
) as PaymentReceived;
|
||||
return asyncDto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -81,17 +81,17 @@ export class SaleEstimateDTOTransformer {
|
||||
deliveredAt: moment().toMySqlDateTime(),
|
||||
}),
|
||||
};
|
||||
const initialAsyncDTO = await composeAsync(
|
||||
const asyncDto = await composeAsync(
|
||||
this.branchDTOTransform.transformDTO<SaleEstimate>,
|
||||
this.warehouseDTOTransform.transformDTO<SaleEstimate>,
|
||||
|
||||
// Assigns the default branding template id to the invoice DTO.
|
||||
this.brandingTemplatesTransformer.assocDefaultBrandingTemplate(
|
||||
'SaleEstimate',
|
||||
),
|
||||
)(initialDTO);
|
||||
|
||||
return R.compose(
|
||||
this.branchDTOTransform.transformDTO<SaleEstimate>,
|
||||
this.warehouseDTOTransform.transformDTO<SaleEstimate>,
|
||||
)(initialAsyncDTO);
|
||||
return asyncDto;
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -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,
|
||||
@@ -92,7 +93,7 @@ export class CommandSaleEstimateDto {
|
||||
branchId?: number;
|
||||
|
||||
@IsArray()
|
||||
@MinLength(1)
|
||||
@ArrayMinSize(1)
|
||||
@ValidateNested({ each: true })
|
||||
@Type(() => SaleEstimateEntryDto)
|
||||
@ApiProperty({
|
||||
|
||||
@@ -121,17 +121,18 @@ export class CommandSaleInvoiceDTOTransformer {
|
||||
} as SaleInvoice;
|
||||
|
||||
const initialAsyncDTO = await composeAsync(
|
||||
this.branchDTOTransform.transformDTO<SaleInvoice>,
|
||||
this.warehouseDTOTransform.transformDTO<SaleInvoice>,
|
||||
|
||||
// Assigns the default branding template id to the invoice DTO.
|
||||
this.brandingTemplatesTransformer.assocDefaultBrandingTemplate(
|
||||
'SaleInvoice',
|
||||
),
|
||||
)(initialDTO);
|
||||
|
||||
return R.compose(
|
||||
this.taxDTOTransformer.assocTaxAmountWithheldFromEntries,
|
||||
this.branchDTOTransform.transformDTO<SaleInvoice>,
|
||||
this.warehouseDTOTransform.transformDTO<SaleInvoice>,
|
||||
)(initialAsyncDTO);
|
||||
return R.compose(this.taxDTOTransformer.assocTaxAmountWithheldFromEntries)(
|
||||
initialAsyncDTO,
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -2,7 +2,6 @@ import { Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Knex } from 'knex';
|
||||
import {
|
||||
ISaleInvoiceCreateDTO,
|
||||
ISaleInvoiceCreatedPayload,
|
||||
ISaleInvoiceCreatingPaylaod,
|
||||
} from '../SaleInvoice.types';
|
||||
|
||||
@@ -15,7 +15,10 @@ import { assocItemEntriesDefaultIndex } from '@/utils/associate-item-entries-ind
|
||||
import { SaleReceipt } from '../models/SaleReceipt';
|
||||
import { Customer } from '@/modules/Customers/models/Customer';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { CreateSaleReceiptDto, EditSaleReceiptDto } from '../dtos/SaleReceipt.dto';
|
||||
import {
|
||||
CreateSaleReceiptDto,
|
||||
EditSaleReceiptDto,
|
||||
} from '../dtos/SaleReceipt.dto';
|
||||
|
||||
@Injectable()
|
||||
export class SaleReceiptDTOTransformer {
|
||||
@@ -96,16 +99,16 @@ export class SaleReceiptDTOTransformer {
|
||||
}),
|
||||
entries,
|
||||
};
|
||||
const initialAsyncDTO = await composeAsync(
|
||||
const asyncDto = await composeAsync(
|
||||
this.branchDTOTransform.transformDTO<SaleReceipt>,
|
||||
this.warehouseDTOTransform.transformDTO<SaleReceipt>,
|
||||
|
||||
// Assigns the default branding template id to the invoice DTO.
|
||||
this.brandingTemplatesTransformer.assocDefaultBrandingTemplate(
|
||||
'SaleReceipt',
|
||||
),
|
||||
)(initialDTO);
|
||||
|
||||
return R.compose(
|
||||
this.branchDTOTransform.transformDTO<SaleReceipt>,
|
||||
this.warehouseDTOTransform.transformDTO<SaleReceipt>,
|
||||
)(initialAsyncDTO) as SaleReceipt;
|
||||
return asyncDto;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -24,6 +24,7 @@ import { SaleReceipt } from '../models/SaleReceipt';
|
||||
import { MailTransporter } from '@/modules/Mail/MailTransporter.service';
|
||||
import { Mail } from '@/modules/Mail/Mail';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class SaleReceiptMailNotification {
|
||||
@@ -43,7 +44,7 @@ export class SaleReceiptMailNotification {
|
||||
private readonly tenancyContext: TenancyContext,
|
||||
|
||||
@Inject(SaleReceipt.name)
|
||||
private readonly saleReceiptModel: typeof SaleReceipt,
|
||||
private readonly saleReceiptModel: TenantModelProxy<typeof SaleReceipt>,
|
||||
|
||||
@InjectQueue(SendSaleReceiptMailQueue)
|
||||
private readonly sendSaleReceiptMailProcess: Queue,
|
||||
@@ -74,7 +75,6 @@ export class SaleReceiptMailNotification {
|
||||
await this.sendSaleReceiptMailProcess.add(SendSaleReceiptMailJob, {
|
||||
...payload,
|
||||
});
|
||||
|
||||
// Triggers the event `onSaleReceiptPreMailSend`.
|
||||
await this.eventEmitter.emitAsync(events.saleReceipt.onPreMailSend, {
|
||||
saleReceiptId,
|
||||
@@ -90,7 +90,7 @@ export class SaleReceiptMailNotification {
|
||||
public async getMailOptions(
|
||||
saleReceiptId: number,
|
||||
): Promise<SaleReceiptMailOpts> {
|
||||
const saleReceipt = await this.saleReceiptModel
|
||||
const saleReceipt = await this.saleReceiptModel()
|
||||
.query()
|
||||
.findById(saleReceiptId)
|
||||
.throwIfNotFound();
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import knex from 'knex';
|
||||
import * as LRUCache from 'lru-cache';
|
||||
import { Global, Module } from '@nestjs/common';
|
||||
import { knexSnakeCaseMappers } from 'objection';
|
||||
import { ClsModule, ClsService } from 'nestjs-cls';
|
||||
@@ -6,6 +7,8 @@ import { ConfigService } from '@nestjs/config';
|
||||
import { TENANCY_DB_CONNECTION } from './TenancyDB.constants';
|
||||
import { UnitOfWork } from './UnitOfWork.service';
|
||||
|
||||
const lruCache = new LRUCache();
|
||||
|
||||
export const TenancyDatabaseProxyProvider = ClsModule.forFeatureAsync({
|
||||
provide: TENANCY_DB_CONNECTION,
|
||||
global: true,
|
||||
@@ -13,14 +16,19 @@ export const TenancyDatabaseProxyProvider = ClsModule.forFeatureAsync({
|
||||
inject: [ConfigService, ClsService],
|
||||
useFactory: async (configService: ConfigService, cls: ClsService) => () => {
|
||||
const organizationId = cls.get('organizationId');
|
||||
const database = `bigcapital_tenant_${organizationId}`;
|
||||
const cachedInstance = lruCache.get(database);
|
||||
|
||||
return knex({
|
||||
if (cachedInstance) {
|
||||
return cachedInstance;
|
||||
}
|
||||
const knexInstance = knex({
|
||||
client: configService.get('tenantDatabase.client'),
|
||||
connection: {
|
||||
host: configService.get('tenantDatabase.host'),
|
||||
user: configService.get('tenantDatabase.user'),
|
||||
password: configService.get('tenantDatabase.password'),
|
||||
database: `bigcapital_tenant_${organizationId}`,
|
||||
database,
|
||||
charset: 'utf8',
|
||||
},
|
||||
migrations: {
|
||||
@@ -32,6 +40,9 @@ export const TenancyDatabaseProxyProvider = ClsModule.forFeatureAsync({
|
||||
pool: { min: 0, max: 7 },
|
||||
...knexSnakeCaseMappers({ upperCase: true }),
|
||||
});
|
||||
lruCache.set(database, knexInstance);
|
||||
|
||||
return knexInstance;
|
||||
},
|
||||
type: 'function',
|
||||
});
|
||||
|
||||
@@ -91,9 +91,10 @@ export function RegisterTenancyModel(model: typeof Model) {
|
||||
provide: model.name,
|
||||
inject: [TENANCY_DB_CONNECTION],
|
||||
global: true,
|
||||
useFactory: async (tenantKnex: () => Knex) => () => {
|
||||
useFactory: (tenantKnex: () => Knex) => () => {
|
||||
return model.bindKnex(tenantKnex());
|
||||
},
|
||||
strict: true,
|
||||
type: 'function',
|
||||
});
|
||||
}
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import * as moment from 'moment';
|
||||
import { omit } from 'lodash';
|
||||
import * as R from 'ramda';
|
||||
import * as composeAsync from 'async/compose';
|
||||
import { ERRORS } from '../constants';
|
||||
import { ItemsEntriesService } from '@/modules/Items/ItemsEntries.service';
|
||||
import { BranchTransactionDTOTransformer } from '@/modules/Branches/integrations/BranchTransactionDTOTransform';
|
||||
@@ -32,7 +33,7 @@ export class VendorCreditDTOTransformService {
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Transformes the credit/edit vendor credit DTO to model.
|
||||
* Transforms the credit/edit vendor credit DTO to model.
|
||||
* @param {IVendorCreditCreateDTO | IVendorCreditEditDTO} vendorCreditDTO
|
||||
* @param {string} vendorCurrencyCode -
|
||||
* @param {IVendorCredit} oldVendorCredit -
|
||||
@@ -80,7 +81,7 @@ export class VendorCreditDTOTransformService {
|
||||
openedAt: moment().toMySqlDateTime(),
|
||||
}),
|
||||
};
|
||||
return R.compose(
|
||||
return composeAsync(
|
||||
this.branchDTOTransform.transformDTO<VendorCredit>,
|
||||
this.warehouseDTOTransform.transformDTO<VendorCredit>,
|
||||
)(initialDTO) as VendorCredit;
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import * as R from 'ramda';
|
||||
import * as composeAsync from 'async/compose';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
IRefundVendorCreditCreatedPayload,
|
||||
@@ -81,7 +82,7 @@ export class CreateRefundVendorCredit {
|
||||
refundVendorCreditDTO,
|
||||
} as IVendorCreditCreatePayload);
|
||||
|
||||
const refundCreditObj = this.transformDTOToModel(
|
||||
const refundCreditObj = await this.transformDTOToModel(
|
||||
vendorCredit,
|
||||
refundVendorCreditDTO,
|
||||
);
|
||||
@@ -119,7 +120,7 @@ export class CreateRefundVendorCredit {
|
||||
* @param {RefundVendorCreditDto} vendorCreditDTO
|
||||
* @returns {IRefundVendorCredit}
|
||||
*/
|
||||
public transformDTOToModel = (
|
||||
public transformDTOToModel = async (
|
||||
vendorCredit: VendorCredit,
|
||||
vendorCreditDTO: RefundVendorCreditDto,
|
||||
) => {
|
||||
@@ -129,7 +130,7 @@ export class CreateRefundVendorCredit {
|
||||
currencyCode: vendorCredit.currencyCode,
|
||||
exchangeRate: vendorCreditDTO.exchangeRate || 1,
|
||||
};
|
||||
return R.compose(this.branchDTOTransform.transformDTO)(initialDTO);
|
||||
return this.branchDTOTransform.transformDTO(initialDTO);
|
||||
};
|
||||
|
||||
/**
|
||||
|
||||
@@ -4,34 +4,32 @@ import { WarehousesSettings } from '../WarehousesSettings';
|
||||
|
||||
@Injectable()
|
||||
export class WarehouseTransactionDTOTransform {
|
||||
constructor(
|
||||
private readonly warehousesSettings: WarehousesSettings,
|
||||
) {}
|
||||
constructor(private readonly warehousesSettings: WarehousesSettings) {}
|
||||
|
||||
/**
|
||||
* Excludes DTO warehouse id when mutli-warehouses feature is inactive.
|
||||
* @param {number} tenantId
|
||||
* @returns {Promise<Omit<T, 'warehouseId'> | T>}
|
||||
*/
|
||||
private excludeDTOWarehouseIdWhenInactive = <
|
||||
T extends { warehouseId?: number }
|
||||
private excludeDTOWarehouseIdWhenInactive = async <
|
||||
T extends { warehouseId?: number },
|
||||
>(
|
||||
DTO: T
|
||||
): Omit<T, 'warehouseId'> | T => {
|
||||
const isActive = this.warehousesSettings.isMultiWarehousesActive();
|
||||
DTO: T,
|
||||
): Promise<Omit<T, 'warehouseId'> | T> => {
|
||||
const isActive = await this.warehousesSettings.isMultiWarehousesActive();
|
||||
|
||||
return !isActive ? omit(DTO, ['warehouseId']) : DTO;
|
||||
};
|
||||
|
||||
/**
|
||||
*
|
||||
*
|
||||
* @param {number} tenantId
|
||||
* @param {T} DTO -
|
||||
* @returns {Omit<T, 'warehouseId'> | T}
|
||||
*/
|
||||
public transformDTO =
|
||||
<T extends { warehouseId?: number }>(DTO: T): Omit<T, 'warehouseId'> | T => {
|
||||
return this.excludeDTOWarehouseIdWhenInactive<T>(DTO);
|
||||
};
|
||||
public transformDTO = async <T extends { warehouseId?: number }>(
|
||||
DTO: T,
|
||||
): Promise<Omit<T, 'warehouseId'> | T> => {
|
||||
return this.excludeDTOWarehouseIdWhenInactive<T>(DTO);
|
||||
};
|
||||
}
|
||||
|
||||
@@ -19,7 +19,9 @@ export class WarehousesDTOValidators {
|
||||
* Validates the warehouse existance of sale invoice transaction.
|
||||
* @param {IWarehouseTransactionDTO} DTO
|
||||
*/
|
||||
public validateDTOWarehouseExistance = async (DTO: IWarehouseTransactionDTO) => {
|
||||
public validateDTOWarehouseExistance = async (
|
||||
DTO: IWarehouseTransactionDTO,
|
||||
) => {
|
||||
// Validates the sale invoice warehouse id existance.
|
||||
this.validateWarehouseExistanceService.validateWarehouseIdExistance(
|
||||
DTO,
|
||||
@@ -47,7 +49,7 @@ export class WarehousesDTOValidators {
|
||||
public validateDTOWarehouseWhenActive = async (
|
||||
DTO: IWarehouseTransactionDTO,
|
||||
): Promise<void> => {
|
||||
const isActive = this.warehousesSettings.isMultiWarehousesActive();
|
||||
const isActive = await this.warehousesSettings.isMultiWarehousesActive();
|
||||
|
||||
// Can't continue if the multi-warehouses feature is inactive.
|
||||
if (!isActive) return;
|
||||
|
||||
@@ -24,7 +24,7 @@ export class WarehousesItemsQuantitySyncSubscriber {
|
||||
inventoryTransactions,
|
||||
trx,
|
||||
}: IInventoryTransactionsCreatedPayload) {
|
||||
const isActive = this.warehousesSettings.isMultiWarehousesActive();
|
||||
const isActive = await this.warehousesSettings.isMultiWarehousesActive();
|
||||
|
||||
// Can't continue if the warehouses features is not active.
|
||||
if (!isActive) return;
|
||||
@@ -44,7 +44,7 @@ export class WarehousesItemsQuantitySyncSubscriber {
|
||||
oldInventoryTransactions,
|
||||
trx,
|
||||
}: IInventoryTransactionsDeletedPayload) {
|
||||
const isActive = this.warehousesSettings.isMultiWarehousesActive();
|
||||
const isActive = await this.warehousesSettings.isMultiWarehousesActive();
|
||||
|
||||
// Can't continue if the warehouses feature is not active yet.
|
||||
if (!isActive) return;
|
||||
|
||||
@@ -1,25 +1,32 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { SettingsStore } from '../Settings/SettingsStore';
|
||||
import { SETTINGS_PROVIDER } from '../Settings/Settings.types';
|
||||
import { Features } from '@/common/types/Features';
|
||||
|
||||
@Injectable()
|
||||
export class WarehousesSettings {
|
||||
constructor(
|
||||
@Inject(SETTINGS_PROVIDER)
|
||||
private readonly settingsStore: () => SettingsStore,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Marks multi-warehouses as activated.
|
||||
*/
|
||||
public markMutliwarehoussAsActivated = () => {
|
||||
// const settings = this.tenancy.settings(tenantId);
|
||||
public markMutliwarehoussAsActivated = async () => {
|
||||
const settings = await this.settingsStore();
|
||||
|
||||
// settings.set({ group: 'features', key: Features.WAREHOUSES, value: 1 });
|
||||
settings.set({ group: 'features', key: Features.WAREHOUSES, value: 1 });
|
||||
};
|
||||
|
||||
/**
|
||||
* Detarmines multi-warehouses is active.
|
||||
* Determines multi-warehouses is active.
|
||||
* @param {number} tenantId
|
||||
* @returns {boolean}
|
||||
*/
|
||||
public isMultiWarehousesActive = () => {
|
||||
// const settings = this.tenancy.settings(tenantId);
|
||||
public isMultiWarehousesActive = async () => {
|
||||
const settings = await this.settingsStore();
|
||||
|
||||
// return settings.get({ group: 'features', key: Features.WAREHOUSES });
|
||||
return true;
|
||||
return settings.get({ group: 'features', key: Features.WAREHOUSES });
|
||||
};
|
||||
}
|
||||
|
||||
@@ -40,7 +40,7 @@ export class ActivateWarehousesService {
|
||||
* - Mutate inventory transactions with the primary warehouse.
|
||||
*/
|
||||
public async activateWarehouses(): Promise<void> {
|
||||
const isActivated = this.settings.isMultiWarehousesActive();
|
||||
const isActivated = await this.settings.isMultiWarehousesActive();
|
||||
this.throwIfWarehousesActivated(isActivated);
|
||||
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
|
||||
@@ -39,6 +39,7 @@ describe('Sale Estimates (e2e)', () => {
|
||||
.set('organization-id', orgainzationId)
|
||||
.send({
|
||||
name: faker.commerce.productName(),
|
||||
type: 'inventory',
|
||||
sellable: true,
|
||||
purchasable: true,
|
||||
sellAccountId: 1026,
|
||||
|
||||
Reference in New Issue
Block a user