From 3f3da30c372a949535563344cfdf6829e8039af2 Mon Sep 17 00:00:00 2001 From: ashar Date: Tue, 11 Jun 2024 15:31:55 +0700 Subject: [PATCH] feat(SPG-361) REST API Read Item/ Tenant Item --- .../infrastructure/dto/base-filter.dto.ts | 6 -- ...{{dashCase name}}-data.orchestrator.ts.hbs | 1 - .../item/data/services/item-read.service.ts | 17 ++++ .../domain/entities/filter-item.entity.ts | 8 ++ .../domain/usecases/item-read.orchestrator.ts | 33 +++++++ .../usecases/managers/detail-item.manager.ts | 63 +++++++++++++ .../usecases/managers/index-item.manager.ts | 91 +++++++++++++++++++ .../infrastructure/dto/filter-item.dto.ts | 30 ++++++ .../infrastructure/item-read.controller.ts | 30 ++++++ .../tenant-item-read.controller.ts | 38 ++++++++ 10 files changed, 310 insertions(+), 7 deletions(-) create mode 100644 src/modules/item-related/item/data/services/item-read.service.ts create mode 100644 src/modules/item-related/item/domain/entities/filter-item.entity.ts create mode 100644 src/modules/item-related/item/domain/usecases/item-read.orchestrator.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/detail-item.manager.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/index-item.manager.ts create mode 100644 src/modules/item-related/item/infrastructure/dto/filter-item.dto.ts create mode 100644 src/modules/item-related/item/infrastructure/item-read.controller.ts create mode 100644 src/modules/user-related/tenant/infrastructure/tenant-item-read.controller.ts diff --git a/src/core/modules/infrastructure/dto/base-filter.dto.ts b/src/core/modules/infrastructure/dto/base-filter.dto.ts index f9d9ec4..b149663 100644 --- a/src/core/modules/infrastructure/dto/base-filter.dto.ts +++ b/src/core/modules/infrastructure/dto/base-filter.dto.ts @@ -60,12 +60,6 @@ export class BaseFilterDto implements BaseFilterEntity { }) @IsArray() @IsString({ each: true }) - @IsEnum(STATUS, { - message: `Status must be a valid enum ${JSON.stringify( - Object.values(STATUS), - )}`, - each: true, - }) statuses: STATUS[]; @ApiProperty({ type: [String], required: false }) diff --git a/src/core/templates/orchestrators/base-status/{{dashCase name}}-data.orchestrator.ts.hbs b/src/core/templates/orchestrators/base-status/{{dashCase name}}-data.orchestrator.ts.hbs index f5687ca..02e4a49 100644 --- a/src/core/templates/orchestrators/base-status/{{dashCase name}}-data.orchestrator.ts.hbs +++ b/src/core/templates/orchestrators/base-status/{{dashCase name}}-data.orchestrator.ts.hbs @@ -38,7 +38,6 @@ export class {{pascalCase name}}DataOrchestrator extends Base{{pascalCase orches this.createManager.setData(data); this.createManager.setService(this.serviceData, TABLE_NAME.{{constantCase name}}); await this.createManager.execute(); - await this.createManager.generateConfig(); return this.createManager.getResult(); } diff --git a/src/modules/item-related/item/data/services/item-read.service.ts b/src/modules/item-related/item/data/services/item-read.service.ts new file mode 100644 index 0000000..92cac81 --- /dev/null +++ b/src/modules/item-related/item/data/services/item-read.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { ItemEntity } from '../../domain/entities/item.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { ItemModel } from '../models/item.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; +import { BaseReadService } from 'src/core/modules/data/service/base-read.service'; + +@Injectable() +export class ItemReadService extends BaseReadService { + constructor( + @InjectRepository(ItemModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/item-related/item/domain/entities/filter-item.entity.ts b/src/modules/item-related/item/domain/entities/filter-item.entity.ts new file mode 100644 index 0000000..7d10d72 --- /dev/null +++ b/src/modules/item-related/item/domain/entities/filter-item.entity.ts @@ -0,0 +1,8 @@ +import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity'; + +export interface FilterItemEntity extends BaseFilterEntity { + item_categories: string[]; + item_types: string[]; + limit_types: string[]; + tenant_ids: string[]; +} diff --git a/src/modules/item-related/item/domain/usecases/item-read.orchestrator.ts b/src/modules/item-related/item/domain/usecases/item-read.orchestrator.ts new file mode 100644 index 0000000..8737793 --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/item-read.orchestrator.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { IndexItemManager } from './managers/index-item.manager'; +import { ItemReadService } from '../../data/services/item-read.service'; +import { ItemEntity } from '../entities/item.entity'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; +import { DetailItemManager } from './managers/detail-item.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class ItemReadOrchestrator extends BaseReadOrchestrator { + constructor( + private indexManager: IndexItemManager, + private detailManager: DetailItemManager, + private serviceData: ItemReadService, + ) { + super(); + } + + async index(params): Promise> { + this.indexManager.setFilterParam(params); + this.indexManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.indexManager.execute(); + return this.indexManager.getResult(); + } + + async detail(dataId: string): Promise { + this.detailManager.setData(dataId); + this.detailManager.setService(this.serviceData, TABLE_NAME.ITEM); + await this.detailManager.execute(); + return this.detailManager.getResult(); + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/detail-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/detail-item.manager.ts new file mode 100644 index 0000000..058c1e0 --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/detail-item.manager.ts @@ -0,0 +1,63 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDetailManager } from 'src/core/modules/domain/usecase/managers/base-detail.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { RelationParam } from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class DetailItemManager extends BaseDetailManager { + async prepareData(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get relations(): RelationParam { + return { + // relation only join (for query purpose) + joinRelations: [], + + // relation join and select (relasi yang ingin ditampilkan), + selectRelations: ['item_category', 'bundling_items'], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.created_at`, + `${this.tableName}.status`, + `${this.tableName}.item_type`, + `${this.tableName}.name`, + `${this.tableName}.limit_type`, + `${this.tableName}.limit_value`, + `${this.tableName}.hpp`, + `${this.tableName}.sales_margin`, + `${this.tableName}.base_price`, + `${this.tableName}.use_queue`, + `${this.tableName}.show_to_booking`, + + `item_category.id`, + `item_category.name`, + + 'bundling_items.id', + 'bundling_items.name', + 'bundling_items.hpp', + 'bundling_items.base_price', + ]; + } + + get setFindProperties(): any { + return { + id: this.dataId, + }; + } +} diff --git a/src/modules/item-related/item/domain/usecases/managers/index-item.manager.ts b/src/modules/item-related/item/domain/usecases/managers/index-item.manager.ts new file mode 100644 index 0000000..ffa0adb --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/index-item.manager.ts @@ -0,0 +1,91 @@ +import { Injectable } from '@nestjs/common'; +import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; +import { ItemEntity } from '../../entities/item.entity'; +import { SelectQueryBuilder } from 'typeorm'; +import { + Param, + RelationParam, +} from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class IndexItemManager extends BaseIndexManager { + async prepareData(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get relations(): RelationParam { + return { + // relation only join (for query purpose) + joinRelations: [], + + // relation join and select (relasi yang ingin ditampilkan), + selectRelations: ['item_category', 'bundling_items'], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.created_at`, + `${this.tableName}.status`, + `${this.tableName}.item_type`, + `${this.tableName}.name`, + `${this.tableName}.hpp`, + `${this.tableName}.limit_type`, + `${this.tableName}.limit_value`, + `${this.tableName}.base_price`, + + `item_category.id`, + `item_category.name`, + + 'bundling_items.id', + 'bundling_items.name', + ]; + } + + get specificFilter(): Param[] { + return [ + { + cols: `${this.tableName}.name`, + data: this.filterParam.names, + }, + { + cols: `${this.tableName}.item_type::text`, + data: this.filterParam.item_types, + }, + { + cols: `${this.tableName}.limit_type::text`, + data: this.filterParam.limit_types, + }, + { + cols: `item_category.name`, + data: this.filterParam.item_categories, + }, + ]; + } + + setQueryFilter( + queryBuilder: SelectQueryBuilder, + ): SelectQueryBuilder { + if (this.filterParam.tenant_ids?.length) { + queryBuilder.andWhere(`${this.tableName}.tenant_id In (:...tenantIds)`, { + tenantIds: this.filterParam.tenant_ids, + }); + } else { + queryBuilder.andWhere(`${this.tableName}.tenant_id Is Null`); + } + + return queryBuilder; + } +} diff --git a/src/modules/item-related/item/infrastructure/dto/filter-item.dto.ts b/src/modules/item-related/item/infrastructure/dto/filter-item.dto.ts new file mode 100644 index 0000000..5270b63 --- /dev/null +++ b/src/modules/item-related/item/infrastructure/dto/filter-item.dto.ts @@ -0,0 +1,30 @@ +import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto'; +import { FilterItemEntity } from '../../domain/entities/filter-item.entity'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class FilterItemDto extends BaseFilterDto implements FilterItemEntity { + @ApiProperty({ type: ['string'], required: false }) + @Transform((body) => { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + item_categories: string[]; + + @ApiProperty({ type: ['string'], required: false }) + @Transform((body) => { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + limit_types: string[]; + + @ApiProperty({ type: ['string'], required: false }) + @Transform((body) => { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + item_types: string[]; + + @ApiProperty({ type: ['string'], required: false }) + @Transform((body) => { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + tenant_ids: string[]; +} diff --git a/src/modules/item-related/item/infrastructure/item-read.controller.ts b/src/modules/item-related/item/infrastructure/item-read.controller.ts new file mode 100644 index 0000000..985f4bb --- /dev/null +++ b/src/modules/item-related/item/infrastructure/item-read.controller.ts @@ -0,0 +1,30 @@ +import { Controller, Get, Param, Query } from '@nestjs/common'; +import { FilterItemDto } from './dto/filter-item.dto'; +import { Pagination } from 'src/core/response'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { ItemEntity } from '../domain/entities/item.entity'; +import { ItemReadOrchestrator } from '../domain/usecases/item-read.orchestrator'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { Public } from 'src/core/guards'; + +@ApiTags(`${MODULE_NAME.ITEM.split('-').join(' ')} - read`) +@Controller(MODULE_NAME.ITEM) +@Public(false) +@ApiBearerAuth('JWT') +export class ItemReadController { + constructor(private orchestrator: ItemReadOrchestrator) {} + + @Get() + @Pagination() + async index( + @Query() params: FilterItemDto, + ): Promise> { + return await this.orchestrator.index(params); + } + + @Get(':id') + async detail(@Param('id') id: string): Promise { + return await this.orchestrator.detail(id); + } +} diff --git a/src/modules/user-related/tenant/infrastructure/tenant-item-read.controller.ts b/src/modules/user-related/tenant/infrastructure/tenant-item-read.controller.ts new file mode 100644 index 0000000..31c3799 --- /dev/null +++ b/src/modules/user-related/tenant/infrastructure/tenant-item-read.controller.ts @@ -0,0 +1,38 @@ +import { Controller, Get, Param, Query } from '@nestjs/common'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { Public } from 'src/core/guards'; +import { Pagination } from 'src/core/response'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { ItemEntity } from 'src/modules/item-related/item/domain/entities/item.entity'; +import { ItemReadOrchestrator } from 'src/modules/item-related/item/domain/usecases/item-read.orchestrator'; +import { FilterItemDto } from 'src/modules/item-related/item/infrastructure/dto/filter-item.dto'; + +@ApiTags(`${MODULE_NAME.TENANT.split('-').join(' ')} item - read`) +@Controller(`${MODULE_NAME.TENANT}/:tenant_id/item`) +@Public(false) +@ApiBearerAuth('JWT') +export class TenantItemReadController { + constructor(private orchestrator: ItemReadOrchestrator) {} + + @Get() + @Pagination() + async index( + @Query() params: FilterItemDto, + @Param('tenant_id') tenant_id: string, + ): Promise> { + Object.assign(params, { + tenant_ids: [tenant_id], + }); + + return await this.orchestrator.index(params); + } + + @Get(':id') + async detail( + @Param('tenant_id') tenant_id: string, + @Param('id') id: string, + ): Promise { + return await this.orchestrator.detail(id); + } +}