mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-17 21:30:31 +00:00
feat(nestjs): migrate to NestJS
This commit is contained in:
@@ -0,0 +1,59 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { VendorValidators } from './VendorValidators';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Vendor } from '../models/Vendor';
|
||||
import { events } from '@/common/events/events';
|
||||
import { IVendorActivatedPayload } from '../types/Vendors.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class ActivateVendorService {
|
||||
constructor(
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
private readonly validators: VendorValidators,
|
||||
|
||||
@Inject(Vendor.name)
|
||||
private readonly vendorModel: TenantModelProxy<typeof Vendor>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Inactive the given contact.
|
||||
* @param {number} vendorId - Vendor id.
|
||||
* @returns {Promise<void>}
|
||||
*/
|
||||
public async activateVendor(vendorId: number): Promise<void> {
|
||||
// Retrieves the old vendor or throw not found error.
|
||||
const oldVendor = await this.vendorModel()
|
||||
.query()
|
||||
.findById(vendorId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Validate whether the vendor is already published.
|
||||
this.validators.validateNotAlreadyPublished(oldVendor);
|
||||
|
||||
// Edits the vendor with associated transactions on unit-of-work environment.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onVendorActivating` event.
|
||||
await this.eventPublisher.emitAsync(events.vendors.onActivating, {
|
||||
trx,
|
||||
oldVendor,
|
||||
} as IVendorActivatedPayload);
|
||||
|
||||
// Updates the vendor on the storage.
|
||||
const vendor = await this.vendorModel()
|
||||
.query(trx)
|
||||
.updateAndFetchById(vendorId, {
|
||||
active: true,
|
||||
});
|
||||
// Triggers `onVendorActivated` event.
|
||||
await this.eventPublisher.emitAsync(events.vendors.onActivated, {
|
||||
trx,
|
||||
oldVendor,
|
||||
vendor,
|
||||
} as IVendorActivatedPayload);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,73 @@
|
||||
import * as moment from 'moment';
|
||||
import { defaultTo, isEmpty } from 'lodash';
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { IVendorEditDTO, IVendorNewDTO } from '../types/Vendors.types';
|
||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||
import { ContactService } from '@/modules/Contacts/types/Contacts.types';
|
||||
import { Vendor } from '../models/Vendor';
|
||||
import { CreateVendorDto } from '../dtos/CreateVendor.dto';
|
||||
|
||||
@Injectable()
|
||||
export class CreateEditVendorDTOService {
|
||||
/**
|
||||
* @param {TenancyContext} tenancyContext - Tenancy context service.
|
||||
*/
|
||||
constructor(private readonly tenancyContext: TenancyContext) {}
|
||||
|
||||
/**
|
||||
* Transforms the common vendor DTO.
|
||||
* @param {IVendorNewDTO | IVendorEditDTO} vendorDTO
|
||||
* @returns {IVendorNewDTO | IVendorEditDTO}
|
||||
*/
|
||||
private transformCommonDTO = (vendorDTO: IVendorNewDTO | IVendorEditDTO) => {
|
||||
return {
|
||||
...vendorDTO,
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformes the create vendor DTO.
|
||||
* @param {IVendorNewDTO} vendorDTO -
|
||||
* @returns {IVendorNewDTO}
|
||||
*/
|
||||
public transformCreateDTO = async (
|
||||
vendorDTO: CreateVendorDto,
|
||||
): Promise<Partial<Vendor>> => {
|
||||
const commonDTO = this.transformCommonDTO(vendorDTO);
|
||||
|
||||
// Retrieves the tenant metadata.
|
||||
const tenant = await this.tenancyContext.getTenant(true);
|
||||
|
||||
return {
|
||||
...commonDTO,
|
||||
currencyCode: vendorDTO.currencyCode || tenant.metadata.baseCurrency,
|
||||
active: defaultTo(vendorDTO.active, true),
|
||||
contactService: ContactService.Vendor,
|
||||
|
||||
...(!isEmpty(vendorDTO.openingBalanceAt)
|
||||
? {
|
||||
openingBalanceAt: moment(
|
||||
vendorDTO?.openingBalanceAt,
|
||||
).toMySqlDateTime(),
|
||||
}
|
||||
: {}),
|
||||
openingBalanceExchangeRate: defaultTo(
|
||||
vendorDTO.openingBalanceExchangeRate,
|
||||
1,
|
||||
),
|
||||
};
|
||||
};
|
||||
|
||||
/**
|
||||
* Transformes the edit vendor DTO.
|
||||
* @param {IVendorEditDTO} vendorDTO
|
||||
* @returns {IVendorEditDTO}
|
||||
*/
|
||||
public transformEditDTO = (vendorDTO: IVendorEditDTO) => {
|
||||
const commonDTO = this.transformCommonDTO(vendorDTO);
|
||||
|
||||
return {
|
||||
...commonDTO,
|
||||
};
|
||||
};
|
||||
}
|
||||
@@ -0,0 +1,66 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { Vendor } from '../models/Vendor';
|
||||
import { events } from '@/common/events/events';
|
||||
import {
|
||||
IVendorEventCreatedPayload,
|
||||
IVendorEventCreatingPayload,
|
||||
IVendorNewDTO,
|
||||
} from '../types/Vendors.types';
|
||||
import { CreateEditVendorDTOService } from './CreateEditVendorDTO';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { CreateVendorDto } from '../dtos/CreateVendor.dto';
|
||||
|
||||
@Injectable()
|
||||
export class CreateVendorService {
|
||||
/**
|
||||
* @param {UnitOfWork} uow - Unit of work service.
|
||||
* @param {EventEmitter2} eventPublisher - Event emitter service.
|
||||
* @param {CreateEditVendorDTOService} transformDTO - Create edit vendor DTO service.
|
||||
* @param {typeof Vendor} vendorModel - Vendor model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
private readonly transformDTO: CreateEditVendorDTOService,
|
||||
|
||||
@Inject(Vendor.name)
|
||||
private readonly vendorModel: TenantModelProxy<typeof Vendor>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Creates a new vendor.
|
||||
* @param {IVendorNewDTO} vendorDTO
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
public async createVendor(vendorDTO: CreateVendorDto, trx?: Knex.Transaction) {
|
||||
// Transforms create DTO to customer object.
|
||||
const vendorObject = await this.transformDTO.transformCreateDTO(vendorDTO);
|
||||
|
||||
// Creates vendor contact under unit-of-work environment.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onVendorCreating` event.
|
||||
await this.eventPublisher.emitAsync(events.vendors.onCreating, {
|
||||
vendorDTO,
|
||||
trx,
|
||||
} as IVendorEventCreatingPayload);
|
||||
|
||||
// Creates a new contact as vendor.
|
||||
const vendor = await this.vendorModel()
|
||||
.query(trx)
|
||||
.insertAndFetch({
|
||||
...vendorObject,
|
||||
});
|
||||
// Triggers `onVendorCreated` event.
|
||||
await this.eventPublisher.emitAsync(events.vendors.onCreated, {
|
||||
vendorId: vendor.id,
|
||||
vendor,
|
||||
trx,
|
||||
} as IVendorEventCreatedPayload);
|
||||
|
||||
return vendor;
|
||||
}, trx);
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,60 @@
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { Knex } from 'knex';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { Vendor } from '../models/Vendor';
|
||||
import { events } from '@/common/events/events';
|
||||
import {
|
||||
IVendorEventDeletedPayload,
|
||||
IVendorEventDeletingPayload,
|
||||
} from '../types/Vendors.types';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class DeleteVendorService {
|
||||
/**
|
||||
* @param {EventEmitter2} eventPublisher - Event emitter service.
|
||||
* @param {UnitOfWork} uow - Unit of work service.
|
||||
* @param {typeof Vendor} contactModel - Vendor model.
|
||||
*/
|
||||
constructor(
|
||||
private eventPublisher: EventEmitter2,
|
||||
private uow: UnitOfWork,
|
||||
@Inject(Vendor.name) private vendorModel: TenantModelProxy<typeof Vendor>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Deletes the given vendor.
|
||||
* @param {number} vendorId
|
||||
* @return {Promise<void>}
|
||||
*/
|
||||
public async deleteVendor(vendorId: number) {
|
||||
// Retrieves the old vendor or throw not found service error.
|
||||
const oldVendor = await this.vendorModel()
|
||||
.query()
|
||||
.findById(vendorId)
|
||||
.throwIfNotFound();
|
||||
// .queryAndThrowIfHasRelations({
|
||||
// type: ERRORS.VENDOR_HAS_TRANSACTIONS,
|
||||
// });
|
||||
|
||||
// Triggers `onVendorDeleting` event.
|
||||
await this.eventPublisher.emitAsync(events.vendors.onDeleting, {
|
||||
vendorId,
|
||||
oldVendor,
|
||||
} as IVendorEventDeletingPayload);
|
||||
|
||||
// Deletes vendor contact under unit-of-work.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Deletes the vendor contact from the storage.
|
||||
await this.vendorModel().query(trx).findById(vendorId).delete();
|
||||
|
||||
// Triggers `onVendorDeleted` event.
|
||||
await this.eventPublisher.emitAsync(events.vendors.onDeleted, {
|
||||
vendorId,
|
||||
oldVendor,
|
||||
trx,
|
||||
} as IVendorEventDeletedPayload);
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,78 @@
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import {
|
||||
IVendorOpeningBalanceEditDTO,
|
||||
IVendorOpeningBalanceEditedPayload,
|
||||
IVendorOpeningBalanceEditingPayload,
|
||||
} from '../types/Vendors.types';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { Vendor } from '../models/Vendor';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
|
||||
@Injectable()
|
||||
export class EditOpeningBalanceVendorService {
|
||||
/**
|
||||
* @param {EventEmitter2} eventPublisher - Event emitter service.
|
||||
* @param {UnitOfWork} uow - Unit of work service.
|
||||
* @param {typeof Vendor} vendorModel - Vendor model.
|
||||
*/
|
||||
constructor(
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
|
||||
@Inject(Vendor.name)
|
||||
private readonly vendorModel: TenantModelProxy<typeof Vendor>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Changes the opening balance of the given customer.
|
||||
* @param {number} vendorId
|
||||
* @param {IVendorOpeningBalanceEditDTO} openingBalanceEditDTO
|
||||
* @returns {Promise<IVendor>}
|
||||
*/
|
||||
public async editOpeningBalance(
|
||||
vendorId: number,
|
||||
openingBalanceEditDTO: IVendorOpeningBalanceEditDTO,
|
||||
) {
|
||||
// Retrieves the old vendor or throw not found error.
|
||||
const oldVendor = await this.vendorModel()
|
||||
.query()
|
||||
.findById(vendorId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Mutates the customer opening balance under unit-of-work.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onVendorOpeingBalanceChanging` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.vendors.onOpeningBalanceChanging,
|
||||
{
|
||||
oldVendor,
|
||||
openingBalanceEditDTO,
|
||||
trx,
|
||||
} as IVendorOpeningBalanceEditingPayload,
|
||||
);
|
||||
|
||||
// Mutates the vendor on the storage.
|
||||
const vendor = await this.vendorModel()
|
||||
.query()
|
||||
.patchAndFetchById(vendorId, {
|
||||
...openingBalanceEditDTO,
|
||||
});
|
||||
|
||||
// Triggers `onVendorOpeingBalanceChanged` event.
|
||||
await this.eventPublisher.emitAsync(
|
||||
events.vendors.onOpeningBalanceChanged,
|
||||
{
|
||||
vendor,
|
||||
oldVendor,
|
||||
openingBalanceEditDTO,
|
||||
trx,
|
||||
} as IVendorOpeningBalanceEditedPayload,
|
||||
);
|
||||
|
||||
return vendor;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,67 @@
|
||||
import {
|
||||
IVendorEventEditedPayload,
|
||||
IVendorEventEditingPayload,
|
||||
} from '../types/Vendors.types';
|
||||
import { Knex } from 'knex';
|
||||
import { Inject, Injectable } from '@nestjs/common';
|
||||
import { CreateEditVendorDTOService } from './CreateEditVendorDTO';
|
||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||
import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
||||
import { Vendor } from '../models/Vendor';
|
||||
import { events } from '@/common/events/events';
|
||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||
import { EditVendorDto } from '../dtos/EditVendor.dto';
|
||||
|
||||
@Injectable()
|
||||
export class EditVendorService {
|
||||
constructor(
|
||||
private readonly eventPublisher: EventEmitter2,
|
||||
private readonly uow: UnitOfWork,
|
||||
private readonly transformDTO: CreateEditVendorDTOService,
|
||||
|
||||
@Inject(Vendor.name)
|
||||
private readonly vendorModel: TenantModelProxy<typeof Vendor>,
|
||||
) {}
|
||||
|
||||
/**
|
||||
* Edits details of the given vendor.
|
||||
* @param {number} vendorId -
|
||||
* @param {IVendorEditDTO} vendorDTO -
|
||||
* @returns {Promise<IVendor>}
|
||||
*/
|
||||
public async editVendor(vendorId: number, vendorDTO: EditVendorDto) {
|
||||
// Retrieve the vendor or throw not found error.
|
||||
const oldVendor = await this.vendorModel()
|
||||
.query()
|
||||
.findById(vendorId)
|
||||
.throwIfNotFound();
|
||||
|
||||
// Transforms vendor DTO to object.
|
||||
const vendorObj = this.transformDTO.transformEditDTO(vendorDTO);
|
||||
|
||||
// Edits vendor contact under unit-of-work environment.
|
||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||
// Triggers `onVendorEditing` event.
|
||||
await this.eventPublisher.emitAsync(events.vendors.onEditing, {
|
||||
trx,
|
||||
vendorDTO,
|
||||
} as IVendorEventEditingPayload);
|
||||
|
||||
// Edits the vendor contact.
|
||||
const vendor = await this.vendorModel()
|
||||
.query()
|
||||
.updateAndFetchById(vendorId, {
|
||||
...vendorObj,
|
||||
});
|
||||
|
||||
// Triggers `onVendorEdited` event.
|
||||
await this.eventPublisher.emitAsync(events.vendors.onEdited, {
|
||||
vendorId,
|
||||
vendor,
|
||||
trx,
|
||||
} as IVendorEventEditedPayload);
|
||||
|
||||
return vendor;
|
||||
});
|
||||
}
|
||||
}
|
||||
@@ -0,0 +1,16 @@
|
||||
import { Injectable } from '@nestjs/common';
|
||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||
import { ERRORS } from '../constants';
|
||||
|
||||
@Injectable()
|
||||
export class VendorValidators {
|
||||
/**
|
||||
* Validates the given vendor is not already activated.
|
||||
* @param {IVendor} vendor
|
||||
*/
|
||||
public validateNotAlreadyPublished = (vendor) => {
|
||||
if (vendor.active) {
|
||||
throw new ServiceError(ERRORS.VENDOR_ALREADY_ACTIVE);
|
||||
}
|
||||
};
|
||||
}
|
||||
Reference in New Issue
Block a user