mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 05:10:31 +00:00
feat(nestjs): migrate to NestJS
This commit is contained in:
@@ -0,0 +1,122 @@
|
||||
import { Queue } from 'bullmq';
|
||||
import { InjectQueue } from '@nestjs/bullmq';
|
||||
import {
|
||||
IOrganizationBuildEventPayload,
|
||||
IOrganizationBuiltEventPayload,
|
||||
OrganizationBuildQueue,
|
||||
OrganizationBuildQueueJob,
|
||||
OrganizationBuildQueueJobPayload,
|
||||
} from '../Organization.types';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import {
|
||||
throwIfTenantInitizalized,
|
||||
throwIfTenantIsBuilding,
|
||||
} from '../Organization/_utils';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { TenantsManagerService } from '@/modules/TenantDBManager/TenantsManager';
|
||||
import { events } from '@/common/events/events';
|
||||
import { transformBuildDto } from '../Organization.utils';
|
||||
import { BuildOrganizationDto } from '../dtos/Organization.dto';
|
||||
import { TenantRepository } from '@/modules/System/repositories/Tenant.repository';
|
||||
|
||||
@Injectable()
|
||||
export class BuildOrganizationService {
|
||||
constructor(
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
private readonly tenantsManager: TenantsManagerService,
|
||||
private readonly tenancyContext: TenancyContext,
|
||||
private readonly tenantRepository: TenantRepository,
|
||||
|
||||
@InjectQueue(OrganizationBuildQueue)
|
||||
private readonly organizationBuildQueue: Queue,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Builds the database schema and seed data of the given organization id.
|
||||
* @param {string} organizationId
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
public async build(buildDTO: BuildOrganizationDto): Promise<void> {
|
||||
const tenant = await this.tenancyContext.getTenant();
|
||||
const systemUser = await this.tenancyContext.getSystemUser();
|
||||
|
||||
// Throw error if the tenant is already initialized.
|
||||
throwIfTenantInitizalized(tenant);
|
||||
|
||||
await this.tenantsManager.dropDatabaseIfExists();
|
||||
await this.tenantsManager.createDatabase();
|
||||
|
||||
await this.tenantsManager.migrateTenant();
|
||||
await this.tenantsManager.seedTenant()
|
||||
|
||||
// Throws `onOrganizationBuild` event.
|
||||
await this.eventPublisher.emitAsync(events.organization.build, {
|
||||
tenantId: tenant.id,
|
||||
buildDTO,
|
||||
systemUser,
|
||||
} as IOrganizationBuildEventPayload);
|
||||
|
||||
// Marks the tenant as completed builing.
|
||||
await this.tenantRepository.markAsBuilt().findById(tenant.id);
|
||||
await this.tenantRepository.markAsBuildCompleted().findById(tenant.id);
|
||||
|
||||
// Flags the tenant database batch.
|
||||
await this.tenantRepository.flagTenantDBBatch().findById(tenant.id);
|
||||
|
||||
// Triggers the organization built event.
|
||||
await this.eventPublisher.emitAsync(events.organization.built, {
|
||||
tenantId: tenant.id,
|
||||
} as IOrganizationBuiltEventPayload);
|
||||
}
|
||||
|
||||
/**
|
||||
* Execute the tenant database build process.
|
||||
* @param {BuildOrganizationDto} buildDTO - Organization build dto.
|
||||
* @returns {Promise<{ nextRunAt: Date; jobId: string }>} - Returns the next run date and job id.
|
||||
*/
|
||||
async buildRunJob(
|
||||
buildDTO: BuildOrganizationDto,
|
||||
): Promise<{ nextRunAt: Date; jobId: string }> {
|
||||
const tenant = await this.tenancyContext.getTenant();
|
||||
const systemUser = await this.tenancyContext.getSystemUser();
|
||||
|
||||
// Throw error if the tenant is already initialized.
|
||||
throwIfTenantInitizalized(tenant);
|
||||
|
||||
// Throw error if tenant is currently building.
|
||||
throwIfTenantIsBuilding(tenant);
|
||||
|
||||
// Transforms build DTO object.
|
||||
const transformedBuildDTO = transformBuildDto(buildDTO);
|
||||
|
||||
// Saves the tenant metadata.
|
||||
await this.tenantRepository.saveMetadata(tenant.id, transformedBuildDTO);
|
||||
|
||||
// Run the organization database build job.
|
||||
const jobMeta = await this.organizationBuildQueue.add(
|
||||
OrganizationBuildQueueJob,
|
||||
{
|
||||
organizationId: tenant.organizationId,
|
||||
userId: systemUser.id,
|
||||
buildDto: transformedBuildDTO,
|
||||
} as OrganizationBuildQueueJobPayload,
|
||||
);
|
||||
// Marks the tenant as currently building.
|
||||
await this.tenantRepository.markAsBuilding(jobMeta.id).findById(tenant.id);
|
||||
|
||||
return {
|
||||
nextRunAt: jobMeta.data.nextRunAt,
|
||||
jobId: jobMeta.data.id,
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Unlocks tenant build run job.
|
||||
*/
|
||||
public async revertBuildRunJob() {
|
||||
const tenant = await this.tenancyContext.getTenant();
|
||||
|
||||
await this.tenantRepository.markAsBuildCompleted().findById(tenant.id);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,35 @@
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { OrganizationBaseCurrencyLocking } from '../Organization/OrganizationBaseCurrencyLocking.service';
|
||||
import { TenantModel } from '@/modules/System/models/TenantModel';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ERRORS } from '../Organization.constants';
|
||||
|
||||
@Injectable()
|
||||
export class CommandOrganizationValidators {
|
||||
constructor(
|
||||
private readonly baseCurrencyMutateLocking: OrganizationBaseCurrencyLocking,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Validate mutate base currency ability.
|
||||
* @param {Tenant} tenant -
|
||||
* @param {string} newBaseCurrency -
|
||||
* @param {string} oldBaseCurrency -
|
||||
*/
|
||||
async validateMutateBaseCurrency(
|
||||
tenant: TenantModel,
|
||||
newBaseCurrency: string,
|
||||
oldBaseCurrency: string,
|
||||
) {
|
||||
if (tenant.isReady && newBaseCurrency !== oldBaseCurrency) {
|
||||
const isLocked =
|
||||
await this.baseCurrencyMutateLocking.isBaseCurrencyMutateLocked(
|
||||
tenant.id,
|
||||
);
|
||||
|
||||
if (isLocked) {
|
||||
throw new ServiceError(ERRORS.BASE_CURRENCY_MUTATE_LOCKED);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,50 @@
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import { UpdateOrganizationDto } from '../dtos/Organization.dto';
|
||||
import { throwIfTenantNotExists } from '../Organization/_utils';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { events } from '@/common/events/events';
|
||||
import { CommandOrganizationValidators } from './CommandOrganizationValidators.service';
|
||||
import { TenantRepository } from '@/modules/System/repositories/Tenant.repository';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
|
||||
@Injectable()
|
||||
export class UpdateOrganizationService {
|
||||
constructor(
|
||||
private readonly tenancyContext: TenancyContext,
|
||||
private readonly eventEmitter: EventEmitter2,
|
||||
private readonly commandOrganizationValidators: CommandOrganizationValidators,
|
||||
|
||||
private readonly tenantRepository: TenantRepository,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Updates organization information.
|
||||
* @param {UpdateOrganizationDto} organizationDTO
|
||||
*/
|
||||
public async execute(organizationDTO: UpdateOrganizationDto): Promise<void> {
|
||||
const tenant = await this.tenancyContext.getTenant(true);
|
||||
|
||||
// Throw error if the tenant not exists.
|
||||
throwIfTenantNotExists(tenant);
|
||||
|
||||
// Validate organization transactions before mutate base currency.
|
||||
if (organizationDTO.baseCurrency) {
|
||||
await this.commandOrganizationValidators.validateMutateBaseCurrency(
|
||||
tenant,
|
||||
organizationDTO.baseCurrency,
|
||||
tenant.metadata?.baseCurrency,
|
||||
);
|
||||
}
|
||||
await this.tenantRepository.saveMetadata(tenant.id, organizationDTO);
|
||||
|
||||
if (organizationDTO.baseCurrency !== tenant.metadata?.baseCurrency) {
|
||||
// Triggers `onOrganizationBaseCurrencyUpdated` event.
|
||||
await this.eventEmitter.emitAsync(
|
||||
events.organization.baseCurrencyUpdated,
|
||||
{
|
||||
organizationDTO,
|
||||
},
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
Reference in New Issue
Block a user