fix(SPG-544) BE-Validasi Tenant dan Item Tenant

pull/3/head
Aswin Ashar Abdullah 2024-06-20 15:16:43 +07:00
parent f170c2e017
commit 766909798f
11 changed files with 122 additions and 26 deletions

View File

@ -9,7 +9,7 @@ export class ValidateRelationHelper<Entity> {
private dataService: BaseDataService<Entity>, private dataService: BaseDataService<Entity>,
private relations: validateRelations[], private relations: validateRelations[],
private tableName: string, private tableName: string,
) {} ) { }
async execute() { async execute() {
const repository = this.dataService.getRepository(); const repository = this.dataService.getRepository();
@ -17,15 +17,32 @@ export class ValidateRelationHelper<Entity> {
// load relation // load relation
for (const relation of this.relations) { for (const relation of this.relations) {
queryBuilder.loadRelationCountAndMap( if (relation.singleQuery) {
`${this.tableName}.total_${relation.relation}`, queryBuilder.leftJoinAndMapOne(
`${this.tableName}.${relation.relation}`, `${ this.tableName }.${ relation.relation }`,
`total_${relation.relation}`, `${ this.tableName }.${ relation.relation }`,
); relation.relation,
)
}
else if (relation.query) {
queryBuilder.loadRelationCountAndMap(
`${ this.tableName }.total_${ relation.relation }`,
`${ this.tableName }.${ relation.relation }`,
`total_${ relation.relation }`,
relation.query,
);
}
else {
queryBuilder.loadRelationCountAndMap(
`${ this.tableName }.total_${ relation.relation }`,
`${ this.tableName }.${ relation.relation }`,
`total_${ relation.relation }`,
);
}
} }
// filtering data only with specific data // filtering data only with specific data
queryBuilder.where(`${this.tableName}.id in ('${this.dataId}')`); queryBuilder.where(`${ this.tableName }.id in ('${ this.dataId }')`);
// get data // get data
const data = await queryBuilder.getOne(); const data = await queryBuilder.getOne();
@ -34,10 +51,27 @@ export class ValidateRelationHelper<Entity> {
for (const relation of this.relations) { for (const relation of this.relations) {
const message = const message =
relation.message ?? relation.message ??
`Failed! this data already connected to ${relation.relation}`; `Failed! this data already connected to ${ relation.relation }`;
if (data[`total_${relation.relation}`]) if (relation.singleQuery) {
const relationColumn = data[relation.relation]?.[`${ relation.singleQuery[0] }`]
if (this.mappingValidator(relationColumn, relation.singleQuery[1], relation.singleQuery[2]))
throw new UnprocessableEntityException(message);
} else if (data[`total_${ relation.relation } `])
throw new UnprocessableEntityException(message); throw new UnprocessableEntityException(message);
} }
} }
}
mappingValidator(column, operator, value) {
switch (operator) {
case '!=':
return column != value;
case '==':
return column == value;
default:
return column == value;
}
}
}

View File

@ -39,7 +39,7 @@ export abstract class BaseBatchUpdateStatusManager<Entity> extends BaseManager {
if (!entity) { if (!entity) {
throw new NotFoundException({ throw new NotFoundException({
statusCode: HttpStatus.NOT_FOUND, statusCode: HttpStatus.NOT_FOUND,
message: `Failed! Entity with id ${id} not found`, message: `Failed! Entity with id ${ id } not found`,
error: 'Entity Not Found', error: 'Entity Not Found',
}); });
} }

View File

@ -1,5 +1,6 @@
import { UsersSession } from 'src/core/sessions'; import { UsersSession } from 'src/core/sessions';
import { OPERATION } from './base.constants'; import { OPERATION } from './base.constants';
import { SelectQueryBuilder } from 'typeorm';
export interface EventTopics { export interface EventTopics {
topic: any; topic: any;
@ -7,7 +8,16 @@ export interface EventTopics {
} }
export interface validateRelations { export interface validateRelations {
// nama relasi
relation: string; relation: string;
// query digunakan untuk query optional jika ingin specifik data
query?: (qb: SelectQueryBuilder<any>) => SelectQueryBuilder<any>;
// query ini sama dengan yang diatas, akan tetapi ini khusus untuk ManyToOne relation
singleQuery?: [string, any, any];
// custom message
message?: string; message?: string;
} }

View File

@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common'; import { HttpStatus, Injectable, UnprocessableEntityException } from '@nestjs/common';
import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager';
import { ItemEntity } from '../../entities/item.entity'; import { ItemEntity } from '../../entities/item.entity';
import { import {
@ -7,11 +7,12 @@ import {
} from 'src/core/strings/constants/interface.constants'; } from 'src/core/strings/constants/interface.constants';
import { ItemModel } from '../../../data/models/item.model'; import { ItemModel } from '../../../data/models/item.model';
import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable() @Injectable()
export class ActiveItemManager extends BaseUpdateStatusManager<ItemEntity> { export class ActiveItemManager extends BaseUpdateStatusManager<ItemEntity> {
getResult(): string { getResult(): string {
return `Success active data ${this.result.name}`; return `Success active data ${ this.result.name }`;
} }
async validateProcess(): Promise<void> { async validateProcess(): Promise<void> {
@ -27,7 +28,11 @@ export class ActiveItemManager extends BaseUpdateStatusManager<ItemEntity> {
} }
get validateRelations(): validateRelations[] { get validateRelations(): validateRelations[] {
return []; return [{
relation: 'tenant',
singleQuery: ['status', '!=', STATUS.ACTIVE],
message: `Failed! Tenant of item must be active first`,
}];
} }
get entityTarget(): any { get entityTarget(): any {

View File

@ -7,7 +7,8 @@ import {
import { ItemModel } from '../../../data/models/item.model'; import { ItemModel } from '../../../data/models/item.model';
import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event';
import { BatchResult } from 'src/core/response/domain/ok-response.interface'; import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { Injectable } from '@nestjs/common'; import { HttpStatus, Injectable, UnprocessableEntityException } from '@nestjs/common';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable() @Injectable()
export class BatchActiveItemManager extends BaseBatchUpdateStatusManager<ItemEntity> { export class BatchActiveItemManager extends BaseBatchUpdateStatusManager<ItemEntity> {
@ -24,7 +25,11 @@ export class BatchActiveItemManager extends BaseBatchUpdateStatusManager<ItemEnt
} }
get validateRelations(): validateRelations[] { get validateRelations(): validateRelations[] {
return []; return [{
relation: 'tenant',
singleQuery: ['status', '!=', STATUS.ACTIVE],
message: `Failed! Tenant of item must be active first`,
}];
} }
get entityTarget(): any { get entityTarget(): any {

View File

@ -8,10 +8,11 @@ import { ItemModel } from '../../../data/models/item.model';
import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event';
import { BatchResult } from 'src/core/response/domain/ok-response.interface'; import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable() @Injectable()
export class BatchConfirmItemManager extends BaseBatchUpdateStatusManager<ItemEntity> { export class BatchConfirmItemManager extends BaseBatchUpdateStatusManager<ItemEntity> {
validateData(data: ItemEntity): Promise<void> { async validateData(data: ItemEntity): Promise<void> {
return; return;
} }
@ -24,7 +25,11 @@ export class BatchConfirmItemManager extends BaseBatchUpdateStatusManager<ItemEn
} }
get validateRelations(): validateRelations[] { get validateRelations(): validateRelations[] {
return []; return [{
relation: 'tenant',
singleQuery: ['status', '!=', STATUS.ACTIVE],
message: `Failed! Tenant of item must be active first`,
}];
} }
get entityTarget(): any { get entityTarget(): any {

View File

@ -1,4 +1,4 @@
import { Injectable } from '@nestjs/common'; import { HttpStatus, Injectable, UnprocessableEntityException } from '@nestjs/common';
import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager';
import { ItemEntity } from '../../entities/item.entity'; import { ItemEntity } from '../../entities/item.entity';
import { import {
@ -7,11 +7,12 @@ import {
} from 'src/core/strings/constants/interface.constants'; } from 'src/core/strings/constants/interface.constants';
import { ItemModel } from '../../../data/models/item.model'; import { ItemModel } from '../../../data/models/item.model';
import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event'; import { ItemChangeStatusEvent } from '../../entities/event/item-change-status.event';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable() @Injectable()
export class ConfirmItemManager extends BaseUpdateStatusManager<ItemEntity> { export class ConfirmItemManager extends BaseUpdateStatusManager<ItemEntity> {
getResult(): string { getResult(): string {
return `Success active data ${this.result.name}`; return `Success active data ${ this.result.name }`;
} }
async validateProcess(): Promise<void> { async validateProcess(): Promise<void> {
@ -27,7 +28,11 @@ export class ConfirmItemManager extends BaseUpdateStatusManager<ItemEntity> {
} }
get validateRelations(): validateRelations[] { get validateRelations(): validateRelations[] {
return []; return [{
relation: 'tenant',
singleQuery: ['status', '!=', STATUS.ACTIVE],
message: `Failed! Tenant of item must be active first`,
}];
} }
get entityTarget(): any { get entityTarget(): any {

View File

@ -8,11 +8,19 @@ import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { SelectQueryBuilder } from 'typeorm';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable() @Injectable()
export class BatchDeleteTenantManager extends BaseBatchDeleteManager<UserEntity> { export class BatchDeleteTenantManager extends BaseBatchDeleteManager<UserEntity> {
get validateRelations(): validateRelations[] { get validateRelations(): validateRelations[] {
return [{ relation: 'items' }]; return [{
relation: 'items',
query: (qb: SelectQueryBuilder<any>) => {
return qb.andWhere('total_items.status In (:...statuses)', { statuses: [STATUS.ACTIVE] });
},
message: 'Failed! There is active item'
}];
} }
async beforeProcess(): Promise<void> { async beforeProcess(): Promise<void> {

View File

@ -8,11 +8,19 @@ import { BatchResult } from 'src/core/response/domain/ok-response.interface';
import { Injectable } from '@nestjs/common'; import { Injectable } from '@nestjs/common';
import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { SelectQueryBuilder } from 'typeorm';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable() @Injectable()
export class BatchInactiveTenantManager extends BaseBatchUpdateStatusManager<UserEntity> { export class BatchInactiveTenantManager extends BaseBatchUpdateStatusManager<UserEntity> {
get validateRelations(): validateRelations[] { get validateRelations(): validateRelations[] {
return [{ relation: 'items' }]; return [{
relation: 'items',
query: (qb: SelectQueryBuilder<any>) => {
return qb.andWhere('total_items.status In (:...statuses)', { statuses: [STATUS.ACTIVE] });
},
message: 'Failed! There is active item'
}];
} }
validateData(data: UserEntity): Promise<void> { validateData(data: UserEntity): Promise<void> {

View File

@ -7,11 +7,19 @@ import {
import { TenantDeletedEvent } from '../../entities/event/tenant-deleted.event'; import { TenantDeletedEvent } from '../../entities/event/tenant-deleted.event';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity';
import { SelectQueryBuilder } from 'typeorm';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable() @Injectable()
export class DeleteTenantManager extends BaseDeleteManager<UserEntity> { export class DeleteTenantManager extends BaseDeleteManager<UserEntity> {
get validateRelations(): validateRelations[] { get validateRelations(): validateRelations[] {
return [{ relation: 'items' }]; return [{
relation: 'items',
query: (qb: SelectQueryBuilder<any>) => {
return qb.andWhere('total_items.status In (:...statuses)', { statuses: [STATUS.ACTIVE] });
},
message: 'Failed! There is active item'
}];
} }
getResult(): string { getResult(): string {

View File

@ -7,15 +7,23 @@ import {
import { TenantChangeStatusEvent } from '../../entities/event/tenant-change-status.event'; import { TenantChangeStatusEvent } from '../../entities/event/tenant-change-status.event';
import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; import { UserModel } from 'src/modules/user-related/user/data/models/user.model';
import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity'; import { UserEntity } from 'src/modules/user-related/user/domain/entities/user.entity';
import { SelectQueryBuilder } from 'typeorm';
import { STATUS } from 'src/core/strings/constants/base.constants';
@Injectable() @Injectable()
export class InactiveTenantManager extends BaseUpdateStatusManager<UserEntity> { export class InactiveTenantManager extends BaseUpdateStatusManager<UserEntity> {
get validateRelations(): validateRelations[] { get validateRelations(): validateRelations[] {
return [{ relation: 'items' }]; return [{
relation: 'items',
query: (qb: SelectQueryBuilder<any>) => {
return qb.andWhere('total_items.status In (:...statuses)', { statuses: [STATUS.ACTIVE] });
},
message: 'Failed! There is active item'
}];
} }
getResult(): string { getResult(): string {
return `Success inactive data ${this.result.name}`; return `Success inactive data ${ this.result.name }`;
} }
async validateProcess(): Promise<void> { async validateProcess(): Promise<void> {