mirror of
https://github.com/bigcapitalhq/bigcapital.git
synced 2026-02-19 14:20:31 +00:00
refactor: api validation schema
This commit is contained in:
@@ -0,0 +1,29 @@
|
|||||||
|
import {
|
||||||
|
PipeTransform,
|
||||||
|
Injectable,
|
||||||
|
ArgumentMetadata,
|
||||||
|
BadRequestException,
|
||||||
|
} from '@nestjs/common';
|
||||||
|
import { validate } from 'class-validator';
|
||||||
|
import { plainToInstance } from 'class-transformer';
|
||||||
|
|
||||||
|
@Injectable()
|
||||||
|
export class ValidationPipe implements PipeTransform<any> {
|
||||||
|
async transform(value: any, { metatype }: ArgumentMetadata) {
|
||||||
|
if (!metatype || !this.toValidate(metatype)) {
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
const object = plainToInstance(metatype, value);
|
||||||
|
const errors = await validate(object);
|
||||||
|
|
||||||
|
if (errors.length > 0) {
|
||||||
|
throw new BadRequestException(errors);
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
private toValidate(metatype: Function): boolean {
|
||||||
|
const types: Function[] = [String, Boolean, Number, Array, Object];
|
||||||
|
return !types.includes(metatype);
|
||||||
|
}
|
||||||
|
}
|
||||||
@@ -4,6 +4,7 @@ import { ClsMiddleware } from 'nestjs-cls';
|
|||||||
import './utils/moment-mysql';
|
import './utils/moment-mysql';
|
||||||
import { AppModule } from './modules/App/App.module';
|
import { AppModule } from './modules/App/App.module';
|
||||||
import { ServiceErrorFilter } from './common/filters/service-error.filter';
|
import { ServiceErrorFilter } from './common/filters/service-error.filter';
|
||||||
|
import { ValidationPipe } from './common/pipes/ClassValidation.pipe';
|
||||||
|
|
||||||
async function bootstrap() {
|
async function bootstrap() {
|
||||||
const app = await NestFactory.create(AppModule);
|
const app = await NestFactory.create(AppModule);
|
||||||
@@ -12,6 +13,9 @@ async function bootstrap() {
|
|||||||
// create and mount the middleware manually here
|
// create and mount the middleware manually here
|
||||||
app.use(new ClsMiddleware({}).use);
|
app.use(new ClsMiddleware({}).use);
|
||||||
|
|
||||||
|
// use the validation pipe globally
|
||||||
|
app.useGlobalPipes(new ValidationPipe());
|
||||||
|
|
||||||
const config = new DocumentBuilder()
|
const config = new DocumentBuilder()
|
||||||
.setTitle('Bigcapital')
|
.setTitle('Bigcapital')
|
||||||
.setDescription('Financial accounting software')
|
.setDescription('Financial accounting software')
|
||||||
|
|||||||
@@ -14,8 +14,6 @@ import { EditAccountDTO } from './EditAccount.dto';
|
|||||||
import { PublicRoute } from '../Auth/Jwt.guard';
|
import { PublicRoute } from '../Auth/Jwt.guard';
|
||||||
import { IAccountsFilter, IAccountsTransactionsFilter } from './Accounts.types';
|
import { IAccountsFilter, IAccountsTransactionsFilter } from './Accounts.types';
|
||||||
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
// import { IAccountsFilter, IAccountsTransactionsFilter } from './Accounts.types';
|
|
||||||
// import { ZodValidationPipe } from '@/common/pipes/ZodValidation.pipe';
|
|
||||||
|
|
||||||
@Controller('accounts')
|
@Controller('accounts')
|
||||||
@ApiTags('accounts')
|
@ApiTags('accounts')
|
||||||
|
|||||||
@@ -8,7 +8,7 @@ import {
|
|||||||
Param,
|
Param,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { BranchesApplication } from './BranchesApplication.service';
|
import { BranchesApplication } from './BranchesApplication.service';
|
||||||
import { ICreateBranchDTO, IEditBranchDTO } from './Branches.types';
|
import { CreateBranchDto, EditBranchDto } from './dtos/Branch.dto';
|
||||||
import { PublicRoute } from '../Auth/Jwt.guard';
|
import { PublicRoute } from '../Auth/Jwt.guard';
|
||||||
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
|
|
||||||
@@ -46,7 +46,7 @@ export class BranchesController {
|
|||||||
description: 'The branch has been successfully created.',
|
description: 'The branch has been successfully created.',
|
||||||
})
|
})
|
||||||
@ApiResponse({ status: 404, description: 'The branch not found.' })
|
@ApiResponse({ status: 404, description: 'The branch not found.' })
|
||||||
createBranch(@Body() createBranchDTO: ICreateBranchDTO) {
|
createBranch(@Body() createBranchDTO: CreateBranchDto) {
|
||||||
return this.branchesApplication.createBranch(createBranchDTO);
|
return this.branchesApplication.createBranch(createBranchDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -57,7 +57,7 @@ export class BranchesController {
|
|||||||
description: 'The branch has been successfully edited.',
|
description: 'The branch has been successfully edited.',
|
||||||
})
|
})
|
||||||
@ApiResponse({ status: 404, description: 'The branch not found.' })
|
@ApiResponse({ status: 404, description: 'The branch not found.' })
|
||||||
editBranch(@Param('id') id: string, @Body() editBranchDTO: IEditBranchDTO) {
|
editBranch(@Param('id') id: string, @Body() editBranchDTO: EditBranchDto) {
|
||||||
return this.branchesApplication.editBranch(Number(id), editBranchDTO);
|
return this.branchesApplication.editBranch(Number(id), editBranchDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { GetBranchesService } from './queries/GetBranches.service';
|
|||||||
import { MarkBranchAsPrimaryService } from './commands/MarkBranchAsPrimary.service';
|
import { MarkBranchAsPrimaryService } from './commands/MarkBranchAsPrimary.service';
|
||||||
import { Branch } from './models/Branch.model';
|
import { Branch } from './models/Branch.model';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { CreateBranchDto, EditBranchDto } from './dtos/Branch.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class BranchesApplication {
|
export class BranchesApplication {
|
||||||
@@ -27,8 +28,7 @@ export class BranchesApplication {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Retrieves branches list.
|
* Retrieves branches list.
|
||||||
* @param {number} tenantId
|
* @returns {Branch[]}
|
||||||
* @returns {IBranch}
|
|
||||||
*/
|
*/
|
||||||
public getBranches = (): Promise<Branch[]> => {
|
public getBranches = (): Promise<Branch[]> => {
|
||||||
return this.getBranchesService.getBranches();
|
return this.getBranchesService.getBranches();
|
||||||
@@ -50,7 +50,7 @@ export class BranchesApplication {
|
|||||||
* @returns {Promise<IBranch>}
|
* @returns {Promise<IBranch>}
|
||||||
*/
|
*/
|
||||||
public createBranch = (
|
public createBranch = (
|
||||||
createBranchDTO: ICreateBranchDTO,
|
createBranchDTO: CreateBranchDto,
|
||||||
): Promise<Branch> => {
|
): Promise<Branch> => {
|
||||||
return this.createBranchService.createBranch(createBranchDTO);
|
return this.createBranchService.createBranch(createBranchDTO);
|
||||||
};
|
};
|
||||||
@@ -63,7 +63,7 @@ export class BranchesApplication {
|
|||||||
*/
|
*/
|
||||||
public editBranch = (
|
public editBranch = (
|
||||||
branchId: number,
|
branchId: number,
|
||||||
editBranchDTO: IEditBranchDTO,
|
editBranchDTO: EditBranchDto,
|
||||||
): Promise<Branch> => {
|
): Promise<Branch> => {
|
||||||
return this.editBranchService.editBranch(branchId, editBranchDTO);
|
return this.editBranchService.editBranch(branchId, editBranchDTO);
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import {
|
import { IBranchCreatedPayload, IBranchCreatePayload } from '../Branches.types';
|
||||||
IBranchCreatedPayload,
|
|
||||||
IBranchCreatePayload,
|
|
||||||
ICreateBranchDTO,
|
|
||||||
} from '../Branches.types';
|
|
||||||
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { Branch } from '../models/Branch.model';
|
import { Branch } from '../models/Branch.model';
|
||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { CreateBranchDto } from '../dtos/Branch.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateBranchService {
|
export class CreateBranchService {
|
||||||
@@ -28,11 +25,11 @@ export class CreateBranchService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Creates a new branch.
|
* Creates a new branch.
|
||||||
* @param {ICreateBranchDTO} createBranchDTO
|
* @param {CreateBranchDto} createBranchDTO
|
||||||
* @returns {Promise<IBranch>}
|
* @returns {Promise<Branch>}
|
||||||
*/
|
*/
|
||||||
public createBranch = async (
|
public createBranch = async (
|
||||||
createBranchDTO: ICreateBranchDTO,
|
createBranchDTO: CreateBranchDto,
|
||||||
): Promise<Branch> => {
|
): Promise<Branch> => {
|
||||||
// Creates a new branch under unit-of-work.
|
// Creates a new branch under unit-of-work.
|
||||||
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
return this.uow.withTransaction(async (trx: Knex.Transaction) => {
|
||||||
|
|||||||
@@ -1,15 +1,12 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { Knex } from 'knex';
|
import { Knex } from 'knex';
|
||||||
import {
|
import { IBranchEditedPayload, IBranchEditPayload } from '../Branches.types';
|
||||||
IBranchEditedPayload,
|
|
||||||
IBranchEditPayload,
|
|
||||||
IEditBranchDTO,
|
|
||||||
} from '../Branches.types';
|
|
||||||
import { Branch } from '../models/Branch.model';
|
import { Branch } from '../models/Branch.model';
|
||||||
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
import { UnitOfWork } from '../../Tenancy/TenancyDB/UnitOfWork.service';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { EditBranchDto } from '../dtos/Branch.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EditBranchService {
|
export class EditBranchService {
|
||||||
@@ -27,7 +24,7 @@ export class EditBranchService {
|
|||||||
*/
|
*/
|
||||||
public editBranch = async (
|
public editBranch = async (
|
||||||
branchId: number,
|
branchId: number,
|
||||||
editBranchDTO: IEditBranchDTO,
|
editBranchDTO: EditBranchDto,
|
||||||
) => {
|
) => {
|
||||||
// Retrieves the old branch or throw not found service error.
|
// Retrieves the old branch or throw not found service error.
|
||||||
const oldBranch = await this.branchModel()
|
const oldBranch = await this.branchModel()
|
||||||
|
|||||||
55
packages/server-nest/src/modules/Branches/dtos/Branch.dto.ts
Normal file
55
packages/server-nest/src/modules/Branches/dtos/Branch.dto.ts
Normal file
@@ -0,0 +1,55 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import {
|
||||||
|
IsEmail,
|
||||||
|
IsNotEmpty,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
IsUrl,
|
||||||
|
} from 'class-validator';
|
||||||
|
|
||||||
|
class CommandBranchDto {
|
||||||
|
@ApiProperty({ description: 'Branch name' })
|
||||||
|
@IsNotEmpty()
|
||||||
|
@IsString()
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Branch code' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
code?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Branch address' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
address?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Branch city' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
city?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Branch country' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
country?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Branch phone number' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
phone_number?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Branch email' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsEmail()
|
||||||
|
@IsString()
|
||||||
|
email?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Branch website' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsUrl()
|
||||||
|
@IsString()
|
||||||
|
website?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateBranchDto extends CommandBranchDto {}
|
||||||
|
export class EditBranchDto extends CommandBranchDto {}
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
export class CreateExpenseDto {}
|
||||||
|
|
||||||
|
export class EditExpenseDto {}
|
||||||
@@ -0,0 +1,6 @@
|
|||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
export class CreateItemCategoryDto {}
|
||||||
|
|
||||||
|
export class EditItemCategoryDto {}
|
||||||
@@ -8,6 +8,7 @@ import { ItemsValidators } from './ItemValidator.service';
|
|||||||
import { Item } from './models/Item';
|
import { Item } from './models/Item';
|
||||||
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
||||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||||
|
import { CreateItemDto } from './dtos/Item.dto';
|
||||||
|
|
||||||
@Injectable({ scope: Scope.REQUEST })
|
@Injectable({ scope: Scope.REQUEST })
|
||||||
export class CreateItemService {
|
export class CreateItemService {
|
||||||
@@ -32,7 +33,7 @@ export class CreateItemService {
|
|||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {IItemDTO} itemDTO
|
* @param {IItemDTO} itemDTO
|
||||||
*/
|
*/
|
||||||
async authorize(itemDTO: IItemDTO) {
|
async authorize(itemDTO: CreateItemDto) {
|
||||||
// Validate whether the given item name already exists on the storage.
|
// Validate whether the given item name already exists on the storage.
|
||||||
await this.validators.validateItemNameUniquiness(itemDTO.name);
|
await this.validators.validateItemNameUniquiness(itemDTO.name);
|
||||||
|
|
||||||
@@ -76,10 +77,10 @@ export class CreateItemService {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Transforms the item DTO to model.
|
* Transforms the item DTO to model.
|
||||||
* @param {IItemDTO} itemDTO - Item DTO.
|
* @param {CreateItemDto} itemDTO - Item DTO.
|
||||||
* @return {IItem}
|
* @return {IItem}
|
||||||
*/
|
*/
|
||||||
private transformNewItemDTOToModel(itemDTO: IItemDTO) {
|
private transformNewItemDTOToModel(itemDTO: CreateItemDto) {
|
||||||
return {
|
return {
|
||||||
...itemDTO,
|
...itemDTO,
|
||||||
active: defaultTo(itemDTO.active, 1),
|
active: defaultTo(itemDTO.active, 1),
|
||||||
@@ -93,7 +94,7 @@ export class CreateItemService {
|
|||||||
* @return {Promise<number>} - The created item id.
|
* @return {Promise<number>} - The created item id.
|
||||||
*/
|
*/
|
||||||
public async createItem(
|
public async createItem(
|
||||||
itemDTO: IItemDTO,
|
itemDTO: CreateItemDto,
|
||||||
trx?: Knex.Transaction,
|
trx?: Knex.Transaction,
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
// Authorize the item before creating.
|
// Authorize the item before creating.
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { ItemsValidators } from './ItemValidator.service';
|
|||||||
import { Item } from './models/Item';
|
import { Item } from './models/Item';
|
||||||
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
import { UnitOfWork } from '../Tenancy/TenancyDB/UnitOfWork.service';
|
||||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||||
|
import { EditItemDto } from './dtos/Item.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EditItemService {
|
export class EditItemService {
|
||||||
@@ -31,7 +32,7 @@ export class EditItemService {
|
|||||||
* @param {IItemDTO} itemDTO
|
* @param {IItemDTO} itemDTO
|
||||||
* @param {Item} oldItem
|
* @param {Item} oldItem
|
||||||
*/
|
*/
|
||||||
async authorize(itemDTO: IItemDTO, oldItem: Item) {
|
async authorize(itemDTO: EditItemDto, oldItem: Item) {
|
||||||
// Validate edit item type from inventory type.
|
// Validate edit item type from inventory type.
|
||||||
this.validators.validateEditItemFromInventory(itemDTO, oldItem);
|
this.validators.validateEditItemFromInventory(itemDTO, oldItem);
|
||||||
|
|
||||||
@@ -86,7 +87,7 @@ export class EditItemService {
|
|||||||
* @return {Partial<Item>}
|
* @return {Partial<Item>}
|
||||||
*/
|
*/
|
||||||
private transformEditItemDTOToModel(
|
private transformEditItemDTOToModel(
|
||||||
itemDTO: IItemDTO,
|
itemDTO: EditItemDto,
|
||||||
oldItem: Item,
|
oldItem: Item,
|
||||||
): Partial<Item> {
|
): Partial<Item> {
|
||||||
return {
|
return {
|
||||||
@@ -107,7 +108,7 @@ export class EditItemService {
|
|||||||
*/
|
*/
|
||||||
public async editItem(
|
public async editItem(
|
||||||
itemId: number,
|
itemId: number,
|
||||||
itemDTO: IItemDTO,
|
itemDTO: EditItemDto,
|
||||||
trx?: Knex.Transaction,
|
trx?: Knex.Transaction,
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
// Validates the given item existance on the storage.
|
// Validates the given item existance on the storage.
|
||||||
|
|||||||
@@ -23,6 +23,7 @@ import {
|
|||||||
} from '@nestjs/swagger';
|
} from '@nestjs/swagger';
|
||||||
import { IItemsFilter } from './types/Items.types';
|
import { IItemsFilter } from './types/Items.types';
|
||||||
import { IItemDTO } from '@/interfaces/Item';
|
import { IItemDTO } from '@/interfaces/Item';
|
||||||
|
import { CreateItemDto, EditItemDto } from './dtos/Item.dto';
|
||||||
|
|
||||||
@Controller('/items')
|
@Controller('/items')
|
||||||
@UseGuards(SubscriptionGuard)
|
@UseGuards(SubscriptionGuard)
|
||||||
@@ -120,7 +121,7 @@ export class ItemsController extends TenantController {
|
|||||||
// @UsePipes(new ZodValidationPipe(createItemSchema))
|
// @UsePipes(new ZodValidationPipe(createItemSchema))
|
||||||
async editItem(
|
async editItem(
|
||||||
@Param('id') id: string,
|
@Param('id') id: string,
|
||||||
@Body() editItemDto: IItemDTO,
|
@Body() editItemDto: EditItemDto,
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
const itemId = parseInt(id, 10);
|
const itemId = parseInt(id, 10);
|
||||||
return this.itemsApplication.editItem(itemId, editItemDto);
|
return this.itemsApplication.editItem(itemId, editItemDto);
|
||||||
@@ -138,7 +139,7 @@ export class ItemsController extends TenantController {
|
|||||||
description: 'The item has been successfully created.',
|
description: 'The item has been successfully created.',
|
||||||
})
|
})
|
||||||
// @UsePipes(new ZodValidationPipe(createItemSchema))
|
// @UsePipes(new ZodValidationPipe(createItemSchema))
|
||||||
async createItem(@Body() createItemDto: IItemDTO): Promise<number> {
|
async createItem(@Body() createItemDto: CreateItemDto): Promise<number> {
|
||||||
return this.itemsApplication.createItem(createItemDto);
|
return this.itemsApplication.createItem(createItemDto);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -182,8 +183,6 @@ export class ItemsController extends TenantController {
|
|||||||
description: 'The item id',
|
description: 'The item id',
|
||||||
})
|
})
|
||||||
async inactivateItem(@Param('id') id: string): Promise<void> {
|
async inactivateItem(@Param('id') id: string): Promise<void> {
|
||||||
console.log(id, 'XXXXXX');
|
|
||||||
|
|
||||||
const itemId = parseInt(id, 10);
|
const itemId = parseInt(id, 10);
|
||||||
return this.itemsApplication.inactivateItem(itemId);
|
return this.itemsApplication.inactivateItem(itemId);
|
||||||
}
|
}
|
||||||
@@ -243,7 +242,8 @@ export class ItemsController extends TenantController {
|
|||||||
})
|
})
|
||||||
@ApiResponse({
|
@ApiResponse({
|
||||||
status: 200,
|
status: 200,
|
||||||
description: 'The item associated invoices transactions have been successfully retrieved.',
|
description:
|
||||||
|
'The item associated invoices transactions have been successfully retrieved.',
|
||||||
})
|
})
|
||||||
@ApiResponse({ status: 404, description: 'The item not found.' })
|
@ApiResponse({ status: 404, description: 'The item not found.' })
|
||||||
@ApiParam({
|
@ApiParam({
|
||||||
|
|||||||
@@ -5,7 +5,6 @@ import {
|
|||||||
ACCOUNT_TYPE,
|
ACCOUNT_TYPE,
|
||||||
} from '@/constants/accounts';
|
} from '@/constants/accounts';
|
||||||
import { ServiceError } from './ServiceError';
|
import { ServiceError } from './ServiceError';
|
||||||
import { IItemDTO } from '@/interfaces/Item';
|
|
||||||
import { ERRORS } from './Items.constants';
|
import { ERRORS } from './Items.constants';
|
||||||
import { Item } from './models/Item';
|
import { Item } from './models/Item';
|
||||||
import { Account } from '../Accounts/models/Account.model';
|
import { Account } from '../Accounts/models/Account.model';
|
||||||
@@ -15,6 +14,7 @@ import { ItemCategory } from '../ItemCategories/models/ItemCategory.model';
|
|||||||
import { AccountTransaction } from '../Accounts/models/AccountTransaction.model';
|
import { AccountTransaction } from '../Accounts/models/AccountTransaction.model';
|
||||||
import { InventoryAdjustment } from '../InventoryAdjutments/models/InventoryAdjustment';
|
import { InventoryAdjustment } from '../InventoryAdjutments/models/InventoryAdjustment';
|
||||||
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
||||||
|
import { CreateItemDto, EditItemDto } from './dtos/Item.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ItemsValidators {
|
export class ItemsValidators {
|
||||||
@@ -229,7 +229,7 @@ export class ItemsValidators {
|
|||||||
*/
|
*/
|
||||||
public async validateEditItemTypeToInventory(
|
public async validateEditItemTypeToInventory(
|
||||||
oldItem: Item,
|
oldItem: Item,
|
||||||
newItemDTO: IItemDTO,
|
newItemDTO: CreateItemDto | EditItemDto,
|
||||||
) {
|
) {
|
||||||
// We have no problem in case the item type not modified.
|
// We have no problem in case the item type not modified.
|
||||||
if (newItemDTO.type === oldItem.type || oldItem.type === 'inventory') {
|
if (newItemDTO.type === oldItem.type || oldItem.type === 'inventory') {
|
||||||
@@ -254,12 +254,12 @@ export class ItemsValidators {
|
|||||||
* Validate the item inventory account whether modified and item
|
* Validate the item inventory account whether modified and item
|
||||||
* has associated inventory transactions.
|
* has associated inventory transactions.
|
||||||
* @param {Item} oldItem - Old item.
|
* @param {Item} oldItem - Old item.
|
||||||
* @param {IItemDTO} newItemDTO - New item DTO.
|
* @param {CreateItemDto | EditItemDto} newItemDTO - New item DTO.
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
async validateItemInvnetoryAccountModified(
|
async validateItemInvnetoryAccountModified(
|
||||||
oldItem: Item,
|
oldItem: Item,
|
||||||
newItemDTO: IItemDTO,
|
newItemDTO: CreateItemDto | EditItemDto,
|
||||||
) {
|
) {
|
||||||
if (
|
if (
|
||||||
newItemDTO.type !== 'inventory' ||
|
newItemDTO.type !== 'inventory' ||
|
||||||
@@ -279,10 +279,13 @@ export class ItemsValidators {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate edit item type from inventory to another type that not allowed.
|
* Validate edit item type from inventory to another type that not allowed.
|
||||||
* @param {IItemDTO} itemDTO - Item DTO.
|
* @param {CreateItemDto | EditItemDto} itemDTO - Item DTO.
|
||||||
* @param {IItem} oldItem - Old item.
|
* @param {IItem} oldItem - Old item.
|
||||||
*/
|
*/
|
||||||
public validateEditItemFromInventory(itemDTO: IItemDTO, oldItem: Item) {
|
public validateEditItemFromInventory(
|
||||||
|
itemDTO: CreateItemDto | EditItemDto,
|
||||||
|
oldItem: Item,
|
||||||
|
) {
|
||||||
if (
|
if (
|
||||||
itemDTO.type &&
|
itemDTO.type &&
|
||||||
oldItem.type === 'inventory' &&
|
oldItem.type === 'inventory' &&
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { ItemTransactionsService } from './ItemTransactions.service';
|
|||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { GetItemsService } from './GetItems.service';
|
import { GetItemsService } from './GetItems.service';
|
||||||
import { IItemsFilter } from './types/Items.types';
|
import { IItemsFilter } from './types/Items.types';
|
||||||
|
import { EditItemDto, CreateItemDto } from './dtos/Item.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class ItemsApplicationService {
|
export class ItemsApplicationService {
|
||||||
@@ -32,7 +33,7 @@ export class ItemsApplicationService {
|
|||||||
* @return {Promise<number>} - The created item id.
|
* @return {Promise<number>} - The created item id.
|
||||||
*/
|
*/
|
||||||
async createItem(
|
async createItem(
|
||||||
createItemDto: IItemDTO,
|
createItemDto: CreateItemDto,
|
||||||
trx?: Knex.Transaction,
|
trx?: Knex.Transaction,
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
return this.createItemService.createItem(createItemDto);
|
return this.createItemService.createItem(createItemDto);
|
||||||
@@ -47,7 +48,7 @@ export class ItemsApplicationService {
|
|||||||
*/
|
*/
|
||||||
async editItem(
|
async editItem(
|
||||||
itemId: number,
|
itemId: number,
|
||||||
editItemDto: IItemDTO,
|
editItemDto: EditItemDto,
|
||||||
trx?: Knex.Transaction,
|
trx?: Knex.Transaction,
|
||||||
): Promise<number> {
|
): Promise<number> {
|
||||||
return this.editItemService.editItem(itemId, editItemDto, trx);
|
return this.editItemService.editItem(itemId, editItemDto, trx);
|
||||||
|
|||||||
109
packages/server-nest/src/modules/Items/dtos/Item.dto.ts
Normal file
109
packages/server-nest/src/modules/Items/dtos/Item.dto.ts
Normal file
@@ -0,0 +1,109 @@
|
|||||||
|
import {
|
||||||
|
IsString,
|
||||||
|
IsIn,
|
||||||
|
IsOptional,
|
||||||
|
IsBoolean,
|
||||||
|
IsNumber,
|
||||||
|
IsInt,
|
||||||
|
IsArray,
|
||||||
|
ValidateIf,
|
||||||
|
MaxLength,
|
||||||
|
Min,
|
||||||
|
Max,
|
||||||
|
IsNotEmpty,
|
||||||
|
} from 'class-validator';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
|
||||||
|
export class CommandItemDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@MaxLength(255)
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsIn(['service', 'non-inventory', 'inventory'])
|
||||||
|
type: 'service' | 'non-inventory' | 'inventory';
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@MaxLength(255)
|
||||||
|
code?: string;
|
||||||
|
|
||||||
|
// Purchase attributes
|
||||||
|
@IsOptional()
|
||||||
|
@IsBoolean()
|
||||||
|
purchasable?: boolean;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber({ maxDecimalPlaces: 3 })
|
||||||
|
@Min(0)
|
||||||
|
@ValidateIf((o) => o.purchasable === true)
|
||||||
|
costPrice?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
@ValidateIf((o) => o.purchasable === true)
|
||||||
|
costAccountId?: number;
|
||||||
|
|
||||||
|
// Sell attributes
|
||||||
|
@IsOptional()
|
||||||
|
@IsBoolean()
|
||||||
|
sellable?: boolean;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber({ maxDecimalPlaces: 3 })
|
||||||
|
@Min(0)
|
||||||
|
@ValidateIf((o) => o.sellable === true)
|
||||||
|
sellPrice?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
@ValidateIf((o) => o.sellable === true)
|
||||||
|
sellAccountId?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
@ValidateIf((o) => o.type === 'inventory')
|
||||||
|
inventoryAccountId?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
sellDescription?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
purchaseDescription?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
sellTaxRateId?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
purchaseTaxRateId?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
@Min(0)
|
||||||
|
categoryId?: number;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
note?: string;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsBoolean()
|
||||||
|
active?: boolean;
|
||||||
|
|
||||||
|
@IsOptional()
|
||||||
|
@IsArray()
|
||||||
|
@Type(() => Number)
|
||||||
|
@IsInt({ each: true })
|
||||||
|
mediaIds?: number[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateItemDto extends CommandItemDto {}
|
||||||
|
export class EditItemDto extends CommandItemDto {}
|
||||||
@@ -11,6 +11,7 @@ import { ManualJournalsApplication } from './ManualJournalsApplication.service';
|
|||||||
import { IManualJournalDTO } from './types/ManualJournals.types';
|
import { IManualJournalDTO } from './types/ManualJournals.types';
|
||||||
import { PublicRoute } from '../Auth/Jwt.guard';
|
import { PublicRoute } from '../Auth/Jwt.guard';
|
||||||
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
|
||||||
|
import { CreateManualJournalDto, EditManualJournalDto } from './dtos/ManualJournal.dto';
|
||||||
|
|
||||||
@Controller('manual-journals')
|
@Controller('manual-journals')
|
||||||
@ApiTags('manual-journals')
|
@ApiTags('manual-journals')
|
||||||
@@ -20,7 +21,7 @@ export class ManualJournalsController {
|
|||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@ApiOperation({ summary: 'Create a new manual journal.' })
|
@ApiOperation({ summary: 'Create a new manual journal.' })
|
||||||
public createManualJournal(@Body() manualJournalDTO: IManualJournalDTO) {
|
public createManualJournal(@Body() manualJournalDTO: CreateManualJournalDto) {
|
||||||
return this.manualJournalsApplication.createManualJournal(manualJournalDTO);
|
return this.manualJournalsApplication.createManualJournal(manualJournalDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -39,7 +40,7 @@ export class ManualJournalsController {
|
|||||||
})
|
})
|
||||||
public editManualJournal(
|
public editManualJournal(
|
||||||
@Param('id') manualJournalId: number,
|
@Param('id') manualJournalId: number,
|
||||||
@Body() manualJournalDTO: IManualJournalDTO,
|
@Body() manualJournalDTO: EditManualJournalDto
|
||||||
) {
|
) {
|
||||||
return this.manualJournalsApplication.editManualJournal(
|
return this.manualJournalsApplication.editManualJournal(
|
||||||
manualJournalId,
|
manualJournalId,
|
||||||
|
|||||||
@@ -5,6 +5,7 @@ import { PublishManualJournal } from './commands/PublishManualJournal.service';
|
|||||||
import { GetManualJournal } from './queries/GetManualJournal.service';
|
import { GetManualJournal } from './queries/GetManualJournal.service';
|
||||||
import { DeleteManualJournalService } from './commands/DeleteManualJournal.service';
|
import { DeleteManualJournalService } from './commands/DeleteManualJournal.service';
|
||||||
import { IManualJournalDTO, } from './types/ManualJournals.types';
|
import { IManualJournalDTO, } from './types/ManualJournals.types';
|
||||||
|
import { CreateManualJournalDto, EditManualJournalDto } from './dtos/ManualJournal.dto';
|
||||||
// import { GetManualJournals } from './queries/GetManualJournals';
|
// import { GetManualJournals } from './queries/GetManualJournals';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
@@ -24,7 +25,7 @@ export class ManualJournalsApplication {
|
|||||||
* @param {IManualJournalDTO} manualJournalDTO
|
* @param {IManualJournalDTO} manualJournalDTO
|
||||||
* @returns {Promise<IManualJournal>}
|
* @returns {Promise<IManualJournal>}
|
||||||
*/
|
*/
|
||||||
public createManualJournal = (manualJournalDTO: IManualJournalDTO) => {
|
public createManualJournal = (manualJournalDTO: CreateManualJournalDto) => {
|
||||||
return this.createManualJournalService.makeJournalEntries(manualJournalDTO);
|
return this.createManualJournalService.makeJournalEntries(manualJournalDTO);
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -35,7 +36,7 @@ export class ManualJournalsApplication {
|
|||||||
*/
|
*/
|
||||||
public editManualJournal = (
|
public editManualJournal = (
|
||||||
manualJournalId: number,
|
manualJournalId: number,
|
||||||
manualJournalDTO: IManualJournalDTO,
|
manualJournalDTO: EditManualJournalDto,
|
||||||
) => {
|
) => {
|
||||||
return this.editManualJournalService.editJournalEntries(
|
return this.editManualJournalService.editJournalEntries(
|
||||||
manualJournalId,
|
manualJournalId,
|
||||||
|
|||||||
@@ -1,15 +1,16 @@
|
|||||||
import { Inject, Injectable } from '@nestjs/common';
|
import { Inject, Injectable } from '@nestjs/common';
|
||||||
import { difference, isEmpty, round, sumBy } from 'lodash';
|
import { difference, isEmpty, round, sumBy } from 'lodash';
|
||||||
import {
|
|
||||||
IManualJournalDTO,
|
|
||||||
IManualJournalEntryDTO,
|
|
||||||
} from '../types/ManualJournals.types';
|
|
||||||
import { ERRORS } from '../constants';
|
import { ERRORS } from '../constants';
|
||||||
import { ServiceError } from '@/modules/Items/ServiceError';
|
import { ServiceError } from '@/modules/Items/ServiceError';
|
||||||
import { Account } from '@/modules/Accounts/models/Account.model';
|
import { Account } from '@/modules/Accounts/models/Account.model';
|
||||||
import { ManualJournal } from '../models/ManualJournal';
|
import { ManualJournal } from '../models/ManualJournal';
|
||||||
import { Contact } from '@/modules/Contacts/models/Contact';
|
import { Contact } from '@/modules/Contacts/models/Contact';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import {
|
||||||
|
CreateManualJournalDto,
|
||||||
|
EditManualJournalDto,
|
||||||
|
ManualJournalEntryDto,
|
||||||
|
} from '../dtos/ManualJournal.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CommandManualJournalValidators {
|
export class CommandManualJournalValidators {
|
||||||
@@ -26,9 +27,11 @@ export class CommandManualJournalValidators {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate manual journal credit and debit should be equal.
|
* Validate manual journal credit and debit should be equal.
|
||||||
* @param {IManualJournalDTO} manualJournalDTO
|
* @param {CreateManualJournalDto | EditManualJournalDto} manualJournalDTO
|
||||||
*/
|
*/
|
||||||
public valdiateCreditDebitTotalEquals(manualJournalDTO: IManualJournalDTO) {
|
public valdiateCreditDebitTotalEquals(
|
||||||
|
manualJournalDTO: CreateManualJournalDto | EditManualJournalDto,
|
||||||
|
) {
|
||||||
const totalCredit = round(
|
const totalCredit = round(
|
||||||
sumBy(manualJournalDTO.entries, (entry) => entry.credit || 0),
|
sumBy(manualJournalDTO.entries, (entry) => entry.credit || 0),
|
||||||
2,
|
2,
|
||||||
@@ -48,9 +51,11 @@ export class CommandManualJournalValidators {
|
|||||||
/**
|
/**
|
||||||
* Validate manual entries accounts existance on the storage.
|
* Validate manual entries accounts existance on the storage.
|
||||||
* @param {number} tenantId -
|
* @param {number} tenantId -
|
||||||
* @param {IManualJournalDTO} manualJournalDTO -
|
* @param {CreateManualJournalDto | EditManualJournalDto} manualJournalDTO -
|
||||||
*/
|
*/
|
||||||
public async validateAccountsExistance(manualJournalDTO: IManualJournalDTO) {
|
public async validateAccountsExistance(
|
||||||
|
manualJournalDTO: CreateManualJournalDto | EditManualJournalDto,
|
||||||
|
) {
|
||||||
const manualAccountsIds = manualJournalDTO.entries.map((e) => e.accountId);
|
const manualAccountsIds = manualJournalDTO.entries.map((e) => e.accountId);
|
||||||
const accounts = await this.accountModel()
|
const accounts = await this.accountModel()
|
||||||
.query()
|
.query()
|
||||||
@@ -66,7 +71,7 @@ export class CommandManualJournalValidators {
|
|||||||
/**
|
/**
|
||||||
* Validate manual journal number unique.
|
* Validate manual journal number unique.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {IManualJournalDTO} manualJournalDTO
|
* @param {CreateManualJournalDto | EditManualJournalDto} manualJournalDTO
|
||||||
*/
|
*/
|
||||||
public async validateManualJournalNoUnique(
|
public async validateManualJournalNoUnique(
|
||||||
journalNumber: string,
|
journalNumber: string,
|
||||||
@@ -91,12 +96,12 @@ export class CommandManualJournalValidators {
|
|||||||
/**
|
/**
|
||||||
* Validate accounts with contact type.
|
* Validate accounts with contact type.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {IManualJournalDTO} manualJournalDTO
|
* @param {CreateManualJournalDto | EditManualJournalDto} manualJournalDTO
|
||||||
* @param {string} accountBySlug
|
* @param {string} accountBySlug
|
||||||
* @param {string} contactType
|
* @param {string} contactType
|
||||||
*/
|
*/
|
||||||
public async validateAccountWithContactType(
|
public async validateAccountWithContactType(
|
||||||
entriesDTO: IManualJournalEntryDTO[],
|
entriesDTO: ManualJournalEntryDto[],
|
||||||
accountBySlug: string,
|
accountBySlug: string,
|
||||||
contactType: string,
|
contactType: string,
|
||||||
): Promise<void | ServiceError> {
|
): Promise<void | ServiceError> {
|
||||||
@@ -147,10 +152,10 @@ export class CommandManualJournalValidators {
|
|||||||
/**
|
/**
|
||||||
* Dynamic validates accounts with contacts.
|
* Dynamic validates accounts with contacts.
|
||||||
* @param {number} tenantId
|
* @param {number} tenantId
|
||||||
* @param {IManualJournalDTO} manualJournalDTO
|
* @param {CreateManualJournalDto | EditManualJournalDto} manualJournalDTO
|
||||||
*/
|
*/
|
||||||
public async dynamicValidateAccountsWithContactType(
|
public async dynamicValidateAccountsWithContactType(
|
||||||
entriesDTO: IManualJournalEntryDTO[],
|
entriesDTO: ManualJournalEntryDto[],
|
||||||
): Promise<any> {
|
): Promise<any> {
|
||||||
return Promise.all([
|
return Promise.all([
|
||||||
this.validateAccountWithContactType(
|
this.validateAccountWithContactType(
|
||||||
@@ -182,9 +187,11 @@ export class CommandManualJournalValidators {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Validate entries contacts existance.
|
* Validate entries contacts existance.
|
||||||
* @param {IManualJournalDTO} manualJournalDTO
|
* @param {CreateManualJournalDto | EditManualJournalDto} manualJournalDTO
|
||||||
*/
|
*/
|
||||||
public async validateContactsExistance(manualJournalDTO: IManualJournalDTO) {
|
public async validateContactsExistance(
|
||||||
|
manualJournalDTO: CreateManualJournalDto | EditManualJournalDto,
|
||||||
|
) {
|
||||||
// Filters the entries that have contact only.
|
// Filters the entries that have contact only.
|
||||||
const entriesContactPairs = manualJournalDTO.entries.filter(
|
const entriesContactPairs = manualJournalDTO.entries.filter(
|
||||||
(entry) => entry.contactId,
|
(entry) => entry.contactId,
|
||||||
@@ -268,10 +275,10 @@ export class CommandManualJournalValidators {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
*
|
||||||
* @param {IManualJournalDTO} manualJournalDTO
|
* @param {CreateManualJournalDto | EditManualJournalDto} manualJournalDTO
|
||||||
*/
|
*/
|
||||||
public validateJournalCurrencyWithAccountsCurrency = async (
|
public validateJournalCurrencyWithAccountsCurrency = async (
|
||||||
manualJournalDTO: IManualJournalDTO,
|
manualJournalDTO: CreateManualJournalDto | EditManualJournalDto,
|
||||||
baseCurrency: string,
|
baseCurrency: string,
|
||||||
) => {
|
) => {
|
||||||
const accountsIds = manualJournalDTO.entries.map((e) => e.accountId);
|
const accountsIds = manualJournalDTO.entries.map((e) => e.accountId);
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ import { assocItemEntriesDefaultIndex } from '@/utils/associate-item-entries-ind
|
|||||||
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
import { TenancyContext } from '@/modules/Tenancy/TenancyContext.service';
|
||||||
import { ManualJournalBranchesDTOTransformer } from '@/modules/Branches/integrations/ManualJournals/ManualJournalDTOTransformer.service';
|
import { ManualJournalBranchesDTOTransformer } from '@/modules/Branches/integrations/ManualJournals/ManualJournalDTOTransformer.service';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { CreateManualJournalDto } from '../dtos/ManualJournal.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateManualJournalService {
|
export class CreateManualJournalService {
|
||||||
@@ -39,7 +40,7 @@ export class CreateManualJournalService {
|
|||||||
* @returns {Promise<ManualJournal>}
|
* @returns {Promise<ManualJournal>}
|
||||||
*/
|
*/
|
||||||
private async transformNewDTOToModel(
|
private async transformNewDTOToModel(
|
||||||
manualJournalDTO: IManualJournalDTO,
|
manualJournalDTO: CreateManualJournalDto,
|
||||||
): Promise<ManualJournal> {
|
): Promise<ManualJournal> {
|
||||||
const amount = sumBy(manualJournalDTO.entries, 'credit') || 0;
|
const amount = sumBy(manualJournalDTO.entries, 'credit') || 0;
|
||||||
const date = moment(manualJournalDTO.date).format('YYYY-MM-DD');
|
const date = moment(manualJournalDTO.date).format('YYYY-MM-DD');
|
||||||
@@ -84,7 +85,7 @@ export class CreateManualJournalService {
|
|||||||
* @param {IManualJournalDTO} manualJournalDTO
|
* @param {IManualJournalDTO} manualJournalDTO
|
||||||
* @param {ISystemUser} authorizedUser
|
* @param {ISystemUser} authorizedUser
|
||||||
*/
|
*/
|
||||||
private authorize = async (manualJournalDTO: IManualJournalDTO) => {
|
private authorize = async (manualJournalDTO: CreateManualJournalDto) => {
|
||||||
const tenant = await this.tenancyContext.getTenant(true);
|
const tenant = await this.tenancyContext.getTenant(true);
|
||||||
|
|
||||||
// Validate the total credit should equals debit.
|
// Validate the total credit should equals debit.
|
||||||
@@ -124,7 +125,7 @@ export class CreateManualJournalService {
|
|||||||
* @param {ISystemUser} authorizedUser
|
* @param {ISystemUser} authorizedUser
|
||||||
*/
|
*/
|
||||||
public makeJournalEntries = async (
|
public makeJournalEntries = async (
|
||||||
manualJournalDTO: IManualJournalDTO,
|
manualJournalDTO: CreateManualJournalDto,
|
||||||
trx?: Knex.Transaction,
|
trx?: Knex.Transaction,
|
||||||
): Promise<ManualJournal> => {
|
): Promise<ManualJournal> => {
|
||||||
// Authorize manual journal creating.
|
// Authorize manual journal creating.
|
||||||
|
|||||||
@@ -13,6 +13,7 @@ import { CommandManualJournalValidators } from './CommandManualJournalValidators
|
|||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { ManualJournal } from '../models/ManualJournal';
|
import { ManualJournal } from '../models/ManualJournal';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { EditManualJournalDto } from '../dtos/ManualJournal.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EditManualJournal {
|
export class EditManualJournal {
|
||||||
@@ -32,7 +33,7 @@ export class EditManualJournal {
|
|||||||
*/
|
*/
|
||||||
private authorize = async (
|
private authorize = async (
|
||||||
manualJournalId: number,
|
manualJournalId: number,
|
||||||
manualJournalDTO: IManualJournalDTO,
|
manualJournalDTO: EditManualJournalDto,
|
||||||
) => {
|
) => {
|
||||||
// Validates the total credit and debit to be equals.
|
// Validates the total credit and debit to be equals.
|
||||||
this.validator.valdiateCreditDebitTotalEquals(manualJournalDTO);
|
this.validator.valdiateCreditDebitTotalEquals(manualJournalDTO);
|
||||||
@@ -62,7 +63,7 @@ export class EditManualJournal {
|
|||||||
* @param {IManualJournal} oldManualJournal
|
* @param {IManualJournal} oldManualJournal
|
||||||
*/
|
*/
|
||||||
private transformEditDTOToModel = (
|
private transformEditDTOToModel = (
|
||||||
manualJournalDTO: IManualJournalDTO,
|
manualJournalDTO: EditManualJournalDto,
|
||||||
oldManualJournal: ManualJournal,
|
oldManualJournal: ManualJournal,
|
||||||
) => {
|
) => {
|
||||||
const amount = sumBy(manualJournalDTO.entries, 'credit') || 0;
|
const amount = sumBy(manualJournalDTO.entries, 'credit') || 0;
|
||||||
@@ -86,7 +87,7 @@ export class EditManualJournal {
|
|||||||
*/
|
*/
|
||||||
public async editJournalEntries(
|
public async editJournalEntries(
|
||||||
manualJournalId: number,
|
manualJournalId: number,
|
||||||
manualJournalDTO: IManualJournalDTO,
|
manualJournalDTO: EditManualJournalDto,
|
||||||
): Promise<{
|
): Promise<{
|
||||||
manualJournal: ManualJournal;
|
manualJournal: ManualJournal;
|
||||||
oldManualJournal: ManualJournal;
|
oldManualJournal: ManualJournal;
|
||||||
|
|||||||
@@ -0,0 +1,130 @@
|
|||||||
|
import { ApiProperty, ApiPropertyOptional } from '@nestjs/swagger';
|
||||||
|
import { Type } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
IsArray,
|
||||||
|
IsBoolean,
|
||||||
|
IsDate,
|
||||||
|
IsInt,
|
||||||
|
IsNumber,
|
||||||
|
IsOptional,
|
||||||
|
IsPositive,
|
||||||
|
IsString,
|
||||||
|
MaxLength,
|
||||||
|
Min,
|
||||||
|
ValidateNested,
|
||||||
|
} from 'class-validator';
|
||||||
|
|
||||||
|
export class ManualJournalEntryDto {
|
||||||
|
@ApiProperty({ description: 'Entry index' })
|
||||||
|
@IsInt()
|
||||||
|
index: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Credit amount' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
@Min(0)
|
||||||
|
credit?: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Debit amount' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
@Min(0)
|
||||||
|
debit?: number;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Account ID' })
|
||||||
|
@IsInt()
|
||||||
|
accountId: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Entry note' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
note?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Contact ID' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
contactId?: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Branch ID' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
branchId?: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Project ID' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
projectId?: number;
|
||||||
|
}
|
||||||
|
|
||||||
|
class AttachmentDto {
|
||||||
|
@ApiProperty({ description: 'Attachment key' })
|
||||||
|
@IsString()
|
||||||
|
key: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CommandManualJournalDto {
|
||||||
|
@ApiProperty({ description: 'Journal date' })
|
||||||
|
@IsDate()
|
||||||
|
@Type(() => Date)
|
||||||
|
date: Date;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Currency code' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
currencyCode?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Exchange rate' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsNumber()
|
||||||
|
@IsPositive()
|
||||||
|
exchangeRate?: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Journal number' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@MaxLength(255)
|
||||||
|
journalNumber?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Journal type' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@MaxLength(255)
|
||||||
|
journalType?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Reference' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
@MaxLength(255)
|
||||||
|
reference?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Description' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsString()
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Branch ID' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsInt()
|
||||||
|
branchId?: number;
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Publish status' })
|
||||||
|
@IsOptional()
|
||||||
|
@IsBoolean()
|
||||||
|
publish?: boolean;
|
||||||
|
|
||||||
|
@ApiProperty({ description: 'Journal entries', type: [ManualJournalEntryDto] })
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => ManualJournalEntryDto)
|
||||||
|
entries: ManualJournalEntryDto[];
|
||||||
|
|
||||||
|
@ApiPropertyOptional({ description: 'Attachments', type: [AttachmentDto] })
|
||||||
|
@IsOptional()
|
||||||
|
@IsArray()
|
||||||
|
@ValidateNested({ each: true })
|
||||||
|
@Type(() => AttachmentDto)
|
||||||
|
attachments?: AttachmentDto[];
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateManualJournalDto extends CommandManualJournalDto {}
|
||||||
|
export class EditManualJournalDto extends CommandManualJournalDto {}
|
||||||
@@ -0,0 +1,30 @@
|
|||||||
|
import { IsObject, IsString } from 'class-validator';
|
||||||
|
import { IsNotEmpty } from 'class-validator';
|
||||||
|
|
||||||
|
export class CreatePdfTemplateDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
templateName: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
resource: string;
|
||||||
|
|
||||||
|
@IsObject()
|
||||||
|
@IsNotEmpty()
|
||||||
|
attributes: Record<string, any>;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class EditPdfTemplateDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
templateName: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
resource: string;
|
||||||
|
|
||||||
|
@IsObject()
|
||||||
|
@IsNotEmpty()
|
||||||
|
attributes: Record<string, any>;
|
||||||
|
}
|
||||||
@@ -2,12 +2,11 @@ import { CreateTaxRate } from './commands/CreateTaxRate.service';
|
|||||||
import { DeleteTaxRateService } from './commands/DeleteTaxRate.service';
|
import { DeleteTaxRateService } from './commands/DeleteTaxRate.service';
|
||||||
import { EditTaxRateService } from './commands/EditTaxRate.service';
|
import { EditTaxRateService } from './commands/EditTaxRate.service';
|
||||||
import { GetTaxRateService } from './queries/GetTaxRate.service';
|
import { GetTaxRateService } from './queries/GetTaxRate.service';
|
||||||
// import { GetTaxRatesService } from './queries/GetTaxRates';
|
|
||||||
import { ActivateTaxRateService } from './commands/ActivateTaxRate.service';
|
import { ActivateTaxRateService } from './commands/ActivateTaxRate.service';
|
||||||
import { InactivateTaxRateService } from './commands/InactivateTaxRate';
|
import { InactivateTaxRateService } from './commands/InactivateTaxRate';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
import { ICreateTaxRateDTO, IEditTaxRateDTO } from './TaxRates.types';
|
|
||||||
import { GetTaxRatesService } from './queries/GetTaxRates.service';
|
import { GetTaxRatesService } from './queries/GetTaxRates.service';
|
||||||
|
import { CreateTaxRateDto, EditTaxRateDto } from './dtos/TaxRate.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class TaxRatesApplication {
|
export class TaxRatesApplication {
|
||||||
@@ -26,7 +25,7 @@ export class TaxRatesApplication {
|
|||||||
* @param {ICreateTaxRateDTO} createTaxRateDTO
|
* @param {ICreateTaxRateDTO} createTaxRateDTO
|
||||||
* @returns {Promise<ITaxRate>}
|
* @returns {Promise<ITaxRate>}
|
||||||
*/
|
*/
|
||||||
public createTaxRate(createTaxRateDTO: ICreateTaxRateDTO) {
|
public createTaxRate(createTaxRateDTO: CreateTaxRateDto) {
|
||||||
return this.createTaxRateService.createTaxRate(createTaxRateDTO);
|
return this.createTaxRateService.createTaxRate(createTaxRateDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -37,7 +36,7 @@ export class TaxRatesApplication {
|
|||||||
* @param {IEditTaxRateDTO} taxRateEditDTO
|
* @param {IEditTaxRateDTO} taxRateEditDTO
|
||||||
* @returns {Promise<ITaxRate>}
|
* @returns {Promise<ITaxRate>}
|
||||||
*/
|
*/
|
||||||
public editTaxRate(taxRateId: number, editTaxRateDTO: IEditTaxRateDTO) {
|
public editTaxRate(taxRateId: number, editTaxRateDTO: EditTaxRateDto) {
|
||||||
return this.editTaxRateService.editTaxRate(taxRateId, editTaxRateDTO);
|
return this.editTaxRateService.editTaxRate(taxRateId, editTaxRateDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -8,9 +8,9 @@ import {
|
|||||||
Put,
|
Put,
|
||||||
} from '@nestjs/common';
|
} from '@nestjs/common';
|
||||||
import { TaxRatesApplication } from './TaxRate.application';
|
import { TaxRatesApplication } from './TaxRate.application';
|
||||||
import { ICreateTaxRateDTO, IEditTaxRateDTO } from './TaxRates.types';
|
|
||||||
import { PublicRoute } from '../Auth/Jwt.guard';
|
import { PublicRoute } from '../Auth/Jwt.guard';
|
||||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
|
import { CreateTaxRateDto, EditTaxRateDto } from './dtos/TaxRate.dto';
|
||||||
|
|
||||||
@Controller('tax-rates')
|
@Controller('tax-rates')
|
||||||
@ApiTags('tax-rates')
|
@ApiTags('tax-rates')
|
||||||
@@ -20,7 +20,7 @@ export class TaxRatesController {
|
|||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@ApiOperation({ summary: 'Create a new tax rate.' })
|
@ApiOperation({ summary: 'Create a new tax rate.' })
|
||||||
public createTaxRate(@Body() createTaxRateDTO: ICreateTaxRateDTO) {
|
public createTaxRate(@Body() createTaxRateDTO: CreateTaxRateDto) {
|
||||||
return this.taxRatesApplication.createTaxRate(createTaxRateDTO);
|
return this.taxRatesApplication.createTaxRate(createTaxRateDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ export class TaxRatesController {
|
|||||||
@ApiOperation({ summary: 'Edit the given tax rate.' })
|
@ApiOperation({ summary: 'Edit the given tax rate.' })
|
||||||
public editTaxRate(
|
public editTaxRate(
|
||||||
@Param('id') taxRateId: number,
|
@Param('id') taxRateId: number,
|
||||||
@Body() editTaxRateDTO: IEditTaxRateDTO,
|
@Body() editTaxRateDTO: EditTaxRateDto,
|
||||||
) {
|
) {
|
||||||
return this.taxRatesApplication.editTaxRate(taxRateId, editTaxRateDTO);
|
return this.taxRatesApplication.editTaxRate(taxRateId, editTaxRateDTO);
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
|||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { CreateTaxRateDto } from '../dtos/TaxRate.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateTaxRate {
|
export class CreateTaxRate {
|
||||||
@@ -34,7 +35,7 @@ export class CreateTaxRate {
|
|||||||
* @param {ICreateTaxRateDTO} createTaxRateDTO
|
* @param {ICreateTaxRateDTO} createTaxRateDTO
|
||||||
*/
|
*/
|
||||||
public async createTaxRate(
|
public async createTaxRate(
|
||||||
createTaxRateDTO: ICreateTaxRateDTO,
|
createTaxRateDTO: CreateTaxRateDto,
|
||||||
trx?: Knex.Transaction,
|
trx?: Knex.Transaction,
|
||||||
) {
|
) {
|
||||||
// Validates the tax code uniquiness.
|
// Validates the tax code uniquiness.
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
|||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { EditTaxRateDto } from '../dtos/TaxRate.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EditTaxRateService {
|
export class EditTaxRateService {
|
||||||
@@ -38,7 +39,7 @@ export class EditTaxRateService {
|
|||||||
*/
|
*/
|
||||||
private isTaxRateDTOChanged = (
|
private isTaxRateDTOChanged = (
|
||||||
taxRate: TaxRateModel,
|
taxRate: TaxRateModel,
|
||||||
editTaxRateDTO: IEditTaxRateDTO,
|
editTaxRateDTO: EditTaxRateDto,
|
||||||
) => {
|
) => {
|
||||||
return (
|
return (
|
||||||
taxRate.rate !== editTaxRateDTO.rate ||
|
taxRate.rate !== editTaxRateDTO.rate ||
|
||||||
@@ -57,7 +58,7 @@ export class EditTaxRateService {
|
|||||||
*/
|
*/
|
||||||
private async editTaxRateOrCreate(
|
private async editTaxRateOrCreate(
|
||||||
oldTaxRate: TaxRateModel,
|
oldTaxRate: TaxRateModel,
|
||||||
editTaxRateDTO: IEditTaxRateDTO,
|
editTaxRateDTO: EditTaxRateDto,
|
||||||
trx?: Knex.Transaction,
|
trx?: Knex.Transaction,
|
||||||
) {
|
) {
|
||||||
const isTaxDTOChanged = this.isTaxRateDTOChanged(
|
const isTaxDTOChanged = this.isTaxRateDTOChanged(
|
||||||
@@ -90,7 +91,7 @@ export class EditTaxRateService {
|
|||||||
* @param {IEditTaxRateDTO} editTaxRateDTO - The tax rate data to edit.
|
* @param {IEditTaxRateDTO} editTaxRateDTO - The tax rate data to edit.
|
||||||
* @returns {Promise<ITaxRate>}
|
* @returns {Promise<ITaxRate>}
|
||||||
*/
|
*/
|
||||||
public async editTaxRate(taxRateId: number, editTaxRateDTO: IEditTaxRateDTO) {
|
public async editTaxRate(taxRateId: number, editTaxRateDTO: EditTaxRateDto) {
|
||||||
const oldTaxRate = await this.taxRateModel().query().findById(taxRateId);
|
const oldTaxRate = await this.taxRateModel().query().findById(taxRateId);
|
||||||
|
|
||||||
// Validates the tax rate existance.
|
// Validates the tax rate existance.
|
||||||
|
|||||||
@@ -0,0 +1,94 @@
|
|||||||
|
import { ApiProperty } from '@nestjs/swagger';
|
||||||
|
import { Transform } from 'class-transformer';
|
||||||
|
import {
|
||||||
|
IsBoolean,
|
||||||
|
IsNumber,
|
||||||
|
IsNotEmpty,
|
||||||
|
IsOptional,
|
||||||
|
IsString,
|
||||||
|
} from 'class-validator';
|
||||||
|
|
||||||
|
export class CommandTaxRateDto {
|
||||||
|
/**
|
||||||
|
* Tax rate name.
|
||||||
|
*/
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The name of the tax rate.',
|
||||||
|
example: 'VAT',
|
||||||
|
})
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tax rate code.
|
||||||
|
*/
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The code of the tax rate.',
|
||||||
|
example: 'VAT',
|
||||||
|
})
|
||||||
|
code: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tax rate percentage.
|
||||||
|
*/
|
||||||
|
@IsNumber()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The rate of the tax rate.',
|
||||||
|
example: 10,
|
||||||
|
})
|
||||||
|
rate: number;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Tax rate description.
|
||||||
|
*/
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'The description of the tax rate.',
|
||||||
|
example: 'VAT',
|
||||||
|
})
|
||||||
|
description?: string;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the tax is non-recoverable.
|
||||||
|
*/
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
@Transform(({ value }) => value ?? false)
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Whether the tax is non-recoverable.',
|
||||||
|
example: false,
|
||||||
|
})
|
||||||
|
isNonRecoverable?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the tax is compound.
|
||||||
|
*/
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
@Transform(({ value }) => value ?? false)
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Whether the tax is compound.',
|
||||||
|
example: false,
|
||||||
|
})
|
||||||
|
isCompound?: boolean;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Whether the tax rate is active.
|
||||||
|
*/
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
@Transform(({ value }) => value ?? false)
|
||||||
|
@ApiProperty({
|
||||||
|
description: 'Whether the tax rate is active.',
|
||||||
|
example: false,
|
||||||
|
})
|
||||||
|
active?: boolean;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateTaxRateDto extends CommandTaxRateDto {}
|
||||||
|
export class EditTaxRateDto extends CommandTaxRateDto {}
|
||||||
@@ -7,7 +7,9 @@ import { TenantModelProxy } from '../System/models/TenantBaseModel';
|
|||||||
export class InventoryTransactionsWarehouses {
|
export class InventoryTransactionsWarehouses {
|
||||||
constructor(
|
constructor(
|
||||||
@Inject(AccountTransaction.name)
|
@Inject(AccountTransaction.name)
|
||||||
private readonly accountTransactionModel: TenantModelProxy<typeof AccountTransaction>,
|
private readonly accountTransactionModel: TenantModelProxy<
|
||||||
|
typeof AccountTransaction
|
||||||
|
>,
|
||||||
) {}
|
) {}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -16,7 +18,7 @@ export class InventoryTransactionsWarehouses {
|
|||||||
*/
|
*/
|
||||||
public updateTransactionsWithWarehouse = async (
|
public updateTransactionsWithWarehouse = async (
|
||||||
primaryBranchId: number,
|
primaryBranchId: number,
|
||||||
trx?: Knex.Transaction
|
trx?: Knex.Transaction,
|
||||||
) => {
|
) => {
|
||||||
await this.accountTransactionModel().query(trx).update({
|
await this.accountTransactionModel().query(trx).update({
|
||||||
branchId: primaryBranchId,
|
branchId: primaryBranchId,
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { WarehousesApplication } from './WarehousesApplication.service';
|
|||||||
import { ICreateWarehouseDTO, IEditWarehouseDTO } from './Warehouse.types';
|
import { ICreateWarehouseDTO, IEditWarehouseDTO } from './Warehouse.types';
|
||||||
import { PublicRoute } from '../Auth/Jwt.guard';
|
import { PublicRoute } from '../Auth/Jwt.guard';
|
||||||
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
import { ApiOperation, ApiTags } from '@nestjs/swagger';
|
||||||
|
import { CreateWarehouseDto, EditWarehouseDto } from './dtos/Warehouse.dto';
|
||||||
|
|
||||||
@Controller('warehouses')
|
@Controller('warehouses')
|
||||||
@ApiTags('warehouses')
|
@ApiTags('warehouses')
|
||||||
@@ -20,14 +21,14 @@ export class WarehousesController {
|
|||||||
|
|
||||||
@Post()
|
@Post()
|
||||||
@ApiOperation({ summary: 'Create a warehouse' })
|
@ApiOperation({ summary: 'Create a warehouse' })
|
||||||
createWarehouse(@Body() createWarehouseDTO: ICreateWarehouseDTO) {
|
createWarehouse(@Body() createWarehouseDTO: CreateWarehouseDto) {
|
||||||
return this.warehousesApplication.createWarehouse(createWarehouseDTO);
|
return this.warehousesApplication.createWarehouse(createWarehouseDTO);
|
||||||
}
|
}
|
||||||
|
|
||||||
@Put(':id')
|
@Put(':id')
|
||||||
editWarehouse(
|
editWarehouse(
|
||||||
@Param('id') warehouseId: string,
|
@Param('id') warehouseId: string,
|
||||||
@Body() editWarehouseDTO: IEditWarehouseDTO,
|
@Body() editWarehouseDTO: EditWarehouseDto,
|
||||||
) {
|
) {
|
||||||
return this.warehousesApplication.editWarehouse(
|
return this.warehousesApplication.editWarehouse(
|
||||||
Number(warehouseId),
|
Number(warehouseId),
|
||||||
|
|||||||
@@ -1,6 +1,4 @@
|
|||||||
import {
|
import {
|
||||||
ICreateWarehouseDTO,
|
|
||||||
IEditWarehouseDTO,
|
|
||||||
IWarehouse,
|
IWarehouse,
|
||||||
} from './Warehouse.types';
|
} from './Warehouse.types';
|
||||||
import { ActivateWarehousesService } from './commands/ActivateWarehouses.service';
|
import { ActivateWarehousesService } from './commands/ActivateWarehouses.service';
|
||||||
@@ -12,6 +10,7 @@ import { GetWarehouses } from './queries/GetWarehouses';
|
|||||||
import { GetItemWarehouses } from './Items/GetItemWarehouses';
|
import { GetItemWarehouses } from './Items/GetItemWarehouses';
|
||||||
import { WarehouseMarkPrimary } from './commands/WarehouseMarkPrimary.service';
|
import { WarehouseMarkPrimary } from './commands/WarehouseMarkPrimary.service';
|
||||||
import { Injectable } from '@nestjs/common';
|
import { Injectable } from '@nestjs/common';
|
||||||
|
import { CreateWarehouseDto, EditWarehouseDto } from './dtos/Warehouse.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class WarehousesApplication {
|
export class WarehousesApplication {
|
||||||
@@ -31,20 +30,19 @@ export class WarehousesApplication {
|
|||||||
* @param {ICreateWarehouseDTO} createWarehouseDTO
|
* @param {ICreateWarehouseDTO} createWarehouseDTO
|
||||||
* @returns {Promise<IWarehouse>}
|
* @returns {Promise<IWarehouse>}
|
||||||
*/
|
*/
|
||||||
public createWarehouse = (createWarehouseDTO: ICreateWarehouseDTO) => {
|
public createWarehouse = (createWarehouseDTO: CreateWarehouseDto) => {
|
||||||
return this.createWarehouseService.createWarehouse(createWarehouseDTO);
|
return this.createWarehouseService.createWarehouse(createWarehouseDTO);
|
||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Edits the given warehouse.
|
* Edits the given warehouse.
|
||||||
* @param {number} tenantId
|
|
||||||
* @param {number} warehouseId
|
* @param {number} warehouseId
|
||||||
* @param {IEditWarehouseDTO} editWarehouseDTO
|
* @param {EditWarehouseDto} editWarehouseDTO
|
||||||
* @returns {Promise<void>}
|
* @returns {Promise<void>}
|
||||||
*/
|
*/
|
||||||
public editWarehouse = (
|
public editWarehouse = (
|
||||||
warehouseId: number,
|
warehouseId: number,
|
||||||
editWarehouseDTO: IEditWarehouseDTO,
|
editWarehouseDTO: EditWarehouseDto,
|
||||||
) => {
|
) => {
|
||||||
return this.editWarehouseService.editWarehouse(
|
return this.editWarehouseService.editWarehouse(
|
||||||
warehouseId,
|
warehouseId,
|
||||||
@@ -54,7 +52,6 @@ export class WarehousesApplication {
|
|||||||
|
|
||||||
/**
|
/**
|
||||||
* Deletes the given warehouse.
|
* Deletes the given warehouse.
|
||||||
* @param {number} tenantId
|
|
||||||
* @param {number} warehouseId
|
* @param {number} warehouseId
|
||||||
*/
|
*/
|
||||||
public deleteWarehouse = (warehouseId: number) => {
|
public deleteWarehouse = (warehouseId: number) => {
|
||||||
@@ -71,9 +68,8 @@ export class WarehousesApplication {
|
|||||||
};
|
};
|
||||||
|
|
||||||
/**
|
/**
|
||||||
*
|
* Retrieves the warehouses list.
|
||||||
* @param {number} tenantId
|
* @returns {Promise<IWarehouse[]>}
|
||||||
* @returns
|
|
||||||
*/
|
*/
|
||||||
public getWarehouses = () => {
|
public getWarehouses = () => {
|
||||||
return this.getWarehousesService.getWarehouses();
|
return this.getWarehousesService.getWarehouses();
|
||||||
|
|||||||
@@ -11,6 +11,7 @@ import { UnitOfWork } from '@/modules/Tenancy/TenancyDB/UnitOfWork.service';
|
|||||||
import { EventEmitter2 } from '@nestjs/event-emitter';
|
import { EventEmitter2 } from '@nestjs/event-emitter';
|
||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { CreateWarehouseDto } from '../dtos/Warehouse.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class CreateWarehouse {
|
export class CreateWarehouse {
|
||||||
@@ -33,7 +34,7 @@ export class CreateWarehouse {
|
|||||||
* Authorize the warehouse before creating.
|
* Authorize the warehouse before creating.
|
||||||
* @param {ICreateWarehouseDTO} warehouseDTO -
|
* @param {ICreateWarehouseDTO} warehouseDTO -
|
||||||
*/
|
*/
|
||||||
public authorize = async (warehouseDTO: ICreateWarehouseDTO) => {
|
public authorize = async (warehouseDTO: CreateWarehouseDto) => {
|
||||||
if (warehouseDTO.code) {
|
if (warehouseDTO.code) {
|
||||||
await this.validator.validateWarehouseCodeUnique(warehouseDTO.code);
|
await this.validator.validateWarehouseCodeUnique(warehouseDTO.code);
|
||||||
}
|
}
|
||||||
@@ -44,7 +45,7 @@ export class CreateWarehouse {
|
|||||||
* @param {ICreateWarehouseDTO} warehouseDTO
|
* @param {ICreateWarehouseDTO} warehouseDTO
|
||||||
*/
|
*/
|
||||||
public createWarehouse = async (
|
public createWarehouse = async (
|
||||||
warehouseDTO: ICreateWarehouseDTO,
|
warehouseDTO: CreateWarehouseDto,
|
||||||
): Promise<Warehouse> => {
|
): Promise<Warehouse> => {
|
||||||
// Authorize warehouse before creating.
|
// Authorize warehouse before creating.
|
||||||
await this.authorize(warehouseDTO);
|
await this.authorize(warehouseDTO);
|
||||||
|
|||||||
@@ -7,6 +7,7 @@ import { EventEmitter2 } from '@nestjs/event-emitter';
|
|||||||
import { Warehouse } from '../models/Warehouse.model';
|
import { Warehouse } from '../models/Warehouse.model';
|
||||||
import { events } from '@/common/events/events';
|
import { events } from '@/common/events/events';
|
||||||
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
import { TenantModelProxy } from '@/modules/System/models/TenantBaseModel';
|
||||||
|
import { EditWarehouseDto } from '../dtos/Warehouse.dto';
|
||||||
|
|
||||||
@Injectable()
|
@Injectable()
|
||||||
export class EditWarehouse {
|
export class EditWarehouse {
|
||||||
@@ -29,7 +30,7 @@ export class EditWarehouse {
|
|||||||
* Authorize the warehouse before deleting.
|
* Authorize the warehouse before deleting.
|
||||||
*/
|
*/
|
||||||
public authorize = async (
|
public authorize = async (
|
||||||
warehouseDTO: IEditWarehouseDTO,
|
warehouseDTO: EditWarehouseDto,
|
||||||
warehouseId: number,
|
warehouseId: number,
|
||||||
) => {
|
) => {
|
||||||
if (warehouseDTO.code) {
|
if (warehouseDTO.code) {
|
||||||
@@ -47,7 +48,7 @@ export class EditWarehouse {
|
|||||||
*/
|
*/
|
||||||
public editWarehouse = async (
|
public editWarehouse = async (
|
||||||
warehouseId: number,
|
warehouseId: number,
|
||||||
warehouseDTO: IEditWarehouseDTO,
|
warehouseDTO: EditWarehouseDto,
|
||||||
): Promise<Warehouse> => {
|
): Promise<Warehouse> => {
|
||||||
// Authorize the warehouse DTO before editing.
|
// Authorize the warehouse DTO before editing.
|
||||||
await this.authorize(warehouseDTO, warehouseId);
|
await this.authorize(warehouseDTO, warehouseId);
|
||||||
|
|||||||
@@ -0,0 +1,55 @@
|
|||||||
|
import { ApiProperty } from "@nestjs/swagger";
|
||||||
|
import { IsBoolean, IsEmail, IsOptional, IsUrl } from "class-validator";
|
||||||
|
import { IsNotEmpty } from "class-validator";
|
||||||
|
import { IsString } from "class-validator";
|
||||||
|
|
||||||
|
|
||||||
|
export class CommandWarehouseDto {
|
||||||
|
@IsString()
|
||||||
|
@IsNotEmpty()
|
||||||
|
@ApiProperty({ description: 'The name of the warehouse' })
|
||||||
|
name: string;
|
||||||
|
|
||||||
|
@IsBoolean()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'Whether the warehouse is primary' })
|
||||||
|
primary?: boolean;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'The code of the warehouse' })
|
||||||
|
code?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'The address of the warehouse' })
|
||||||
|
address?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'The city of the warehouse' })
|
||||||
|
city?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'The country of the warehouse' })
|
||||||
|
country?: string;
|
||||||
|
|
||||||
|
@IsString()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'The phone number of the warehouse' })
|
||||||
|
phoneNumber?: string;
|
||||||
|
|
||||||
|
@IsEmail()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'The email of the warehouse' })
|
||||||
|
email?: string;
|
||||||
|
|
||||||
|
@IsUrl()
|
||||||
|
@IsOptional()
|
||||||
|
@ApiProperty({ description: 'The website of the warehouse' })
|
||||||
|
website?: string;
|
||||||
|
}
|
||||||
|
|
||||||
|
export class CreateWarehouseDto extends CommandWarehouseDto {}
|
||||||
|
export class EditWarehouseDto extends CommandWarehouseDto {}
|
||||||
Reference in New Issue
Block a user