From 08dea7965d7c921af98ee7b56d1fbbc162dc03ea Mon Sep 17 00:00:00 2001 From: ashar Date: Thu, 20 Jun 2024 01:44:41 +0700 Subject: [PATCH 1/5] feat(google-calendar) module google calendar --- .../google-calendar/constants.ts | 0 .../usecases/google-calendar.orchestrator.ts | 11 ++++ .../index-holiday-google-calendar.manager.ts | 55 +++++++++++++++++++ .../google-calendar/google-calendar.module.ts | 13 +++++ .../configuration/google-calendar/index.ts | 0 .../google-calendar.controller.ts | 16 ++++++ 6 files changed, 95 insertions(+) create mode 100644 src/modules/configuration/google-calendar/constants.ts create mode 100644 src/modules/configuration/google-calendar/domain/usecases/google-calendar.orchestrator.ts create mode 100644 src/modules/configuration/google-calendar/domain/usecases/managers/index-holiday-google-calendar.manager.ts create mode 100644 src/modules/configuration/google-calendar/google-calendar.module.ts create mode 100644 src/modules/configuration/google-calendar/index.ts create mode 100644 src/modules/configuration/google-calendar/infrastructure/google-calendar.controller.ts diff --git a/src/modules/configuration/google-calendar/constants.ts b/src/modules/configuration/google-calendar/constants.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/configuration/google-calendar/domain/usecases/google-calendar.orchestrator.ts b/src/modules/configuration/google-calendar/domain/usecases/google-calendar.orchestrator.ts new file mode 100644 index 0000000..3dfcad7 --- /dev/null +++ b/src/modules/configuration/google-calendar/domain/usecases/google-calendar.orchestrator.ts @@ -0,0 +1,11 @@ +import { Injectable } from '@nestjs/common'; +import { IndexHolidayCalendarManager } from './managers/index-holiday-google-calendar.manager'; + +@Injectable() +export class GoogleCalendarOrchestrator { + constructor(private indexHoliday: IndexHolidayCalendarManager) {} + + async holiday() { + return await this.indexHoliday.execute(); + } +} diff --git a/src/modules/configuration/google-calendar/domain/usecases/managers/index-holiday-google-calendar.manager.ts b/src/modules/configuration/google-calendar/domain/usecases/managers/index-holiday-google-calendar.manager.ts new file mode 100644 index 0000000..191b755 --- /dev/null +++ b/src/modules/configuration/google-calendar/domain/usecases/managers/index-holiday-google-calendar.manager.ts @@ -0,0 +1,55 @@ +import { Injectable } from '@nestjs/common'; +import { google } from 'googleapis'; + +@Injectable() +export class IndexHolidayCalendarManager { + async execute() { + const events = []; + const calendar = google.calendar({ + version: 'v3', + auth: 'AIzaSyCsCt6PDd6uYLkahvtdvCoMWf-1_QaLiNM', + }); + const calendarId = 'id.indonesian#holiday@group.v.calendar.google.com'; + + const res = await calendar.events.list({ + calendarId: calendarId, + timeMin: new Date().getFullYear() + '-01-01T00:00:00Z', + timeMax: new Date().getFullYear() + '-12-31T23:59:59Z', + singleEvents: true, + orderBy: 'startTime', + }); + + res.data.items?.forEach((item) => { + // const eventName = item.summary.replace("Joint", "").replace("for", "").replace("after", "").replace("Holiday","").trim(); + let eventName = item.summary.replace('Cuti Bersama', '').trim(); + + // function ini untuk menyamakan dan menggabungkan Hari Libur + if (eventName == 'Hari Idul Fitri') + eventName = eventName.replace('Hari', '').trim(); + else if (eventName == 'Natal (Hari Tinju)' || eventName == 'Malam Natal') + eventName = 'Hari Raya Natal'; + + const exist = events.find((event) => { + return event.holiday_name + .toLowerCase() + .includes(eventName.toLowerCase()); + }); + + if (exist) { + Object.assign(exist, { + end_date: item.start.date, + total_day: exist.total_day + 1, + }); + } else { + events.push({ + holiday_name: eventName, + start_date: item.start?.date, + end_date: item.start?.date, + total_day: 1, + }); + } + }); + + return events; + } +} diff --git a/src/modules/configuration/google-calendar/google-calendar.module.ts b/src/modules/configuration/google-calendar/google-calendar.module.ts new file mode 100644 index 0000000..e3659cc --- /dev/null +++ b/src/modules/configuration/google-calendar/google-calendar.module.ts @@ -0,0 +1,13 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { CqrsModule } from '@nestjs/cqrs'; +import { IndexHolidayCalendarManager } from '../../configuration/google-calendar/domain/usecases/managers/index-holiday-google-calendar.manager'; +import { GoogleCalendarController } from './infrastructure/google-calendar.controller'; +import { GoogleCalendarOrchestrator } from './domain/usecases/google-calendar.orchestrator'; + +@Module({ + imports: [ConfigModule.forRoot(), CqrsModule], + controllers: [GoogleCalendarController], + providers: [IndexHolidayCalendarManager, GoogleCalendarOrchestrator], +}) +export class GoogleCalendarModule {} diff --git a/src/modules/configuration/google-calendar/index.ts b/src/modules/configuration/google-calendar/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/configuration/google-calendar/infrastructure/google-calendar.controller.ts b/src/modules/configuration/google-calendar/infrastructure/google-calendar.controller.ts new file mode 100644 index 0000000..0cee860 --- /dev/null +++ b/src/modules/configuration/google-calendar/infrastructure/google-calendar.controller.ts @@ -0,0 +1,16 @@ +import { GoogleCalendarOrchestrator } from './../domain/usecases/google-calendar.orchestrator'; +import { Controller, Get } from '@nestjs/common'; +import { ApiTags } from '@nestjs/swagger'; +import { Public } from 'src/core/guards'; + +@ApiTags(`google calendar - read`) +@Controller('google-calendar') +@Public(true) +export class GoogleCalendarController { + constructor(private orchestrator: GoogleCalendarOrchestrator) {} + + @Get('/holiday') + async calendar() { + return await this.orchestrator.holiday(); + } +} From 5b5c3efcccf4749077d5d3a2e8703487b3369560 Mon Sep 17 00:00:00 2001 From: ashar Date: Thu, 20 Jun 2024 01:46:09 +0700 Subject: [PATCH 2/5] feat(SPG-355) REST API Read Season Period --- .../services/season-period-read.service.ts | 17 ++++ .../entities/filter-season-period.entity.ts | 9 +++ .../managers/detail-season-period.manager.ts | 56 +++++++++++++ .../index-holiday-google-calendar.manager.ts | 53 ------------- .../managers/index-season-period.manager.ts | 79 +++++++++++++++++++ .../season-period-read.orchestrator.ts | 33 ++++++++ .../dto/filter-season-period.dto.ts | 28 +++++++ .../season-period-read.controller.ts | 30 +++++++ 8 files changed, 252 insertions(+), 53 deletions(-) create mode 100644 src/modules/season-related/season-period/data/services/season-period-read.service.ts create mode 100644 src/modules/season-related/season-period/domain/entities/filter-season-period.entity.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/detail-season-period.manager.ts delete mode 100644 src/modules/season-related/season-period/domain/usecases/managers/index-holiday-google-calendar.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/index-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/season-period-read.orchestrator.ts create mode 100644 src/modules/season-related/season-period/infrastructure/dto/filter-season-period.dto.ts create mode 100644 src/modules/season-related/season-period/infrastructure/season-period-read.controller.ts diff --git a/src/modules/season-related/season-period/data/services/season-period-read.service.ts b/src/modules/season-related/season-period/data/services/season-period-read.service.ts new file mode 100644 index 0000000..8384f0a --- /dev/null +++ b/src/modules/season-related/season-period/data/services/season-period-read.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { SeasonPeriodEntity } from '../../domain/entities/season-period.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { SeasonPeriodModel } from '../models/season-period.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 SeasonPeriodReadService extends BaseReadService { + constructor( + @InjectRepository(SeasonPeriodModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/season-related/season-period/domain/entities/filter-season-period.entity.ts b/src/modules/season-related/season-period/domain/entities/filter-season-period.entity.ts new file mode 100644 index 0000000..0dc158d --- /dev/null +++ b/src/modules/season-related/season-period/domain/entities/filter-season-period.entity.ts @@ -0,0 +1,9 @@ +import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity'; +import { EnumDays } from '../../constants'; + +export interface FilterSeasonPeriodEntity extends BaseFilterEntity { + start_date: Date; + end_date: Date; + holiday_names: string[]; + days: EnumDays[]; +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/detail-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/detail-season-period.manager.ts new file mode 100644 index 0000000..c99528c --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/detail-season-period.manager.ts @@ -0,0 +1,56 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDetailManager } from 'src/core/modules/domain/usecase/managers/base-detail.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { RelationParam } from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class DetailSeasonPeriodManager 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: ['season_type'], + + // relation join and select (relasi yang ingin ditampilkan), + selectRelations: [], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.created_at`, + `${this.tableName}.creator_name`, + `${this.tableName}.editor_name`, + `${this.tableName}.updated_at`, + `${this.tableName}.status`, + `${this.tableName}.start_date`, + `${this.tableName}.end_date`, + `${this.tableName}.days`, + `${this.tableName}.holiday_name`, + + 'season_type.id', + 'season_type.name', + ]; + } + + get setFindProperties(): any { + return { + id: this.dataId, + }; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/index-holiday-google-calendar.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/index-holiday-google-calendar.manager.ts deleted file mode 100644 index e1c52c3..0000000 --- a/src/modules/season-related/season-period/domain/usecases/managers/index-holiday-google-calendar.manager.ts +++ /dev/null @@ -1,53 +0,0 @@ -import { Injectable } from '@nestjs/common'; -import { google } from 'googleapis'; - -@Injectable() -export class IndexHolidayCalendarManager { - async execute() { - const events = []; - const calendar = google.calendar({ - version: 'v3', - auth: 'AIzaSyCsCt6PDd6uYLkahvtdvCoMWf-1_QaLiNM', - }); - const calendarId = 'id.indonesian#holiday@group.v.calendar.google.com'; - - const res = await calendar.events.list({ - calendarId: calendarId, - timeMin: new Date().getFullYear() + '-01-01T00:00:00Z', - timeMax: new Date().getFullYear() + '-12-31T23:59:59Z', - singleEvents: true, - orderBy: 'startTime', - }); - - res.data.items?.forEach((item) => { - // const eventName = item.summary.replace("Joint", "").replace("for", "").replace("after", "").replace("Holiday","").trim(); - let eventName = item.summary.replace('Cuti Bersama', '').trim(); - - // function ini untuk menyamakan dan menggabungkan Hari Libur - if (eventName == 'Hari Idul Fitri') - eventName = eventName.replace('Hari', '').trim(); - else if (eventName == 'Natal (Hari Tinju)' || eventName == 'Malam Natal') - eventName = 'Hari Raya Natal'; - - const exist = events.find((event) => { - return event.name.toLowerCase().includes(eventName.toLowerCase()); - }); - - if (exist) { - Object.assign(exist, { - end_date: item.start.date, - total_day: exist.total_day + 1, - }); - } else { - events.push({ - name: eventName, - start_date: item.start?.date, - end_date: item.start?.date, - total_day: 1, - }); - } - }); - - return events; - } -} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/index-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/index-season-period.manager.ts new file mode 100644 index 0000000..62dec43 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/index-season-period.manager.ts @@ -0,0 +1,79 @@ +import { Injectable } from '@nestjs/common'; +import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { SelectQueryBuilder } from 'typeorm'; +import { + Param, + RelationParam, +} from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class IndexSeasonPeriodManager 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: ['season_type'], + + // relation join and select (relasi yang ingin ditampilkan), + selectRelations: [], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${this.tableName}.id`, + `${this.tableName}.created_at`, + `${this.tableName}.creator_name`, + `${this.tableName}.editor_name`, + `${this.tableName}.updated_at`, + `${this.tableName}.status`, + `${this.tableName}.start_date`, + `${this.tableName}.end_date`, + `${this.tableName}.days`, + `${this.tableName}.holiday_name`, + + 'season_type.id', + 'season_type.name', + ]; + } + + get specificFilter(): Param[] { + return [ + { + cols: `${this.tableName}.holiday_name`, + data: this.filterParam.holiday_names, + }, + ]; + } + + setQueryFilter( + queryBuilder: SelectQueryBuilder, + ): SelectQueryBuilder { + if (this.filterParam.start_date && this.filterParam.end_date) { + queryBuilder.andWhere( + `${this.tableName}.start_date BETWEEN :from AND :to`, + { + from: this.filterParam.start_date, + to: this.filterParam.end_date, + }, + ); + } + + return queryBuilder; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/season-period-read.orchestrator.ts b/src/modules/season-related/season-period/domain/usecases/season-period-read.orchestrator.ts new file mode 100644 index 0000000..36ae641 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/season-period-read.orchestrator.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { IndexSeasonPeriodManager } from './managers/index-season-period.manager'; +import { SeasonPeriodReadService } from '../../data/services/season-period-read.service'; +import { SeasonPeriodEntity } from '../entities/season-period.entity'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; +import { DetailSeasonPeriodManager } from './managers/detail-season-period.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class SeasonPeriodReadOrchestrator extends BaseReadOrchestrator { + constructor( + private indexManager: IndexSeasonPeriodManager, + private detailManager: DetailSeasonPeriodManager, + private serviceData: SeasonPeriodReadService, + ) { + super(); + } + + async index(params): Promise> { + this.indexManager.setFilterParam(params); + this.indexManager.setService(this.serviceData, TABLE_NAME.SEASON_PERIOD); + await this.indexManager.execute(); + return this.indexManager.getResult(); + } + + async detail(dataId: string): Promise { + this.detailManager.setData(dataId); + this.detailManager.setService(this.serviceData, TABLE_NAME.SEASON_PERIOD); + await this.detailManager.execute(); + return this.detailManager.getResult(); + } +} diff --git a/src/modules/season-related/season-period/infrastructure/dto/filter-season-period.dto.ts b/src/modules/season-related/season-period/infrastructure/dto/filter-season-period.dto.ts new file mode 100644 index 0000000..b2a438a --- /dev/null +++ b/src/modules/season-related/season-period/infrastructure/dto/filter-season-period.dto.ts @@ -0,0 +1,28 @@ +import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto'; +import { FilterSeasonPeriodEntity } from '../../domain/entities/filter-season-period.entity'; +import { EnumDays } from '../../constants'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; + +export class FilterSeasonPeriodDto + extends BaseFilterDto + implements FilterSeasonPeriodEntity +{ + @ApiProperty({ type: Date, required: false }) + start_date: Date; + + @ApiProperty({ type: Date, required: false }) + end_date: Date; + + @ApiProperty({ type: ['string'], required: false }) + @Transform((body) => { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + holiday_names: string[]; + + @ApiProperty({ type: ['string'], required: false }) + @Transform((body) => { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + days: EnumDays[]; +} diff --git a/src/modules/season-related/season-period/infrastructure/season-period-read.controller.ts b/src/modules/season-related/season-period/infrastructure/season-period-read.controller.ts new file mode 100644 index 0000000..5d64393 --- /dev/null +++ b/src/modules/season-related/season-period/infrastructure/season-period-read.controller.ts @@ -0,0 +1,30 @@ +import { Controller, Get, Param, Query } from '@nestjs/common'; +import { FilterSeasonPeriodDto } from './dto/filter-season-period.dto'; +import { Pagination } from 'src/core/response'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { SeasonPeriodEntity } from '../domain/entities/season-period.entity'; +import { SeasonPeriodReadOrchestrator } from '../domain/usecases/season-period-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.SEASON_PERIOD.split('-').join(' ')} - read`) +@Controller(MODULE_NAME.SEASON_PERIOD) +@Public(false) +@ApiBearerAuth('JWT') +export class SeasonPeriodReadController { + constructor(private orchestrator: SeasonPeriodReadOrchestrator) {} + + @Get() + @Pagination() + async index( + @Query() params: FilterSeasonPeriodDto, + ): Promise> { + return await this.orchestrator.index(params); + } + + @Get(':id') + async detail(@Param('id') id: string): Promise { + return await this.orchestrator.detail(id); + } +} From 54c5738676c7f5bab7ce5a74b5a14554413f4468 Mon Sep 17 00:00:00 2001 From: ashar Date: Thu, 20 Jun 2024 01:46:59 +0700 Subject: [PATCH 3/5] feat(SPG-353) REST API CUD Season Period --- src/app.module.ts | 14 ++- .../modules/data/service/base-data.service.ts | 9 ++ .../usecase/managers/base-create.manager.ts | 15 ++- .../strings/constants/module.constants.ts | 2 + src/core/strings/constants/table.constants.ts | 2 + .../1718675739425-update-column-tax.ts | 25 ++-- .../migrations/1718699373958-season-period.ts | 25 ++++ .../season-related/season-period/constants.ts | 9 ++ .../data/models/season-period.model.ts | 42 +++++++ .../services/season-period-data.service.ts | 17 +++ .../season-period-change-status.event.ts | 5 + .../event/season-period-created.event.ts | 5 + .../event/season-period-deleted.event.ts | 5 + .../event/season-period-updated.event.ts | 5 + .../domain/entities/season-period.entity.ts | 9 ++ .../handlers/season-period-created.handler.ts | 51 ++++++++ .../managers/active-season-period.manager.ts | 45 +++++++ .../batch-active-season-period.manager.ts | 45 +++++++ .../batch-confirm-season-period.manager.ts | 45 +++++++ .../batch-delete-season-period.manager.ts | 45 +++++++ .../batch-inactive-season-period.manager.ts | 45 +++++++ .../managers/confirm-season-period.manager.ts | 45 +++++++ .../managers/create-season-period.manager.ts | 44 +++++++ .../managers/delete-season-period.manager.ts | 45 +++++++ .../inactive-season-period.manager.ts | 45 +++++++ .../managers/update-season-period.manager.ts | 46 +++++++ .../season-period-data.orchestrator.ts | 118 ++++++++++++++++++ .../season-related/season-period/index.ts | 0 .../dto/season-period-holiday.dto.ts | 24 ++++ .../infrastructure/dto/season-period.dto.ts | 80 ++++++++++++ .../dto/update-season-period-item.dto.ts | 46 +++++++ .../dto/update-season-period.dto.ts | 60 +++++++++ .../season-period-data.controller.ts | 89 +++++++++++++ .../season-period/season-period.module.ts | 57 +++++++++ .../data/models/season-type.model.ts | 9 +- 35 files changed, 1158 insertions(+), 15 deletions(-) create mode 100644 src/database/migrations/1718699373958-season-period.ts create mode 100644 src/modules/season-related/season-period/constants.ts create mode 100644 src/modules/season-related/season-period/data/models/season-period.model.ts create mode 100644 src/modules/season-related/season-period/data/services/season-period-data.service.ts create mode 100644 src/modules/season-related/season-period/domain/entities/event/season-period-change-status.event.ts create mode 100644 src/modules/season-related/season-period/domain/entities/event/season-period-created.event.ts create mode 100644 src/modules/season-related/season-period/domain/entities/event/season-period-deleted.event.ts create mode 100644 src/modules/season-related/season-period/domain/entities/event/season-period-updated.event.ts create mode 100644 src/modules/season-related/season-period/domain/entities/season-period.entity.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/handlers/season-period-created.handler.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/active-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/batch-active-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/batch-confirm-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/batch-delete-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/batch-inactive-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/confirm-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/create-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/delete-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/inactive-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/update-season-period.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/season-period-data.orchestrator.ts create mode 100644 src/modules/season-related/season-period/index.ts create mode 100644 src/modules/season-related/season-period/infrastructure/dto/season-period-holiday.dto.ts create mode 100644 src/modules/season-related/season-period/infrastructure/dto/season-period.dto.ts create mode 100644 src/modules/season-related/season-period/infrastructure/dto/update-season-period-item.dto.ts create mode 100644 src/modules/season-related/season-period/infrastructure/dto/update-season-period.dto.ts create mode 100644 src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts create mode 100644 src/modules/season-related/season-period/season-period.module.ts diff --git a/src/app.module.ts b/src/app.module.ts index 7bf0036..f430b37 100644 --- a/src/app.module.ts +++ b/src/app.module.ts @@ -37,6 +37,11 @@ import { SalesPriceFormulaModel } from './modules/transaction/sales-price-formul import { ProfitShareFormulaModule } from './modules/transaction/profit-share-formula/profit-share-formula.module'; import { PaymentMethodModule } from './modules/transaction/payment-method/payment-method.module'; import { PaymentMethodModel } from './modules/transaction/payment-method/data/models/payment-method.model'; +import { SeasonPeriodModule } from './modules/season-related/season-period/season-period.module'; +import { SeasonPeriodModel } from './modules/season-related/season-period/data/models/season-period.model'; +import { ItemRateModule } from './modules/item-related/item-rate/item-rate.module'; +import { ItemRateModel } from './modules/item-related/item-rate/data/models/item-rate.model'; +import { GoogleCalendarModule } from './modules/configuration/google-calendar/google-calendar.module'; @Module({ imports: [ @@ -57,9 +62,11 @@ import { PaymentMethodModel } from './modules/transaction/payment-method/data/mo ErrorLogModel, ItemModel, ItemCategoryModel, + ItemRateModel, LogModel, PaymentMethodModel, SalesPriceFormulaModel, + SeasonPeriodModel, SeasonTypeModel, TaxModel, UserModel, @@ -68,12 +75,13 @@ import { PaymentMethodModel } from './modules/transaction/payment-method/data/mo ], synchronize: false, }), + AuthModule, ConstantModule, CqrsModule, - SessionModule, - AuthModule, CouchModule, + GoogleCalendarModule, LogModule, + SessionModule, // user TenantModule, @@ -83,6 +91,7 @@ import { PaymentMethodModel } from './modules/transaction/payment-method/data/mo // Item ItemCategoryModule, ItemModule, + ItemRateModule, // transaction PaymentMethodModule, @@ -94,6 +103,7 @@ import { PaymentMethodModel } from './modules/transaction/payment-method/data/mo // session SeasonTypeModule, + SeasonPeriodModule, ], controllers: [], providers: [ diff --git a/src/core/modules/data/service/base-data.service.ts b/src/core/modules/data/service/base-data.service.ts index b957808..dafd592 100644 --- a/src/core/modules/data/service/base-data.service.ts +++ b/src/core/modules/data/service/base-data.service.ts @@ -21,6 +21,15 @@ export abstract class BaseDataService { return await queryRunner.manager.save(newEntity); } + async createBatch( + queryRunner: QueryRunner, + entityTarget: EntityTarget, + entity: Entity[], + ): Promise { + const newEntity = queryRunner.manager.create(entityTarget, entity); + return await queryRunner.manager.save(newEntity); + } + async update( queryRunner: QueryRunner, entityTarget: EntityTarget, diff --git a/src/core/modules/domain/usecase/managers/base-create.manager.ts b/src/core/modules/domain/usecase/managers/base-create.manager.ts index 61e08a4..fdfb694 100644 --- a/src/core/modules/domain/usecase/managers/base-create.manager.ts +++ b/src/core/modules/domain/usecase/managers/base-create.manager.ts @@ -73,6 +73,19 @@ export abstract class BaseCreateManager extends BaseManager { }), ); - // if (!this.eventTopics.length) return; + if (!this.eventTopics.length) return; + for (const topic of this.eventTopics) { + this.eventBus.publishAll([ + new topic.topic({ + id: this.result['id'], + old: null, + data: topic.data, + user: this.user, + description: '', + module: this.tableName, + op: OPERATION.CREATE, + }), + ]); + } } } diff --git a/src/core/strings/constants/module.constants.ts b/src/core/strings/constants/module.constants.ts index d5579b7..ccc5889 100644 --- a/src/core/strings/constants/module.constants.ts +++ b/src/core/strings/constants/module.constants.ts @@ -1,8 +1,10 @@ export enum MODULE_NAME { ITEM = 'items', ITEM_CATEGORY = 'item-categories', + ITEM_RATE = 'item-rates', PAYMENT_METHOD = 'payment-methods', SEASON_TYPE = 'season-types', + SEASON_PERIOD = 'season-periods', TAX = 'taxes', TENANT = 'tenants', USER = 'users', diff --git a/src/core/strings/constants/table.constants.ts b/src/core/strings/constants/table.constants.ts index aeec40a..16f7897 100644 --- a/src/core/strings/constants/table.constants.ts +++ b/src/core/strings/constants/table.constants.ts @@ -2,10 +2,12 @@ export enum TABLE_NAME { ERROR_LOG = 'log_errors', ITEM = 'items', ITEM_CATEGORY = 'item_categories', + ITEM_RATE = 'item_rates', LOG = 'logs', PAYMENT_METHOD = 'payment_methods', PRICE_FORMULA = 'price_formulas', SEASON_TYPE = 'season_types', + SEASON_PERIOD = 'season_periods', TAX = 'taxes', TENANT = 'tenants', USER = 'users', diff --git a/src/database/migrations/1718675739425-update-column-tax.ts b/src/database/migrations/1718675739425-update-column-tax.ts index 78a58a9..2cd829c 100644 --- a/src/database/migrations/1718675739425-update-column-tax.ts +++ b/src/database/migrations/1718675739425-update-column-tax.ts @@ -1,16 +1,19 @@ -import { MigrationInterface, QueryRunner } from "typeorm"; +import { MigrationInterface, QueryRunner } from 'typeorm'; export class UpdateColumnTax1718675739425 implements MigrationInterface { - name = 'UpdateColumnTax1718675739425' + name = 'UpdateColumnTax1718675739425'; - public async up(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "taxes" DROP COLUMN "value"`); - await queryRunner.query(`ALTER TABLE "taxes" ADD "value" double precision NOT NULL DEFAULT '0'`); - } - - public async down(queryRunner: QueryRunner): Promise { - await queryRunner.query(`ALTER TABLE "taxes" DROP COLUMN "value"`); - await queryRunner.query(`ALTER TABLE "taxes" ADD "value" integer NOT NULL DEFAULT '0'`); - } + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "taxes" DROP COLUMN "value"`); + await queryRunner.query( + `ALTER TABLE "taxes" ADD "value" double precision NOT NULL DEFAULT '0'`, + ); + } + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query(`ALTER TABLE "taxes" DROP COLUMN "value"`); + await queryRunner.query( + `ALTER TABLE "taxes" ADD "value" integer NOT NULL DEFAULT '0'`, + ); + } } diff --git a/src/database/migrations/1718699373958-season-period.ts b/src/database/migrations/1718699373958-season-period.ts new file mode 100644 index 0000000..32f479d --- /dev/null +++ b/src/database/migrations/1718699373958-season-period.ts @@ -0,0 +1,25 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class SeasonPeriod1718699373958 implements MigrationInterface { + name = 'SeasonPeriod1718699373958'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TYPE "public"."season_periods_status_enum" AS ENUM('active', 'cancel', 'confirmed', 'draft', 'expired', 'inactive', 'pending', 'refunded', 'rejected', 'settled', 'waiting')`, + ); + await queryRunner.query( + `CREATE TABLE "season_periods" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "creator_id" character varying(36), "creator_name" character varying(125), "editor_id" character varying(36), "editor_name" character varying(125), "created_at" bigint NOT NULL, "updated_at" bigint NOT NULL, "status" "public"."season_periods_status_enum" NOT NULL DEFAULT 'draft', "start_date" date, "end_date" date, "days" text, "holiday_name" character varying, "season_type_id" uuid, CONSTRAINT "PK_8e25cedd8ffb18516de871fb4e0" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `ALTER TABLE "season_periods" ADD CONSTRAINT "FK_4e9e71a640b450d23177c2add46" FOREIGN KEY ("season_type_id") REFERENCES "season_types"("id") ON DELETE CASCADE ON UPDATE CASCADE`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "season_periods" DROP CONSTRAINT "FK_4e9e71a640b450d23177c2add46"`, + ); + await queryRunner.query(`DROP TABLE "season_periods"`); + await queryRunner.query(`DROP TYPE "public"."season_periods_status_enum"`); + } +} diff --git a/src/modules/season-related/season-period/constants.ts b/src/modules/season-related/season-period/constants.ts new file mode 100644 index 0000000..eb97255 --- /dev/null +++ b/src/modules/season-related/season-period/constants.ts @@ -0,0 +1,9 @@ +export enum EnumDays { + MONDAY = 'senin', + TUESDAY = 'selasa', + WEDNESDAY = 'rabu', + THURSDAY = 'kamis', + FRIDAY = 'jumat', + SATURDAY = 'sabtu', + SUNDAY = 'minggu', +} diff --git a/src/modules/season-related/season-period/data/models/season-period.model.ts b/src/modules/season-related/season-period/data/models/season-period.model.ts new file mode 100644 index 0000000..b364ee8 --- /dev/null +++ b/src/modules/season-related/season-period/data/models/season-period.model.ts @@ -0,0 +1,42 @@ +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { SeasonPeriodEntity } from '../../domain/entities/season-period.entity'; +import { Column, Entity, JoinColumn, ManyToOne, OneToMany } from 'typeorm'; +import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; +import { EnumDays } from '../../constants'; +import { SeasonTypeModel } from 'src/modules/season-related/season-type/data/models/season-type.model'; +import { ItemRateModel } from 'src/modules/item-related/item-rate/data/models/item-rate.model'; + +@Entity(TABLE_NAME.SEASON_PERIOD) +export class SeasonPeriodModel + extends BaseStatusModel + implements SeasonPeriodEntity +{ + @Column('date', { name: 'start_date', nullable: true }) + start_date: Date; + + @Column('date', { name: 'end_date', nullable: true }) + end_date: Date; + + @Column('simple-array', { name: 'days', nullable: true }) + days: EnumDays[]; + + @Column('varchar', { name: 'holiday_name', nullable: true }) + holiday_name: string; + + @Column('varchar', { name: 'season_type_id', nullable: true }) + season_type_id: string; + @ManyToOne(() => SeasonTypeModel, (model) => model.season_periods, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + @JoinColumn({ name: 'season_type_id' }) + season_type: SeasonTypeModel; + + // relasi ke item rates + @OneToMany(() => ItemRateModel, (model) => model.season_period, { + cascade: true, + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + item_rates: ItemRateModel[]; +} diff --git a/src/modules/season-related/season-period/data/services/season-period-data.service.ts b/src/modules/season-related/season-period/data/services/season-period-data.service.ts new file mode 100644 index 0000000..f0e76cd --- /dev/null +++ b/src/modules/season-related/season-period/data/services/season-period-data.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDataService } from 'src/core/modules/data/service/base-data.service'; +import { SeasonPeriodEntity } from '../../domain/entities/season-period.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { SeasonPeriodModel } from '../models/season-period.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; + +@Injectable() +export class SeasonPeriodDataService extends BaseDataService { + constructor( + @InjectRepository(SeasonPeriodModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/season-related/season-period/domain/entities/event/season-period-change-status.event.ts b/src/modules/season-related/season-period/domain/entities/event/season-period-change-status.event.ts new file mode 100644 index 0000000..b470de9 --- /dev/null +++ b/src/modules/season-related/season-period/domain/entities/event/season-period-change-status.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class SeasonPeriodChangeStatusEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/season-related/season-period/domain/entities/event/season-period-created.event.ts b/src/modules/season-related/season-period/domain/entities/event/season-period-created.event.ts new file mode 100644 index 0000000..85efc72 --- /dev/null +++ b/src/modules/season-related/season-period/domain/entities/event/season-period-created.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class SeasonPeriodCreatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/season-related/season-period/domain/entities/event/season-period-deleted.event.ts b/src/modules/season-related/season-period/domain/entities/event/season-period-deleted.event.ts new file mode 100644 index 0000000..220e025 --- /dev/null +++ b/src/modules/season-related/season-period/domain/entities/event/season-period-deleted.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class SeasonPeriodDeletedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/season-related/season-period/domain/entities/event/season-period-updated.event.ts b/src/modules/season-related/season-period/domain/entities/event/season-period-updated.event.ts new file mode 100644 index 0000000..381c333 --- /dev/null +++ b/src/modules/season-related/season-period/domain/entities/event/season-period-updated.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class SeasonPeriodUpdatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/season-related/season-period/domain/entities/season-period.entity.ts b/src/modules/season-related/season-period/domain/entities/season-period.entity.ts new file mode 100644 index 0000000..58298e5 --- /dev/null +++ b/src/modules/season-related/season-period/domain/entities/season-period.entity.ts @@ -0,0 +1,9 @@ +import { BaseStatusEntity } from 'src/core/modules/domain/entities/base-status.entity'; +import { EnumDays } from '../../constants'; + +export interface SeasonPeriodEntity extends BaseStatusEntity { + start_date: Date; + end_date: Date; + days: EnumDays[]; + holiday_name: string; +} diff --git a/src/modules/season-related/season-period/domain/usecases/handlers/season-period-created.handler.ts b/src/modules/season-related/season-period/domain/usecases/handlers/season-period-created.handler.ts new file mode 100644 index 0000000..0ed9424 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/handlers/season-period-created.handler.ts @@ -0,0 +1,51 @@ +import { EventsHandler, IEventHandler } from '@nestjs/cqrs'; +import { SeasonPeriodCreatedEvent } from '../../entities/event/season-period-created.event'; +import { SeasonPeriodDataService } from '../../../data/services/season-period-data.service'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; + +@EventsHandler(SeasonPeriodCreatedEvent) +export class SeasonPeriodHolidayHandler + implements IEventHandler +{ + constructor(private dataService: SeasonPeriodDataService) {} + + async handle(event: SeasonPeriodCreatedEvent) { + const queryRunner = this.dataService + .getRepository() + .manager.connection.createQueryRunner(); + const holidayDates = []; + + if (event.data.data.holidays?.length) { + // foreach holiday + for (const holiday of event.data.data.holidays) { + const holidayDate = new SeasonPeriodModel(); + + holidayDate.holiday_name = holiday.holiday_name; + holidayDate.start_date = holiday.start_date; + holidayDate.end_date = holiday.end_date; + holidayDate.created_at = event.data.data.created_at; + holidayDate.creator_id = event.data.data.creator_id; + holidayDate.creator_name = event.data.data.creator_name; + holidayDate.updated_at = event.data.data.updated_at; + holidayDate.season_type = event.data.data.season_type; + holidayDate.item_rates = event.data.data.item_rates; + + holidayDates.push(holidayDate); + } + + // create batch + await this.dataService.createBatch( + queryRunner, + SeasonPeriodModel, + holidayDates, + ); + + // delete data + await this.dataService.deleteById( + queryRunner, + SeasonPeriodModel, + event.data.id, + ); + } + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/active-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/active-season-period.manager.ts new file mode 100644 index 0000000..e0ab96a --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/active-season-period.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; +import { SeasonPeriodChangeStatusEvent } from '../../entities/event/season-period-change-status.event'; + +@Injectable() +export class ActiveSeasonPeriodManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data ${this.result.id}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return SeasonPeriodModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: SeasonPeriodChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/batch-active-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/batch-active-season-period.manager.ts new file mode 100644 index 0000000..388bbd9 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/batch-active-season-period.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; +import { SeasonPeriodChangeStatusEvent } from '../../entities/event/season-period-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchActiveSeasonPeriodManager extends BaseBatchUpdateStatusManager { + validateData(data: SeasonPeriodEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return SeasonPeriodModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: SeasonPeriodChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/batch-confirm-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/batch-confirm-season-period.manager.ts new file mode 100644 index 0000000..c641fe5 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/batch-confirm-season-period.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; +import { SeasonPeriodChangeStatusEvent } from '../../entities/event/season-period-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchConfirmSeasonPeriodManager extends BaseBatchUpdateStatusManager { + validateData(data: SeasonPeriodEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return SeasonPeriodModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: SeasonPeriodChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/batch-delete-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/batch-delete-season-period.manager.ts new file mode 100644 index 0000000..61cdd16 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/batch-delete-season-period.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchDeleteManager } from 'src/core/modules/domain/usecase/managers/base-batch-delete.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; +import { SeasonPeriodDeletedEvent } from '../../entities/event/season-period-deleted.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchDeleteSeasonPeriodManager extends BaseBatchDeleteManager { + async beforeProcess(): Promise { + return; + } + + async validateData(data: SeasonPeriodEntity): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return SeasonPeriodModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: SeasonPeriodDeletedEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/batch-inactive-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/batch-inactive-season-period.manager.ts new file mode 100644 index 0000000..8b460c4 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/batch-inactive-season-period.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-batch-update-status.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; +import { SeasonPeriodChangeStatusEvent } from '../../entities/event/season-period-change-status.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchInactiveSeasonPeriodManager extends BaseBatchUpdateStatusManager { + validateData(data: SeasonPeriodEntity): Promise { + return; + } + + beforeProcess(): Promise { + return; + } + + afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return SeasonPeriodModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: SeasonPeriodChangeStatusEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/confirm-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/confirm-season-period.manager.ts new file mode 100644 index 0000000..8146592 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/confirm-season-period.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; +import { SeasonPeriodChangeStatusEvent } from '../../entities/event/season-period-change-status.event'; + +@Injectable() +export class ConfirmSeasonPeriodManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success active data ${this.result.id}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return SeasonPeriodModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: SeasonPeriodChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/create-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/create-season-period.manager.ts new file mode 100644 index 0000000..98a332a --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/create-season-period.manager.ts @@ -0,0 +1,44 @@ +import { Injectable } from '@nestjs/common'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; +import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager'; +import { SeasonPeriodCreatedEvent } from '../../entities/event/season-period-created.event'; + +@Injectable() +export class CreateSeasonPeriodManager extends BaseCreateManager { + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: SeasonPeriodCreatedEvent, + data: { + ...this.data, + }, + }, + ]; + } + + get entityTarget(): any { + return SeasonPeriodModel; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/delete-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/delete-season-period.manager.ts new file mode 100644 index 0000000..87cefe1 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/delete-season-period.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; +import { SeasonPeriodDeletedEvent } from '../../entities/event/season-period-deleted.event'; + +@Injectable() +export class DeleteSeasonPeriodManager extends BaseDeleteManager { + getResult(): string { + return `Success`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return SeasonPeriodModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: SeasonPeriodDeletedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/inactive-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/inactive-season-period.manager.ts new file mode 100644 index 0000000..767c9eb --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/inactive-season-period.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateStatusManager } from 'src/core/modules/domain/usecase/managers/base-update-status.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; +import { SeasonPeriodChangeStatusEvent } from '../../entities/event/season-period-change-status.event'; + +@Injectable() +export class InactiveSeasonPeriodManager extends BaseUpdateStatusManager { + getResult(): string { + return `Success inactive data ${this.result.id}`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return SeasonPeriodModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: SeasonPeriodChangeStatusEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/managers/update-season-period.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/update-season-period.manager.ts new file mode 100644 index 0000000..3653184 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/update-season-period.manager.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager'; +import { SeasonPeriodEntity } from '../../entities/season-period.entity'; +import { SeasonPeriodModel } from '../../../data/models/season-period.model'; +import { SeasonPeriodUpdatedEvent } from '../../entities/event/season-period-updated.event'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; + +@Injectable() +export class UpdateSeasonPeriodManager extends BaseUpdateManager { + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get entityTarget(): any { + return SeasonPeriodModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: SeasonPeriodUpdatedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/season-period-data.orchestrator.ts b/src/modules/season-related/season-period/domain/usecases/season-period-data.orchestrator.ts new file mode 100644 index 0000000..804ddaf --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/season-period-data.orchestrator.ts @@ -0,0 +1,118 @@ +import { Injectable } from '@nestjs/common'; +import { CreateSeasonPeriodManager } from './managers/create-season-period.manager'; +import { SeasonPeriodDataService } from '../../data/services/season-period-data.service'; +import { SeasonPeriodEntity } from '../entities/season-period.entity'; +import { DeleteSeasonPeriodManager } from './managers/delete-season-period.manager'; +import { UpdateSeasonPeriodManager } from './managers/update-season-period.manager'; +import { BaseDataTransactionOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-data-transaction.orchestrator'; +import { ActiveSeasonPeriodManager } from './managers/active-season-period.manager'; +import { InactiveSeasonPeriodManager } from './managers/inactive-season-period.manager'; +import { ConfirmSeasonPeriodManager } from './managers/confirm-season-period.manager'; +import { STATUS } from 'src/core/strings/constants/base.constants'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchConfirmSeasonPeriodManager } from './managers/batch-confirm-season-period.manager'; +import { BatchInactiveSeasonPeriodManager } from './managers/batch-inactive-season-period.manager'; +import { BatchActiveSeasonPeriodManager } from './managers/batch-active-season-period.manager'; +import { BatchDeleteSeasonPeriodManager } from './managers/batch-delete-season-period.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class SeasonPeriodDataOrchestrator extends BaseDataTransactionOrchestrator { + constructor( + private createManager: CreateSeasonPeriodManager, + private updateManager: UpdateSeasonPeriodManager, + private deleteManager: DeleteSeasonPeriodManager, + private activeManager: ActiveSeasonPeriodManager, + private confirmManager: ConfirmSeasonPeriodManager, + private inactiveManager: InactiveSeasonPeriodManager, + private batchDeleteManager: BatchDeleteSeasonPeriodManager, + private batchActiveManager: BatchActiveSeasonPeriodManager, + private batchConfirmManager: BatchConfirmSeasonPeriodManager, + private batchInactiveManager: BatchInactiveSeasonPeriodManager, + private serviceData: SeasonPeriodDataService, + ) { + super(); + } + + async create(data): Promise { + this.createManager.setData(data); + this.createManager.setService(this.serviceData, TABLE_NAME.SEASON_PERIOD); + await this.createManager.execute(); + return this.createManager.getResult(); + } + + async update(dataId, data): Promise { + this.updateManager.setData(dataId, data); + this.updateManager.setService(this.serviceData, TABLE_NAME.SEASON_PERIOD); + await this.updateManager.execute(); + return this.updateManager.getResult(); + } + + async delete(dataId): Promise { + this.deleteManager.setData(dataId); + this.deleteManager.setService(this.serviceData, TABLE_NAME.SEASON_PERIOD); + await this.deleteManager.execute(); + return this.deleteManager.getResult(); + } + + async batchDelete(dataIds: string[]): Promise { + this.batchDeleteManager.setData(dataIds); + this.batchDeleteManager.setService( + this.serviceData, + TABLE_NAME.SEASON_PERIOD, + ); + await this.batchDeleteManager.execute(); + return this.batchDeleteManager.getResult(); + } + + async active(dataId): Promise { + this.activeManager.setData(dataId, STATUS.ACTIVE); + this.activeManager.setService(this.serviceData, TABLE_NAME.SEASON_PERIOD); + await this.activeManager.execute(); + return this.activeManager.getResult(); + } + + async batchActive(dataIds: string[]): Promise { + this.batchActiveManager.setData(dataIds, STATUS.ACTIVE); + this.batchActiveManager.setService( + this.serviceData, + TABLE_NAME.SEASON_PERIOD, + ); + await this.batchActiveManager.execute(); + return this.batchActiveManager.getResult(); + } + + async confirm(dataId): Promise { + this.confirmManager.setData(dataId, STATUS.ACTIVE); + this.confirmManager.setService(this.serviceData, TABLE_NAME.SEASON_PERIOD); + await this.confirmManager.execute(); + return this.confirmManager.getResult(); + } + + async batchConfirm(dataIds: string[]): Promise { + this.batchConfirmManager.setData(dataIds, STATUS.ACTIVE); + this.batchConfirmManager.setService( + this.serviceData, + TABLE_NAME.SEASON_PERIOD, + ); + await this.batchConfirmManager.execute(); + return this.batchConfirmManager.getResult(); + } + + async inactive(dataId): Promise { + this.inactiveManager.setData(dataId, STATUS.INACTIVE); + this.inactiveManager.setService(this.serviceData, TABLE_NAME.SEASON_PERIOD); + await this.inactiveManager.execute(); + return this.inactiveManager.getResult(); + } + + async batchInactive(dataIds: string[]): Promise { + this.batchInactiveManager.setData(dataIds, STATUS.INACTIVE); + this.batchInactiveManager.setService( + this.serviceData, + TABLE_NAME.SEASON_PERIOD, + ); + await this.batchInactiveManager.execute(); + return this.batchInactiveManager.getResult(); + } +} diff --git a/src/modules/season-related/season-period/index.ts b/src/modules/season-related/season-period/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/season-related/season-period/infrastructure/dto/season-period-holiday.dto.ts b/src/modules/season-related/season-period/infrastructure/dto/season-period-holiday.dto.ts new file mode 100644 index 0000000..db9aa24 --- /dev/null +++ b/src/modules/season-related/season-period/infrastructure/dto/season-period-holiday.dto.ts @@ -0,0 +1,24 @@ +import { ApiProperty } from '@nestjs/swagger'; + +export class SeasonPeriodHolidayDto { + @ApiProperty({ + type: Date, + required: true, + example: '01/01/2024', + }) + start_date: Date; + + @ApiProperty({ + type: Date, + required: true, + example: '30/12/2024', + }) + end_date: Date; + + @ApiProperty({ + type: Date, + required: true, + example: 'Hari Raya', + }) + holiday_name: string; +} diff --git a/src/modules/season-related/season-period/infrastructure/dto/season-period.dto.ts b/src/modules/season-related/season-period/infrastructure/dto/season-period.dto.ts new file mode 100644 index 0000000..241a3fe --- /dev/null +++ b/src/modules/season-related/season-period/infrastructure/dto/season-period.dto.ts @@ -0,0 +1,80 @@ +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { SeasonPeriodEntity } from '../../domain/entities/season-period.entity'; +import { EnumDays } from '../../constants'; +import { ApiProperty } from '@nestjs/swagger'; +import { IsObject, ValidateIf, ValidateNested } from 'class-validator'; +import { Exclude } from 'class-transformer'; +import { SeasonTypeModel } from 'src/modules/season-related/season-type/data/models/season-type.model'; +import { SeasonPeriodHolidayDto } from './season-period-holiday.dto'; +import { ItemRateModel } from 'src/modules/item-related/item-rate/data/models/item-rate.model'; +import { ItemDto } from 'src/modules/item-related/item/infrastructure/dto/item.dto'; + +export class SeasonPeriodDto + extends BaseStatusDto + implements SeasonPeriodEntity +{ + @ApiProperty({ + type: Object, + required: true, + example: { + id: 'uuid', + name: 'High Season', + }, + }) + @IsObject() + season_type: SeasonTypeModel; + + @ApiProperty({ + type: Date, + required: true, + example: '2024/01/01', + }) + start_date: Date; + + @ApiProperty({ + type: Date, + required: true, + example: '2024/12/30', + }) + end_date: Date; + + @ApiProperty({ + type: [String], + required: false, + example: [EnumDays.FRIDAY, EnumDays.MONDAY], + }) + @ValidateIf((body) => body.days) + days: EnumDays[]; + + @ApiProperty({ + type: [SeasonPeriodHolidayDto], + required: false, + example: [ + { + start_date: '2024/01/01', + end_date: '2024/12/30', + holiday_name: 'Hari Raya', + }, + ], + }) + @ValidateNested({ each: true }) + @ValidateIf((body) => body.holidays) + holidays: SeasonPeriodHolidayDto[]; + + @Exclude() + holiday_name: string; + + @ApiProperty({ + type: [Object], + example: [ + { + item: { + id: 'uuid', + name: 'Entrance Ticket', + }, + price: 10000, + }, + ], + }) + item_rates: ItemRateModel[]; +} diff --git a/src/modules/season-related/season-period/infrastructure/dto/update-season-period-item.dto.ts b/src/modules/season-related/season-period/infrastructure/dto/update-season-period-item.dto.ts new file mode 100644 index 0000000..7fb5052 --- /dev/null +++ b/src/modules/season-related/season-period/infrastructure/dto/update-season-period-item.dto.ts @@ -0,0 +1,46 @@ +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { SeasonPeriodEntity } from '../../domain/entities/season-period.entity'; +import { EnumDays } from '../../constants'; +import { ApiProperty } from '@nestjs/swagger'; +import { IsObject, ValidateIf, ValidateNested } from 'class-validator'; +import { Exclude } from 'class-transformer'; +import { SeasonTypeModel } from 'src/modules/season-related/season-type/data/models/season-type.model'; +import { SeasonPeriodHolidayDto } from './season-period-holiday.dto'; +import { ItemRateModel } from 'src/modules/item-related/item-rate/data/models/item-rate.model'; + +export class UpdateSeasonPeriodItemDto + extends BaseStatusDto + implements SeasonPeriodEntity +{ + @Exclude() + season_type: SeasonTypeModel; + + @Exclude() + start_date: Date; + + @Exclude() + end_date: Date; + + @Exclude() + days: EnumDays[]; + + @Exclude() + holidays: SeasonPeriodHolidayDto[]; + + @Exclude() + holiday_name: string; + + @ApiProperty({ + type: [Object], + example: [ + { + item: { + id: 'uuid', + name: 'Entrance Ticket', + }, + price: 10000, + }, + ], + }) + item_rates: ItemRateModel[]; +} diff --git a/src/modules/season-related/season-period/infrastructure/dto/update-season-period.dto.ts b/src/modules/season-related/season-period/infrastructure/dto/update-season-period.dto.ts new file mode 100644 index 0000000..e383b62 --- /dev/null +++ b/src/modules/season-related/season-period/infrastructure/dto/update-season-period.dto.ts @@ -0,0 +1,60 @@ +import { BaseStatusDto } from 'src/core/modules/infrastructure/dto/base-status.dto'; +import { SeasonPeriodEntity } from '../../domain/entities/season-period.entity'; +import { EnumDays } from '../../constants'; +import { ApiProperty } from '@nestjs/swagger'; +import { IsObject, ValidateIf } from 'class-validator'; +import { SeasonTypeModel } from 'src/modules/season-related/season-type/data/models/season-type.model'; +import { Exclude } from 'class-transformer'; +import { ItemRateModel } from 'src/modules/item-related/item-rate/data/models/item-rate.model'; +import { SeasonPeriodHolidayDto } from './season-period-holiday.dto'; + +export class UpdateSeasonPeriodDto + extends BaseStatusDto + implements SeasonPeriodEntity +{ + @ApiProperty({ + type: Object, + required: true, + example: { + id: 'uuid', + name: 'High Season', + }, + }) + @IsObject() + season_type: SeasonTypeModel; + + @ApiProperty({ + type: Date, + required: true, + example: '01/01/2024', + }) + start_date: Date; + + @ApiProperty({ + type: Date, + required: true, + example: '30/12/2024', + }) + end_date: Date; + + @ApiProperty({ + type: [String], + required: false, + example: [EnumDays.FRIDAY, EnumDays.MONDAY], + }) + @ValidateIf((body) => body.days) + days: EnumDays[]; + + @ApiProperty({ + type: String, + required: false, + example: 'Hari Raya', + }) + holiday_name: string; + + @Exclude() + holidays: SeasonPeriodHolidayDto[]; + + @Exclude() + item_rates: any[]; +} diff --git a/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts b/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts new file mode 100644 index 0000000..efd3807 --- /dev/null +++ b/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts @@ -0,0 +1,89 @@ +import { + Body, + Controller, + Delete, + Param, + Patch, + Post, + Put, + Get, +} from '@nestjs/common'; +import { SeasonPeriodDataOrchestrator } from '../domain/usecases/season-period-data.orchestrator'; +import { SeasonPeriodDto } from './dto/season-period.dto'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { SeasonPeriodEntity } from '../domain/entities/season-period.entity'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; +import { Public } from 'src/core/guards'; +import { UpdateSeasonPeriodDto } from './dto/update-season-period.dto'; +import { UpdateSeasonPeriodItemDto } from './dto/update-season-period-item.dto'; + +@ApiTags(`${MODULE_NAME.SEASON_PERIOD.split('-').join(' ')} - data`) +@Controller(MODULE_NAME.SEASON_PERIOD) +@Public(false) +@ApiBearerAuth('JWT') +export class SeasonPeriodDataController { + constructor(private orchestrator: SeasonPeriodDataOrchestrator) {} + + @Post() + async create(@Body() data: SeasonPeriodDto): Promise { + return await this.orchestrator.create(data); + } + + @Put('/batch-delete') + async batchDeleted(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchDelete(body.ids); + } + + @Patch(':id/active') + async active(@Param('id') dataId: string): Promise { + return await this.orchestrator.active(dataId); + } + + @Put('/batch-active') + async batchActive(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchActive(body.ids); + } + + @Patch(':id/confirm') + async confirm(@Param('id') dataId: string): Promise { + return await this.orchestrator.confirm(dataId); + } + + @Put('/batch-confirm') + async batchConfirm(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchConfirm(body.ids); + } + + @Patch(':id/inactive') + async inactive(@Param('id') dataId: string): Promise { + return await this.orchestrator.inactive(dataId); + } + + @Put('/batch-inactive') + async batchInactive(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchInactive(body.ids); + } + + @Put(':id') + async update( + @Param('id') dataId: string, + @Body() data: UpdateSeasonPeriodDto, + ): Promise { + return await this.orchestrator.update(dataId, data); + } + + @Put(':id/items') + async updateItems( + @Param('id') dataId: string, + @Body() data: UpdateSeasonPeriodItemDto, + ): Promise { + return await this.orchestrator.update(dataId, data); + } + + @Delete(':id') + async delete(@Param('id') dataId: string): Promise { + return await this.orchestrator.delete(dataId); + } +} diff --git a/src/modules/season-related/season-period/season-period.module.ts b/src/modules/season-related/season-period/season-period.module.ts new file mode 100644 index 0000000..5efb09a --- /dev/null +++ b/src/modules/season-related/season-period/season-period.module.ts @@ -0,0 +1,57 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { SeasonPeriodDataService } from './data/services/season-period-data.service'; +import { SeasonPeriodReadService } from './data/services/season-period-read.service'; +import { SeasonPeriodReadController } from './infrastructure/season-period-read.controller'; +import { SeasonPeriodReadOrchestrator } from './domain/usecases/season-period-read.orchestrator'; +import { SeasonPeriodDataController } from './infrastructure/season-period-data.controller'; +import { SeasonPeriodDataOrchestrator } from './domain/usecases/season-period-data.orchestrator'; +import { CreateSeasonPeriodManager } from './domain/usecases/managers/create-season-period.manager'; +import { CqrsModule } from '@nestjs/cqrs'; +import { IndexSeasonPeriodManager } from './domain/usecases/managers/index-season-period.manager'; +import { DeleteSeasonPeriodManager } from './domain/usecases/managers/delete-season-period.manager'; +import { UpdateSeasonPeriodManager } from './domain/usecases/managers/update-season-period.manager'; +import { ActiveSeasonPeriodManager } from './domain/usecases/managers/active-season-period.manager'; +import { ConfirmSeasonPeriodManager } from './domain/usecases/managers/confirm-season-period.manager'; +import { InactiveSeasonPeriodManager } from './domain/usecases/managers/inactive-season-period.manager'; +import { DetailSeasonPeriodManager } from './domain/usecases/managers/detail-season-period.manager'; +import { BatchDeleteSeasonPeriodManager } from './domain/usecases/managers/batch-delete-season-period.manager'; +import { BatchActiveSeasonPeriodManager } from './domain/usecases/managers/batch-active-season-period.manager'; +import { BatchConfirmSeasonPeriodManager } from './domain/usecases/managers/batch-confirm-season-period.manager'; +import { BatchInactiveSeasonPeriodManager } from './domain/usecases/managers/batch-inactive-season-period.manager'; +import { SeasonPeriodModel } from './data/models/season-period.model'; +import { SeasonPeriodHolidayHandler } from './domain/usecases/handlers/season-period-created.handler'; + +@Module({ + imports: [ + ConfigModule.forRoot(), + TypeOrmModule.forFeature([SeasonPeriodModel], CONNECTION_NAME.DEFAULT), + CqrsModule, + ], + controllers: [SeasonPeriodDataController, SeasonPeriodReadController], + providers: [ + SeasonPeriodHolidayHandler, + + IndexSeasonPeriodManager, + DetailSeasonPeriodManager, + CreateSeasonPeriodManager, + DeleteSeasonPeriodManager, + UpdateSeasonPeriodManager, + ActiveSeasonPeriodManager, + ConfirmSeasonPeriodManager, + InactiveSeasonPeriodManager, + BatchDeleteSeasonPeriodManager, + BatchActiveSeasonPeriodManager, + BatchConfirmSeasonPeriodManager, + BatchInactiveSeasonPeriodManager, + + SeasonPeriodDataService, + SeasonPeriodReadService, + + SeasonPeriodDataOrchestrator, + SeasonPeriodReadOrchestrator, + ], +}) +export class SeasonPeriodModule {} diff --git a/src/modules/season-related/season-type/data/models/season-type.model.ts b/src/modules/season-related/season-type/data/models/season-type.model.ts index ad26020..f8ba5f7 100644 --- a/src/modules/season-related/season-type/data/models/season-type.model.ts +++ b/src/modules/season-related/season-type/data/models/season-type.model.ts @@ -1,7 +1,8 @@ import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; import { SeasonTypeEntity } from '../../domain/entities/season-type.entity'; -import { Column, Entity } from 'typeorm'; +import { Column, Entity, OneToMany } from 'typeorm'; import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; +import { SeasonPeriodModel } from 'src/modules/season-related/season-period/data/models/season-period.model'; @Entity(TABLE_NAME.SEASON_TYPE) export class SeasonTypeModel @@ -10,4 +11,10 @@ export class SeasonTypeModel { @Column('varchar', { name: 'name' }) name: string; + + @OneToMany(() => SeasonPeriodModel, (model) => model.season_type, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + season_periods: SeasonPeriodModel[]; } From 86f81f30278df3a3695d66709cd4786e7bdea5de Mon Sep 17 00:00:00 2001 From: ashar Date: Thu, 20 Jun 2024 01:47:56 +0700 Subject: [PATCH 4/5] feat(SPG-367) REST API CUD Item Rate --- .../migrations/1718792479432-item-rate.ts | 27 +++++++++ .../item-related/item-rate/constants.ts | 0 .../item-rate/data/models/item-rate.model.ts | 35 ++++++++++++ .../data/services/item-rate-data.service.ts | 17 ++++++ .../data/services/item-rate-read.service.ts | 17 ++++++ .../entities/event/item-rate-created.event.ts | 5 ++ .../entities/event/item-rate-deleted.event.ts | 5 ++ .../entities/event/item-rate-updated.event.ts | 5 ++ .../entities/filter-item-rate.entity.ts | 3 + .../domain/entities/item-rate.entity.ts | 7 +++ .../usecases/item-rate-data.orchestrator.ts | 52 ++++++++++++++++++ .../usecases/item-rate-read.orchestrator.ts | 33 +++++++++++ .../batch-delete-item-rate.manager.ts | 45 +++++++++++++++ .../managers/create-item-rate.manager.ts | 42 ++++++++++++++ .../managers/delete-item-rate.manager.ts | 45 +++++++++++++++ .../managers/detail-item-rate.manager.ts | 42 ++++++++++++++ .../managers/index-item-rate.manager.ts | 55 +++++++++++++++++++ .../managers/update-item-rate.manager.ts | 46 ++++++++++++++++ src/modules/item-related/item-rate/index.ts | 0 .../dto/filter-item-rate.dto.ts | 6 ++ .../infrastructure/dto/item-rate.dto.ts | 32 +++++++++++ .../item-rate-data.controller.ts | 40 ++++++++++++++ .../item-rate-read.controller.ts | 30 ++++++++++ .../item-rate/item-rate.module.ts | 42 ++++++++++++++ .../item/data/models/item.model.ts | 9 +++ .../domain/entities/filter-item.entity.ts | 1 + .../usecases/managers/index-item.manager.ts | 2 +- .../infrastructure/dto/filter-item.dto.ts | 7 +++ .../item/infrastructure/dto/item.dto.ts | 6 +- 29 files changed, 654 insertions(+), 2 deletions(-) create mode 100644 src/database/migrations/1718792479432-item-rate.ts create mode 100644 src/modules/item-related/item-rate/constants.ts create mode 100644 src/modules/item-related/item-rate/data/models/item-rate.model.ts create mode 100644 src/modules/item-related/item-rate/data/services/item-rate-data.service.ts create mode 100644 src/modules/item-related/item-rate/data/services/item-rate-read.service.ts create mode 100644 src/modules/item-related/item-rate/domain/entities/event/item-rate-created.event.ts create mode 100644 src/modules/item-related/item-rate/domain/entities/event/item-rate-deleted.event.ts create mode 100644 src/modules/item-related/item-rate/domain/entities/event/item-rate-updated.event.ts create mode 100644 src/modules/item-related/item-rate/domain/entities/filter-item-rate.entity.ts create mode 100644 src/modules/item-related/item-rate/domain/entities/item-rate.entity.ts create mode 100644 src/modules/item-related/item-rate/domain/usecases/item-rate-data.orchestrator.ts create mode 100644 src/modules/item-related/item-rate/domain/usecases/item-rate-read.orchestrator.ts create mode 100644 src/modules/item-related/item-rate/domain/usecases/managers/batch-delete-item-rate.manager.ts create mode 100644 src/modules/item-related/item-rate/domain/usecases/managers/create-item-rate.manager.ts create mode 100644 src/modules/item-related/item-rate/domain/usecases/managers/delete-item-rate.manager.ts create mode 100644 src/modules/item-related/item-rate/domain/usecases/managers/detail-item-rate.manager.ts create mode 100644 src/modules/item-related/item-rate/domain/usecases/managers/index-item-rate.manager.ts create mode 100644 src/modules/item-related/item-rate/domain/usecases/managers/update-item-rate.manager.ts create mode 100644 src/modules/item-related/item-rate/index.ts create mode 100644 src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto.ts create mode 100644 src/modules/item-related/item-rate/infrastructure/dto/item-rate.dto.ts create mode 100644 src/modules/item-related/item-rate/infrastructure/item-rate-data.controller.ts create mode 100644 src/modules/item-related/item-rate/infrastructure/item-rate-read.controller.ts create mode 100644 src/modules/item-related/item-rate/item-rate.module.ts diff --git a/src/database/migrations/1718792479432-item-rate.ts b/src/database/migrations/1718792479432-item-rate.ts new file mode 100644 index 0000000..5c97cb2 --- /dev/null +++ b/src/database/migrations/1718792479432-item-rate.ts @@ -0,0 +1,27 @@ +import { MigrationInterface, QueryRunner } from 'typeorm'; + +export class ItemRate1718792479432 implements MigrationInterface { + name = 'ItemRate1718792479432'; + + public async up(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `CREATE TABLE "item_rates" ("id" uuid NOT NULL DEFAULT uuid_generate_v4(), "item_id" uuid, "season_period_id" uuid, "price" bigint, CONSTRAINT "PK_e3e0cf3b098409533dc20bf1992" PRIMARY KEY ("id"))`, + ); + await queryRunner.query( + `ALTER TABLE "item_rates" ADD CONSTRAINT "FK_2bff76c50f678bdf0c4f93990fc" FOREIGN KEY ("item_id") REFERENCES "items"("id") ON DELETE CASCADE ON UPDATE CASCADE`, + ); + await queryRunner.query( + `ALTER TABLE "item_rates" ADD CONSTRAINT "FK_d309461c7e5a7f83ca596203afa" FOREIGN KEY ("season_period_id") REFERENCES "season_periods"("id") ON DELETE CASCADE ON UPDATE CASCADE`, + ); + } + + public async down(queryRunner: QueryRunner): Promise { + await queryRunner.query( + `ALTER TABLE "item_rates" DROP CONSTRAINT "FK_d309461c7e5a7f83ca596203afa"`, + ); + await queryRunner.query( + `ALTER TABLE "item_rates" DROP CONSTRAINT "FK_2bff76c50f678bdf0c4f93990fc"`, + ); + await queryRunner.query(`DROP TABLE "item_rates"`); + } +} diff --git a/src/modules/item-related/item-rate/constants.ts b/src/modules/item-related/item-rate/constants.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/item-related/item-rate/data/models/item-rate.model.ts b/src/modules/item-related/item-rate/data/models/item-rate.model.ts new file mode 100644 index 0000000..cf1bf78 --- /dev/null +++ b/src/modules/item-related/item-rate/data/models/item-rate.model.ts @@ -0,0 +1,35 @@ +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { ItemRateEntity } from '../../domain/entities/item-rate.entity'; +import { Column, Entity, JoinColumn, ManyToOne } from 'typeorm'; +import { BaseCoreModel } from 'src/core/modules/data/model/base-core.model'; +import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; +import { SeasonPeriodModel } from 'src/modules/season-related/season-period/data/models/season-period.model'; + +@Entity(TABLE_NAME.ITEM_RATE) +export class ItemRateModel + extends BaseCoreModel + implements ItemRateEntity +{ + @Column('varchar', { name: 'item_id', nullable: true }) + item_id: string; + + @ManyToOne(() => ItemModel, (model) => model.item_rates, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + @JoinColumn({ name: 'item_id' }) + item: ItemModel; + + @Column('varchar', { name: 'season_period_id', nullable: true }) + season_period_id: string; + + @ManyToOne(() => SeasonPeriodModel, (model) => model.item_rates, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + @JoinColumn({ name: 'season_period_id' }) + season_period: SeasonPeriodModel; + + @Column('bigint', { name: 'price', nullable: true }) + price: number; +} diff --git a/src/modules/item-related/item-rate/data/services/item-rate-data.service.ts b/src/modules/item-related/item-rate/data/services/item-rate-data.service.ts new file mode 100644 index 0000000..1c8862f --- /dev/null +++ b/src/modules/item-related/item-rate/data/services/item-rate-data.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDataService } from 'src/core/modules/data/service/base-data.service'; +import { ItemRateEntity } from '../../domain/entities/item-rate.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { ItemRateModel } from '../models/item-rate.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { Repository } from 'typeorm'; + +@Injectable() +export class ItemRateDataService extends BaseDataService { + constructor( + @InjectRepository(ItemRateModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/item-related/item-rate/data/services/item-rate-read.service.ts b/src/modules/item-related/item-rate/data/services/item-rate-read.service.ts new file mode 100644 index 0000000..3273f11 --- /dev/null +++ b/src/modules/item-related/item-rate/data/services/item-rate-read.service.ts @@ -0,0 +1,17 @@ +import { Injectable } from '@nestjs/common'; +import { ItemRateEntity } from '../../domain/entities/item-rate.entity'; +import { InjectRepository } from '@nestjs/typeorm'; +import { ItemRateModel } from '../models/item-rate.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 ItemRateReadService extends BaseReadService { + constructor( + @InjectRepository(ItemRateModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(repo); + } +} diff --git a/src/modules/item-related/item-rate/domain/entities/event/item-rate-created.event.ts b/src/modules/item-related/item-rate/domain/entities/event/item-rate-created.event.ts new file mode 100644 index 0000000..72232fc --- /dev/null +++ b/src/modules/item-related/item-rate/domain/entities/event/item-rate-created.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class ItemRateCreatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/item-related/item-rate/domain/entities/event/item-rate-deleted.event.ts b/src/modules/item-related/item-rate/domain/entities/event/item-rate-deleted.event.ts new file mode 100644 index 0000000..948d976 --- /dev/null +++ b/src/modules/item-related/item-rate/domain/entities/event/item-rate-deleted.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class ItemRateDeletedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/item-related/item-rate/domain/entities/event/item-rate-updated.event.ts b/src/modules/item-related/item-rate/domain/entities/event/item-rate-updated.event.ts new file mode 100644 index 0000000..270967e --- /dev/null +++ b/src/modules/item-related/item-rate/domain/entities/event/item-rate-updated.event.ts @@ -0,0 +1,5 @@ +import { IEvent } from 'src/core/strings/constants/interface.constants'; + +export class ItemRateUpdatedEvent { + constructor(public readonly data: IEvent) {} +} diff --git a/src/modules/item-related/item-rate/domain/entities/filter-item-rate.entity.ts b/src/modules/item-related/item-rate/domain/entities/filter-item-rate.entity.ts new file mode 100644 index 0000000..87df4e3 --- /dev/null +++ b/src/modules/item-related/item-rate/domain/entities/filter-item-rate.entity.ts @@ -0,0 +1,3 @@ +import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity'; + +export interface FilterItemRateEntity extends BaseFilterEntity {} diff --git a/src/modules/item-related/item-rate/domain/entities/item-rate.entity.ts b/src/modules/item-related/item-rate/domain/entities/item-rate.entity.ts new file mode 100644 index 0000000..b290f0d --- /dev/null +++ b/src/modules/item-related/item-rate/domain/entities/item-rate.entity.ts @@ -0,0 +1,7 @@ +import { BaseCoreEntity } from 'src/core/modules/domain/entities/base-core.entity'; + +export interface ItemRateEntity extends BaseCoreEntity { + item_id: string; + season_period_id: string; + price: number; +} diff --git a/src/modules/item-related/item-rate/domain/usecases/item-rate-data.orchestrator.ts b/src/modules/item-related/item-rate/domain/usecases/item-rate-data.orchestrator.ts new file mode 100644 index 0000000..0745326 --- /dev/null +++ b/src/modules/item-related/item-rate/domain/usecases/item-rate-data.orchestrator.ts @@ -0,0 +1,52 @@ +import { Injectable } from '@nestjs/common'; +import { CreateItemRateManager } from './managers/create-item-rate.manager'; +import { ItemRateDataService } from '../../data/services/item-rate-data.service'; +import { ItemRateEntity } from '../entities/item-rate.entity'; +import { DeleteItemRateManager } from './managers/delete-item-rate.manager'; +import { UpdateItemRateManager } from './managers/update-item-rate.manager'; +import { BaseDataOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-data.orchestrator'; +import { STATUS } from 'src/core/strings/constants/base.constants'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchDeleteItemRateManager } from './managers/batch-delete-item-rate.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class ItemRateDataOrchestrator extends BaseDataOrchestrator { + constructor( + private createManager: CreateItemRateManager, + private updateManager: UpdateItemRateManager, + private deleteManager: DeleteItemRateManager, + private batchDeleteManager: BatchDeleteItemRateManager, + private serviceData: ItemRateDataService, + ) { + super(); + } + + async create(data): Promise { + this.createManager.setData(data); + this.createManager.setService(this.serviceData, TABLE_NAME.ITEM_RATE); + await this.createManager.execute(); + return this.createManager.getResult(); + } + + async update(dataId, data): Promise { + this.updateManager.setData(dataId, data); + this.updateManager.setService(this.serviceData, TABLE_NAME.ITEM_RATE); + await this.updateManager.execute(); + return this.updateManager.getResult(); + } + + async delete(dataId): Promise { + this.deleteManager.setData(dataId); + this.deleteManager.setService(this.serviceData, TABLE_NAME.ITEM_RATE); + await this.deleteManager.execute(); + return this.deleteManager.getResult(); + } + + async batchDelete(dataIds: string[]): Promise { + this.batchDeleteManager.setData(dataIds); + this.batchDeleteManager.setService(this.serviceData, TABLE_NAME.ITEM_RATE); + await this.batchDeleteManager.execute(); + return this.batchDeleteManager.getResult(); + } +} diff --git a/src/modules/item-related/item-rate/domain/usecases/item-rate-read.orchestrator.ts b/src/modules/item-related/item-rate/domain/usecases/item-rate-read.orchestrator.ts new file mode 100644 index 0000000..b0a135b --- /dev/null +++ b/src/modules/item-related/item-rate/domain/usecases/item-rate-read.orchestrator.ts @@ -0,0 +1,33 @@ +import { Injectable } from '@nestjs/common'; +import { IndexItemRateManager } from './managers/index-item-rate.manager'; +import { ItemRateReadService } from '../../data/services/item-rate-read.service'; +import { ItemRateEntity } from '../entities/item-rate.entity'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; +import { DetailItemRateManager } from './managers/detail-item-rate.manager'; +import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; + +@Injectable() +export class ItemRateReadOrchestrator extends BaseReadOrchestrator { + constructor( + private indexManager: IndexItemRateManager, + private detailManager: DetailItemRateManager, + private serviceData: ItemRateReadService, + ) { + super(); + } + + async index(params): Promise> { + this.indexManager.setFilterParam(params); + this.indexManager.setService(this.serviceData, TABLE_NAME.ITEM_RATE); + 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_RATE); + await this.detailManager.execute(); + return this.detailManager.getResult(); + } +} diff --git a/src/modules/item-related/item-rate/domain/usecases/managers/batch-delete-item-rate.manager.ts b/src/modules/item-related/item-rate/domain/usecases/managers/batch-delete-item-rate.manager.ts new file mode 100644 index 0000000..f8f1e2f --- /dev/null +++ b/src/modules/item-related/item-rate/domain/usecases/managers/batch-delete-item-rate.manager.ts @@ -0,0 +1,45 @@ +import { BaseBatchDeleteManager } from 'src/core/modules/domain/usecase/managers/base-batch-delete.manager'; +import { ItemRateEntity } from '../../entities/item-rate.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemRateModel } from '../../../data/models/item-rate.model'; +import { ItemRateDeletedEvent } from '../../entities/event/item-rate-deleted.event'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { Injectable } from '@nestjs/common'; + +@Injectable() +export class BatchDeleteItemRateManager extends BaseBatchDeleteManager { + async beforeProcess(): Promise { + return; + } + + async validateData(data: ItemRateEntity): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return ItemRateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemRateDeletedEvent, + }, + ]; + } + + getResult(): BatchResult { + return this.result; + } +} diff --git a/src/modules/item-related/item-rate/domain/usecases/managers/create-item-rate.manager.ts b/src/modules/item-related/item-rate/domain/usecases/managers/create-item-rate.manager.ts new file mode 100644 index 0000000..31d1453 --- /dev/null +++ b/src/modules/item-related/item-rate/domain/usecases/managers/create-item-rate.manager.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@nestjs/common'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemRateEntity } from '../../entities/item-rate.entity'; +import { ItemRateModel } from '../../../data/models/item-rate.model'; +import { BaseCreateManager } from 'src/core/modules/domain/usecase/managers/base-create.manager'; +import { ItemRateCreatedEvent } from '../../entities/event/item-rate-created.event'; + +@Injectable() +export class CreateItemRateManager extends BaseCreateManager { + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemRateCreatedEvent, + data: this.data, + }, + ]; + } + + get entityTarget(): any { + return ItemRateModel; + } +} diff --git a/src/modules/item-related/item-rate/domain/usecases/managers/delete-item-rate.manager.ts b/src/modules/item-related/item-rate/domain/usecases/managers/delete-item-rate.manager.ts new file mode 100644 index 0000000..2e0b3dc --- /dev/null +++ b/src/modules/item-related/item-rate/domain/usecases/managers/delete-item-rate.manager.ts @@ -0,0 +1,45 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDeleteManager } from 'src/core/modules/domain/usecase/managers/base-delete.manager'; +import { ItemRateEntity } from '../../entities/item-rate.entity'; +import { + EventTopics, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; +import { ItemRateModel } from '../../../data/models/item-rate.model'; +import { ItemRateDeletedEvent } from '../../entities/event/item-rate-deleted.event'; + +@Injectable() +export class DeleteItemRateManager extends BaseDeleteManager { + getResult(): string { + return `Success`; + } + + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get entityTarget(): any { + return ItemRateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemRateDeletedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/item-related/item-rate/domain/usecases/managers/detail-item-rate.manager.ts b/src/modules/item-related/item-rate/domain/usecases/managers/detail-item-rate.manager.ts new file mode 100644 index 0000000..1d20cb1 --- /dev/null +++ b/src/modules/item-related/item-rate/domain/usecases/managers/detail-item-rate.manager.ts @@ -0,0 +1,42 @@ +import { Injectable } from '@nestjs/common'; +import { BaseDetailManager } from 'src/core/modules/domain/usecase/managers/base-detail.manager'; +import { ItemRateEntity } from '../../entities/item-rate.entity'; +import { RelationParam } from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class DetailItemRateManager 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: [], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return []; + } + + get setFindProperties(): any { + return { + id: this.dataId, + }; + } +} diff --git a/src/modules/item-related/item-rate/domain/usecases/managers/index-item-rate.manager.ts b/src/modules/item-related/item-rate/domain/usecases/managers/index-item-rate.manager.ts new file mode 100644 index 0000000..82f19cc --- /dev/null +++ b/src/modules/item-related/item-rate/domain/usecases/managers/index-item-rate.manager.ts @@ -0,0 +1,55 @@ +import { Injectable } from '@nestjs/common'; +import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; +import { ItemRateEntity } from '../../entities/item-rate.entity'; +import { SelectQueryBuilder } from 'typeorm'; +import { + Param, + RelationParam, +} from 'src/core/modules/domain/entities/base-filter.entity'; + +@Injectable() +export class IndexItemRateManager 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: [], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return []; + } + + get specificFilter(): Param[] { + return [ + { + cols: `${this.tableName}.name`, + data: this.filterParam.names, + }, + ]; + } + + setQueryFilter( + queryBuilder: SelectQueryBuilder, + ): SelectQueryBuilder { + return queryBuilder; + } +} diff --git a/src/modules/item-related/item-rate/domain/usecases/managers/update-item-rate.manager.ts b/src/modules/item-related/item-rate/domain/usecases/managers/update-item-rate.manager.ts new file mode 100644 index 0000000..963ea85 --- /dev/null +++ b/src/modules/item-related/item-rate/domain/usecases/managers/update-item-rate.manager.ts @@ -0,0 +1,46 @@ +import { Injectable } from '@nestjs/common'; +import { BaseUpdateManager } from 'src/core/modules/domain/usecase/managers/base-update.manager'; +import { ItemRateEntity } from '../../entities/item-rate.entity'; +import { ItemRateModel } from '../../../data/models/item-rate.model'; +import { ItemRateUpdatedEvent } from '../../entities/event/item-rate-updated.event'; +import { + EventTopics, + columnUniques, + validateRelations, +} from 'src/core/strings/constants/interface.constants'; + +@Injectable() +export class UpdateItemRateManager extends BaseUpdateManager { + async validateProcess(): Promise { + return; + } + + async beforeProcess(): Promise { + return; + } + + async afterProcess(): Promise { + return; + } + + get validateRelations(): validateRelations[] { + return []; + } + + get uniqueColumns(): columnUniques[] { + return []; + } + + get entityTarget(): any { + return ItemRateModel; + } + + get eventTopics(): EventTopics[] { + return [ + { + topic: ItemRateUpdatedEvent, + data: this.data, + }, + ]; + } +} diff --git a/src/modules/item-related/item-rate/index.ts b/src/modules/item-related/item-rate/index.ts new file mode 100644 index 0000000..e69de29 diff --git a/src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto.ts b/src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto.ts new file mode 100644 index 0000000..de94d21 --- /dev/null +++ b/src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto.ts @@ -0,0 +1,6 @@ +import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto'; +import { FilterItemRateEntity } from '../../domain/entities/filter-item-rate.entity'; + +export class FilterItemRateDto + extends BaseFilterDto + implements FilterItemRateEntity {} diff --git a/src/modules/item-related/item-rate/infrastructure/dto/item-rate.dto.ts b/src/modules/item-related/item-rate/infrastructure/dto/item-rate.dto.ts new file mode 100644 index 0000000..5ae1270 --- /dev/null +++ b/src/modules/item-related/item-rate/infrastructure/dto/item-rate.dto.ts @@ -0,0 +1,32 @@ +import { BaseCoreDto } from 'src/core/modules/infrastructure/dto/base-core.dto'; +import { ItemRateEntity } from '../../domain/entities/item-rate.entity'; +import { ApiProperty } from '@nestjs/swagger'; +import { Exclude } from 'class-transformer'; +import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; +import { IsObject } from 'class-validator'; +import { ItemDto } from 'src/modules/item-related/item/infrastructure/dto/item.dto'; + +export class ItemRateDto extends BaseCoreDto implements ItemRateEntity { + @Exclude() + item_id: string; + + @ApiProperty({ + type: [Object], + required: true, + example: { + id: 'uuid', + name: 'Entrace Ticket', + }, + }) + @IsObject() + item: ItemModel; + + @Exclude() + season_period_id: string; + + @ApiProperty({ + type: Number, + required: true, + }) + price: number; +} diff --git a/src/modules/item-related/item-rate/infrastructure/item-rate-data.controller.ts b/src/modules/item-related/item-rate/infrastructure/item-rate-data.controller.ts new file mode 100644 index 0000000..d8a3648 --- /dev/null +++ b/src/modules/item-related/item-rate/infrastructure/item-rate-data.controller.ts @@ -0,0 +1,40 @@ +import { Body, Controller, Delete, Param, Post, Put } from '@nestjs/common'; +import { ItemRateDataOrchestrator } from '../domain/usecases/item-rate-data.orchestrator'; +import { ItemRateDto } from './dto/item-rate.dto'; +import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; +import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; +import { ItemRateEntity } from '../domain/entities/item-rate.entity'; +import { BatchResult } from 'src/core/response/domain/ok-response.interface'; +import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; +import { Public } from 'src/core/guards'; + +@ApiTags(`${MODULE_NAME.ITEM_RATE.split('-').join(' ')} - data`) +@Controller(MODULE_NAME.ITEM_RATE) +@Public(false) +@ApiBearerAuth('JWT') +export class ItemRateDataController { + constructor(private orchestrator: ItemRateDataOrchestrator) {} + + @Post() + async create(@Body() data: ItemRateDto): Promise { + return await this.orchestrator.create(data); + } + + @Put('/batch-delete') + async batchDeleted(@Body() body: BatchIdsDto): Promise { + return await this.orchestrator.batchDelete(body.ids); + } + + @Put(':id') + async update( + @Param('id') dataId: string, + @Body() data: ItemRateDto, + ): Promise { + return await this.orchestrator.update(dataId, data); + } + + @Delete(':id') + async delete(@Param('id') dataId: string): Promise { + return await this.orchestrator.delete(dataId); + } +} diff --git a/src/modules/item-related/item-rate/infrastructure/item-rate-read.controller.ts b/src/modules/item-related/item-rate/infrastructure/item-rate-read.controller.ts new file mode 100644 index 0000000..4861962 --- /dev/null +++ b/src/modules/item-related/item-rate/infrastructure/item-rate-read.controller.ts @@ -0,0 +1,30 @@ +import { Controller, Get, Param, Query } from '@nestjs/common'; +import { FilterItemRateDto } from './dto/filter-item-rate.dto'; +import { Pagination } from 'src/core/response'; +import { PaginationResponse } from 'src/core/response/domain/ok-response.interface'; +import { ItemRateEntity } from '../domain/entities/item-rate.entity'; +import { ItemRateReadOrchestrator } from '../domain/usecases/item-rate-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_RATE.split('-').join(' ')} - read`) +@Controller(MODULE_NAME.ITEM_RATE) +@Public(false) +@ApiBearerAuth('JWT') +export class ItemRateReadController { + constructor(private orchestrator: ItemRateReadOrchestrator) {} + + @Get() + @Pagination() + async index( + @Query() params: FilterItemRateDto, + ): 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/item-related/item-rate/item-rate.module.ts b/src/modules/item-related/item-rate/item-rate.module.ts new file mode 100644 index 0000000..17e224f --- /dev/null +++ b/src/modules/item-related/item-rate/item-rate.module.ts @@ -0,0 +1,42 @@ +import { Module } from '@nestjs/common'; +import { ConfigModule } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { ItemRateDataService } from './data/services/item-rate-data.service'; +import { ItemRateReadService } from './data/services/item-rate-read.service'; +import { ItemRateReadController } from './infrastructure/item-rate-read.controller'; +import { ItemRateReadOrchestrator } from './domain/usecases/item-rate-read.orchestrator'; +import { ItemRateDataController } from './infrastructure/item-rate-data.controller'; +import { ItemRateDataOrchestrator } from './domain/usecases/item-rate-data.orchestrator'; +import { CreateItemRateManager } from './domain/usecases/managers/create-item-rate.manager'; +import { CqrsModule } from '@nestjs/cqrs'; +import { IndexItemRateManager } from './domain/usecases/managers/index-item-rate.manager'; +import { DeleteItemRateManager } from './domain/usecases/managers/delete-item-rate.manager'; +import { UpdateItemRateManager } from './domain/usecases/managers/update-item-rate.manager'; +import { DetailItemRateManager } from './domain/usecases/managers/detail-item-rate.manager'; +import { BatchDeleteItemRateManager } from './domain/usecases/managers/batch-delete-item-rate.manager'; +import { ItemRateModel } from './data/models/item-rate.model'; + +@Module({ + imports: [ + ConfigModule.forRoot(), + TypeOrmModule.forFeature([ItemRateModel], CONNECTION_NAME.DEFAULT), + CqrsModule, + ], + controllers: [ItemRateDataController, ItemRateReadController], + providers: [ + IndexItemRateManager, + DetailItemRateManager, + CreateItemRateManager, + DeleteItemRateManager, + UpdateItemRateManager, + BatchDeleteItemRateManager, + + ItemRateDataService, + ItemRateReadService, + + ItemRateDataOrchestrator, + ItemRateReadOrchestrator, + ], +}) +export class ItemRateModule {} diff --git a/src/modules/item-related/item/data/models/item.model.ts b/src/modules/item-related/item/data/models/item.model.ts index e1cd7ec..0b9bf82 100644 --- a/src/modules/item-related/item/data/models/item.model.ts +++ b/src/modules/item-related/item/data/models/item.model.ts @@ -7,12 +7,14 @@ import { JoinTable, ManyToMany, ManyToOne, + OneToMany, } from 'typeorm'; import { BaseStatusModel } from 'src/core/modules/data/model/base-status.model'; import { ItemType } from 'src/modules/item-related/item-category/constants'; import { LimitType } from '../../constants'; import { ItemCategoryModel } from 'src/modules/item-related/item-category/data/models/item-category.model'; import { UserModel } from 'src/modules/user-related/user/data/models/user.model'; +import { ItemRateModel } from 'src/modules/item-related/item-rate/data/models/item-rate.model'; @Entity(TABLE_NAME.ITEM) export class ItemModel @@ -99,4 +101,11 @@ export class ItemModel }, }) bundling_items: ItemModel[]; + + // relasi ke item rates + @OneToMany(() => ItemRateModel, (model) => model.item, { + onDelete: 'CASCADE', + onUpdate: 'CASCADE', + }) + item_rates: ItemRateModel[]; } 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 index 7d10d72..1bde43f 100644 --- a/src/modules/item-related/item/domain/entities/filter-item.entity.ts +++ b/src/modules/item-related/item/domain/entities/filter-item.entity.ts @@ -5,4 +5,5 @@ export interface FilterItemEntity extends BaseFilterEntity { item_types: string[]; limit_types: string[]; tenant_ids: string[]; + all_item: boolean; } 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 index ffa0adb..281ab07 100644 --- 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 @@ -82,7 +82,7 @@ export class IndexItemManager extends BaseIndexManager { queryBuilder.andWhere(`${this.tableName}.tenant_id In (:...tenantIds)`, { tenantIds: this.filterParam.tenant_ids, }); - } else { + } else if (!this.filterParam.all_item) { queryBuilder.andWhere(`${this.tableName}.tenant_id Is Null`); } 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 index 5270b63..5a0d70f 100644 --- a/src/modules/item-related/item/infrastructure/dto/filter-item.dto.ts +++ b/src/modules/item-related/item/infrastructure/dto/filter-item.dto.ts @@ -27,4 +27,11 @@ export class FilterItemDto extends BaseFilterDto implements FilterItemEntity { return Array.isArray(body.value) ? body.value : [body.value]; }) tenant_ids: string[]; + + @ApiProperty({ + type: Boolean, + required: false, + }) + @Transform((body) => body.value == 'true') + all_item: boolean; } diff --git a/src/modules/item-related/item/infrastructure/dto/item.dto.ts b/src/modules/item-related/item/infrastructure/dto/item.dto.ts index 65a6b88..cc2067e 100644 --- a/src/modules/item-related/item/infrastructure/dto/item.dto.ts +++ b/src/modules/item-related/item/infrastructure/dto/item.dto.ts @@ -108,7 +108,11 @@ export class ItemDto extends BaseStatusDto implements ItemEntity { example: 60, }) @IsNumber() - @ValidateIf((body) => body.item_type.toLowerCase() == ItemType.WAHANA && body.limit_type.toLowerCase() != LimitType.NO_LIMIT) + @ValidateIf( + (body) => + body.item_type.toLowerCase() == ItemType.WAHANA && + body.limit_type.toLowerCase() != LimitType.NO_LIMIT, + ) limit_value: number; @ApiProperty({ type: Boolean, required: false }) From a3d67ff5bef17a3588b83efd18993f96613aeedc Mon Sep 17 00:00:00 2001 From: Aswin Ashar Abdullah <98192542+Asharaswin@users.noreply.github.com> Date: Thu, 20 Jun 2024 05:14:06 +0700 Subject: [PATCH 5/5] feat(SPG-372) REST API Read Item Rate --- .../entities/filter-item-rate.entity.ts | 7 +- .../usecases/item-rate-read.orchestrator.ts | 16 +++- .../managers/index-item-rate.manager.ts | 74 ++++++++++++++--- .../dto/filter-item-rate.dto.ts | 32 +++++++- .../infrastructure/dto/item-rate.dto.ts | 1 - .../dto/update-item-rate.dto.ts | 18 ++++ .../item-rate-data.controller.ts | 32 ++++---- .../item-rate-read.controller.ts | 17 ++-- .../domain/usecases/item-read.orchestrator.ts | 18 ++++ .../managers/index-item-rates.manager.ts | 74 +++++++++++++++++ .../infrastructure/item-read.controller.ts | 14 +++- src/modules/item-related/item/item.module.ts | 11 ++- .../index-season-period-item.manager.ts | 82 +++++++++++++++++++ .../season-period-read.orchestrator.ts | 16 ++++ .../season-period-data.controller.ts | 5 +- .../season-period-read.controller.ts | 11 ++- .../season-period/season-period.module.ts | 9 +- .../tenant-item-data.controller.ts | 6 +- .../tenant-item-read.controller.ts | 6 +- 19 files changed, 394 insertions(+), 55 deletions(-) create mode 100644 src/modules/item-related/item-rate/infrastructure/dto/update-item-rate.dto.ts create mode 100644 src/modules/item-related/item/domain/usecases/managers/index-item-rates.manager.ts create mode 100644 src/modules/season-related/season-period/domain/usecases/managers/index-season-period-item.manager.ts diff --git a/src/modules/item-related/item-rate/domain/entities/filter-item-rate.entity.ts b/src/modules/item-related/item-rate/domain/entities/filter-item-rate.entity.ts index 87df4e3..4f40752 100644 --- a/src/modules/item-related/item-rate/domain/entities/filter-item-rate.entity.ts +++ b/src/modules/item-related/item-rate/domain/entities/filter-item-rate.entity.ts @@ -1,3 +1,8 @@ import { BaseFilterEntity } from 'src/core/modules/domain/entities/base-filter.entity'; -export interface FilterItemRateEntity extends BaseFilterEntity {} +export interface FilterItemRateEntity extends BaseFilterEntity { + item_ids: string[]; + season_period_ids: string[]; + start_date: Date; + end_date: Date; +} diff --git a/src/modules/item-related/item-rate/domain/usecases/item-rate-read.orchestrator.ts b/src/modules/item-related/item-rate/domain/usecases/item-rate-read.orchestrator.ts index b0a135b..aa25a00 100644 --- a/src/modules/item-related/item-rate/domain/usecases/item-rate-read.orchestrator.ts +++ b/src/modules/item-related/item-rate/domain/usecases/item-rate-read.orchestrator.ts @@ -6,6 +6,8 @@ import { PaginationResponse } from 'src/core/response/domain/ok-response.interfa import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; import { DetailItemRateManager } from './managers/detail-item-rate.manager'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { ItemReadService } from 'src/modules/item-related/item/data/services/item-read.service'; +import { ItemEntity } from 'src/modules/item-related/item/domain/entities/item.entity'; @Injectable() export class ItemRateReadOrchestrator extends BaseReadOrchestrator { @@ -13,13 +15,25 @@ export class ItemRateReadOrchestrator extends BaseReadOrchestrator> { + // this.indexManager.setFilterParam(params); + // this.indexManager.setService(this.itemServiceRead, TABLE_NAME.ITEM_RATE); + // await this.indexManager.execute(); + // return this.indexManager.getResult(); + return + } + + async indexItem(params): Promise> { + params.ia_all = true; + this.indexManager.setFilterParam(params); - this.indexManager.setService(this.serviceData, TABLE_NAME.ITEM_RATE); + this.indexManager.setService(this.itemServiceRead, TABLE_NAME.ITEM); await this.indexManager.execute(); return this.indexManager.getResult(); } diff --git a/src/modules/item-related/item-rate/domain/usecases/managers/index-item-rate.manager.ts b/src/modules/item-related/item-rate/domain/usecases/managers/index-item-rate.manager.ts index 82f19cc..d5c42f5 100644 --- a/src/modules/item-related/item-rate/domain/usecases/managers/index-item-rate.manager.ts +++ b/src/modules/item-related/item-rate/domain/usecases/managers/index-item-rate.manager.ts @@ -1,14 +1,14 @@ import { Injectable } from '@nestjs/common'; import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; -import { ItemRateEntity } from '../../entities/item-rate.entity'; import { SelectQueryBuilder } from 'typeorm'; import { Param, RelationParam, } from 'src/core/modules/domain/entities/base-filter.entity'; +import { ItemEntity } from 'src/modules/item-related/item/domain/entities/item.entity'; @Injectable() -export class IndexItemRateManager extends BaseIndexManager { +export class IndexItemRateManager extends BaseIndexManager { async prepareData(): Promise { return; } @@ -18,6 +18,30 @@ export class IndexItemRateManager extends BaseIndexManager { } async afterProcess(): Promise { + + this.result.data?.map(item => { + let prices = [] + for (let d = new Date(this.filterParam.start_date); d <= new Date(this.filterParam.end_date); d.setDate(d.getDate() + 1)) { + console.log(d, 'tanggal') + + const rate = item['item_rates']?.find( + rate => d >= new Date(rate.season_period.start_date) && d <= new Date(rate.season_period.end_date), + ); + + prices.push({ + date: new Date(d), + price: rate?.price ?? item.base_price, + season_type: rate?.season_period?.season_type ?? null, + holiday_name: rate?.season_period?.holiday_name ?? null, + }); + } + + delete item['item_rates']; + Object.assign(item, { + dates: prices + }) + }) + return; } @@ -27,7 +51,13 @@ export class IndexItemRateManager extends BaseIndexManager { joinRelations: [], // relation join and select (relasi yang ingin ditampilkan), - selectRelations: [], + selectRelations: [ + 'bundling_items', + 'tenant', + 'item_rates', + 'item_rates.season_period', + 'season_period.season_type' + ], // relation yang hanya ingin dihitung (akan return number) countRelations: [], @@ -35,21 +65,39 @@ export class IndexItemRateManager extends BaseIndexManager { } get selects(): string[] { - return []; - } - - get specificFilter(): Param[] { return [ - { - cols: `${this.tableName}.name`, - data: this.filterParam.names, - }, + `${ this.tableName }.id`, + `${ this.tableName }.created_at`, + `${ this.tableName }.name`, + `${ this.tableName }.base_price`, + + 'tenant.id', + 'tenant.name', + + 'bundling_items.id', + 'bundling_items.name', + + 'item_rates.id', + 'item_rates.price', + + 'season_period.id', + 'season_period.holiday_name', + 'season_period.start_date', + 'season_period.end_date', + + 'season_type.id', + 'season_type.name', ]; } + get specificFilter(): Param[] { + return []; + } + setQueryFilter( - queryBuilder: SelectQueryBuilder, - ): SelectQueryBuilder { + queryBuilder: SelectQueryBuilder, + ): SelectQueryBuilder { + return queryBuilder; } } diff --git a/src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto.ts b/src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto.ts index de94d21..27041b5 100644 --- a/src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto.ts +++ b/src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto.ts @@ -1,6 +1,36 @@ import { BaseFilterDto } from 'src/core/modules/infrastructure/dto/base-filter.dto'; import { FilterItemRateEntity } from '../../domain/entities/filter-item-rate.entity'; +import { ApiProperty } from '@nestjs/swagger'; +import { Transform } from 'class-transformer'; export class FilterItemRateDto extends BaseFilterDto - implements FilterItemRateEntity {} + implements FilterItemRateEntity { + @ApiProperty({ + required: true, + type: Date, + example: '2024-04-01' + }) + start_date: Date; + + @ApiProperty({ + required: true, + type: Date, + example: '2024-04-30' + }) + end_date: Date; + + @ApiProperty({ type: ['string'], required: false }) + @Transform((body) => { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + item_ids: string[]; + + @ApiProperty({ type: ['string'], required: false }) + @Transform((body) => { + return Array.isArray(body.value) ? body.value : [body.value]; + }) + season_period_ids: string[]; + + +} diff --git a/src/modules/item-related/item-rate/infrastructure/dto/item-rate.dto.ts b/src/modules/item-related/item-rate/infrastructure/dto/item-rate.dto.ts index 5ae1270..29cfe14 100644 --- a/src/modules/item-related/item-rate/infrastructure/dto/item-rate.dto.ts +++ b/src/modules/item-related/item-rate/infrastructure/dto/item-rate.dto.ts @@ -4,7 +4,6 @@ import { ApiProperty } from '@nestjs/swagger'; import { Exclude } from 'class-transformer'; import { ItemModel } from 'src/modules/item-related/item/data/models/item.model'; import { IsObject } from 'class-validator'; -import { ItemDto } from 'src/modules/item-related/item/infrastructure/dto/item.dto'; export class ItemRateDto extends BaseCoreDto implements ItemRateEntity { @Exclude() diff --git a/src/modules/item-related/item-rate/infrastructure/dto/update-item-rate.dto.ts b/src/modules/item-related/item-rate/infrastructure/dto/update-item-rate.dto.ts new file mode 100644 index 0000000..1b4a4ea --- /dev/null +++ b/src/modules/item-related/item-rate/infrastructure/dto/update-item-rate.dto.ts @@ -0,0 +1,18 @@ +import { BaseCoreDto } from 'src/core/modules/infrastructure/dto/base-core.dto'; +import { ItemRateEntity } from '../../domain/entities/item-rate.entity'; +import { ApiProperty } from '@nestjs/swagger'; +import { Exclude } from 'class-transformer'; + +export class UpdateItemRateDto extends BaseCoreDto implements ItemRateEntity { + @Exclude() + item_id: string; + + @Exclude() + season_period_id: string; + + @ApiProperty({ + type: Number, + required: true, + }) + price: number; +} diff --git a/src/modules/item-related/item-rate/infrastructure/item-rate-data.controller.ts b/src/modules/item-related/item-rate/infrastructure/item-rate-data.controller.ts index d8a3648..d319957 100644 --- a/src/modules/item-related/item-rate/infrastructure/item-rate-data.controller.ts +++ b/src/modules/item-related/item-rate/infrastructure/item-rate-data.controller.ts @@ -8,23 +8,27 @@ import { BatchResult } from 'src/core/response/domain/ok-response.interface'; import { BatchIdsDto } from 'src/core/modules/infrastructure/dto/base-batch.dto'; import { Public } from 'src/core/guards'; -@ApiTags(`${MODULE_NAME.ITEM_RATE.split('-').join(' ')} - data`) +@ApiTags(`${ MODULE_NAME.ITEM_RATE.split('-').join(' ') } - data`) @Controller(MODULE_NAME.ITEM_RATE) @Public(false) @ApiBearerAuth('JWT') export class ItemRateDataController { - constructor(private orchestrator: ItemRateDataOrchestrator) {} + constructor(private orchestrator: ItemRateDataOrchestrator) { } - @Post() - async create(@Body() data: ItemRateDto): Promise { - return await this.orchestrator.create(data); - } + // untuk sementara, tidak dapat create + // @Post() + // async create(@Body() data: ItemRateDto): Promise { + // return await this.orchestrator.create(data); + // } - @Put('/batch-delete') - async batchDeleted(@Body() body: BatchIdsDto): Promise { - return await this.orchestrator.batchDelete(body.ids); - } + // untuk sementara, tidak dapat delete + // @Put('/batch-delete') + // async batchDeleted(@Body() body: BatchIdsDto): Promise { + // return await this.orchestrator.batchDelete(body.ids); + // } + // update endpoint digunakan untuk update single price + // pada halaman detail item -> list item rates (dapat update single row) @Put(':id') async update( @Param('id') dataId: string, @@ -33,8 +37,8 @@ export class ItemRateDataController { return await this.orchestrator.update(dataId, data); } - @Delete(':id') - async delete(@Param('id') dataId: string): Promise { - return await this.orchestrator.delete(dataId); - } + // @Delete(':id') + // async delete(@Param('id') dataId: string): Promise { + // return await this.orchestrator.delete(dataId); + // } } diff --git a/src/modules/item-related/item-rate/infrastructure/item-rate-read.controller.ts b/src/modules/item-related/item-rate/infrastructure/item-rate-read.controller.ts index 4861962..8d3aa83 100644 --- a/src/modules/item-related/item-rate/infrastructure/item-rate-read.controller.ts +++ b/src/modules/item-related/item-rate/infrastructure/item-rate-read.controller.ts @@ -7,24 +7,25 @@ import { ItemRateReadOrchestrator } from '../domain/usecases/item-rate-read.orch import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; import { Public } from 'src/core/guards'; +import { ItemEntity } from '../../item/domain/entities/item.entity'; -@ApiTags(`${MODULE_NAME.ITEM_RATE.split('-').join(' ')} - read`) +@ApiTags(`${ MODULE_NAME.ITEM_RATE.split('-').join(' ') } - read`) @Controller(MODULE_NAME.ITEM_RATE) @Public(false) @ApiBearerAuth('JWT') export class ItemRateReadController { - constructor(private orchestrator: ItemRateReadOrchestrator) {} + constructor(private orchestrator: ItemRateReadOrchestrator) { } @Get() @Pagination() async index( @Query() params: FilterItemRateDto, - ): Promise> { - return await this.orchestrator.index(params); + ): Promise> { + return await this.orchestrator.indexItem(params); } - @Get(':id') - async detail(@Param('id') id: string): Promise { - return await this.orchestrator.detail(id); - } + // @Get(':id') + // async detail(@Param('id') id: string): Promise { + // return await this.orchestrator.detail(id); + // } } 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 index 8737793..72d9978 100644 --- a/src/modules/item-related/item/domain/usecases/item-read.orchestrator.ts +++ b/src/modules/item-related/item/domain/usecases/item-read.orchestrator.ts @@ -6,13 +6,19 @@ import { PaginationResponse } from 'src/core/response/domain/ok-response.interfa 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'; +import { ItemRateReadService } from 'src/modules/item-related/item-rate/data/services/item-rate-read.service'; +import { FilterItemRateDto } from 'src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto'; +import { ItemRateEntity } from 'src/modules/item-related/item-rate/domain/entities/item-rate.entity'; +import { IndexItemRatesManager } from './managers/index-item-rates.manager'; @Injectable() export class ItemReadOrchestrator extends BaseReadOrchestrator { constructor( private indexManager: IndexItemManager, private detailManager: DetailItemManager, + private indexRateManager: IndexItemRatesManager, private serviceData: ItemReadService, + private serviceItemData: ItemRateReadService, ) { super(); } @@ -30,4 +36,16 @@ export class ItemReadOrchestrator extends BaseReadOrchestrator { await this.detailManager.execute(); return this.detailManager.getResult(); } + + async indexRate(id): Promise> { + const params = new FilterItemRateDto(); + params.item_ids = [id]; + + console.log(params, 'param') + + this.indexRateManager.setFilterParam(params); + this.indexRateManager.setService(this.serviceItemData, TABLE_NAME.ITEM); + await this.indexRateManager.execute(); + return this.indexRateManager.getResult(); + } } diff --git a/src/modules/item-related/item/domain/usecases/managers/index-item-rates.manager.ts b/src/modules/item-related/item/domain/usecases/managers/index-item-rates.manager.ts new file mode 100644 index 0000000..6c7e576 --- /dev/null +++ b/src/modules/item-related/item/domain/usecases/managers/index-item-rates.manager.ts @@ -0,0 +1,74 @@ +import { Injectable } from '@nestjs/common'; +import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; +import { SelectQueryBuilder } from 'typeorm'; +import { + Param, + RelationParam, +} from 'src/core/modules/domain/entities/base-filter.entity'; +import { ItemRateEntity } from 'src/modules/item-related/item-rate/domain/entities/item-rate.entity'; + +@Injectable() +export class IndexItemRatesManager extends BaseIndexManager { + async prepareData(): Promise { + this.filterParam.order_by = `${ this.tableName }.id` + 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: ['season_period', 'season_period.season_type'], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${ this.tableName }.id`, + `${ this.tableName }.price`, + + `season_period.id`, + `season_period.created_at`, + `season_period.creator_name`, + `season_period.editor_name`, + `season_period.updated_at`, + `season_period.status`, + `season_period.start_date`, + `season_period.end_date`, + `season_period.days`, + `season_period.holiday_name`, + + 'season_type.id', + 'season_type.name', + ]; + } + + get specificFilter(): Param[] { + return []; + } + + setQueryFilter( + queryBuilder: SelectQueryBuilder, + ): SelectQueryBuilder { + + if (this.filterParam.item_ids) { + queryBuilder.andWhere(`${ this.tableName }.item_id In (:...itemIds)`, { + itemIds: this.filterParam.item_ids + }) + } + return queryBuilder; + } +} diff --git a/src/modules/item-related/item/infrastructure/item-read.controller.ts b/src/modules/item-related/item/infrastructure/item-read.controller.ts index 985f4bb..4e960aa 100644 --- a/src/modules/item-related/item/infrastructure/item-read.controller.ts +++ b/src/modules/item-related/item/infrastructure/item-read.controller.ts @@ -7,13 +7,14 @@ 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'; +import { ItemRateEntity } from '../../item-rate/domain/entities/item-rate.entity'; -@ApiTags(`${MODULE_NAME.ITEM.split('-').join(' ')} - read`) +@ApiTags(`${ MODULE_NAME.ITEM.split('-').join(' ') } - read`) @Controller(MODULE_NAME.ITEM) @Public(false) @ApiBearerAuth('JWT') export class ItemReadController { - constructor(private orchestrator: ItemReadOrchestrator) {} + constructor(private orchestrator: ItemReadOrchestrator) { } @Get() @Pagination() @@ -27,4 +28,13 @@ export class ItemReadController { async detail(@Param('id') id: string): Promise { return await this.orchestrator.detail(id); } + + @Get(':id/rates') + @Pagination() + async indexRate( + @Param('id') id: string + ): Promise> { + console.log(id, 'id') + return await this.orchestrator.indexRate(id); + } } diff --git a/src/modules/item-related/item/item.module.ts b/src/modules/item-related/item/item.module.ts index ed35180..9ae46da 100644 --- a/src/modules/item-related/item/item.module.ts +++ b/src/modules/item-related/item/item.module.ts @@ -22,17 +22,21 @@ import { BatchActiveItemManager } from './domain/usecases/managers/batch-active- import { BatchConfirmItemManager } from './domain/usecases/managers/batch-confirm-item.manager'; import { BatchInactiveItemManager } from './domain/usecases/managers/batch-inactive-item.manager'; import { ItemModel } from './data/models/item.model'; +import { ItemRateModel } from '../item-rate/data/models/item-rate.model'; +import { ItemRateReadService } from '../item-rate/data/services/item-rate-read.service'; +import { IndexItemRatesManager } from './domain/usecases/managers/index-item-rates.manager'; @Global() @Module({ imports: [ ConfigModule.forRoot(), - TypeOrmModule.forFeature([ItemModel], CONNECTION_NAME.DEFAULT), + TypeOrmModule.forFeature([ItemModel, ItemRateModel], CONNECTION_NAME.DEFAULT), CqrsModule, ], controllers: [ItemDataController, ItemReadController], providers: [ IndexItemManager, + IndexItemRatesManager, DetailItemManager, CreateItemManager, DeleteItemManager, @@ -47,12 +51,14 @@ import { ItemModel } from './data/models/item.model'; ItemDataService, ItemReadService, + ItemRateReadService, ItemDataOrchestrator, ItemReadOrchestrator, ], exports: [ IndexItemManager, + IndexItemRatesManager, DetailItemManager, CreateItemManager, DeleteItemManager, @@ -65,6 +71,7 @@ import { ItemModel } from './data/models/item.model'; BatchConfirmItemManager, BatchInactiveItemManager, + ItemRateReadService, ItemDataService, ItemReadService, @@ -72,4 +79,4 @@ import { ItemModel } from './data/models/item.model'; ItemReadOrchestrator, ], }) -export class ItemModule {} +export class ItemModule { } diff --git a/src/modules/season-related/season-period/domain/usecases/managers/index-season-period-item.manager.ts b/src/modules/season-related/season-period/domain/usecases/managers/index-season-period-item.manager.ts new file mode 100644 index 0000000..083c9f5 --- /dev/null +++ b/src/modules/season-related/season-period/domain/usecases/managers/index-season-period-item.manager.ts @@ -0,0 +1,82 @@ +import { Injectable } from '@nestjs/common'; +import { BaseIndexManager } from 'src/core/modules/domain/usecase/managers/base-index.manager'; +import { SelectQueryBuilder } from 'typeorm'; +import { + Param, + RelationParam, +} from 'src/core/modules/domain/entities/base-filter.entity'; +import { ItemRateEntity } from 'src/modules/item-related/item-rate/domain/entities/item-rate.entity'; + +@Injectable() +export class IndexSeasonPeriodeItemManager extends BaseIndexManager { + async prepareData(): Promise { + this.filterParam.order_by = `${ this.tableName }.id` + 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', 'item.item_category', 'item.bundling_items'], + + // relation yang hanya ingin dihitung (akan return number) + countRelations: [], + }; + } + + get selects(): string[] { + return [ + `${ this.tableName }.id`, + `${ this.tableName }.price`, + + `item.id`, + `item.created_at`, + `item.status`, + `item.item_type`, + `item.name`, + `item.hpp`, + `item.limit_type`, + `item.limit_value`, + `item.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, + }, + ]; + } + + setQueryFilter( + queryBuilder: SelectQueryBuilder, + ): SelectQueryBuilder { + + if (this.filterParam.season_period_ids) { + queryBuilder.andWhere(`${ this.tableName }.season_period_id In (:...periodIds)`, { + periodIds: this.filterParam.season_period_ids + }) + } + + return queryBuilder; + } +} diff --git a/src/modules/season-related/season-period/domain/usecases/season-period-read.orchestrator.ts b/src/modules/season-related/season-period/domain/usecases/season-period-read.orchestrator.ts index 36ae641..551f71d 100644 --- a/src/modules/season-related/season-period/domain/usecases/season-period-read.orchestrator.ts +++ b/src/modules/season-related/season-period/domain/usecases/season-period-read.orchestrator.ts @@ -6,13 +6,19 @@ import { PaginationResponse } from 'src/core/response/domain/ok-response.interfa import { BaseReadOrchestrator } from 'src/core/modules/domain/usecase/orchestrators/base-read.orchestrator'; import { DetailSeasonPeriodManager } from './managers/detail-season-period.manager'; import { TABLE_NAME } from 'src/core/strings/constants/table.constants'; +import { IndexSeasonPeriodeItemManager } from './managers/index-season-period-item.manager'; +import { ItemRateEntity } from 'src/modules/item-related/item-rate/domain/entities/item-rate.entity'; +import { FilterItemRateDto } from 'src/modules/item-related/item-rate/infrastructure/dto/filter-item-rate.dto'; +import { ItemRateReadService } from 'src/modules/item-related/item-rate/data/services/item-rate-read.service'; @Injectable() export class SeasonPeriodReadOrchestrator extends BaseReadOrchestrator { constructor( private indexManager: IndexSeasonPeriodManager, private detailManager: DetailSeasonPeriodManager, + private indexItemManager: IndexSeasonPeriodeItemManager, private serviceData: SeasonPeriodReadService, + private itemServiceRead: ItemRateReadService, ) { super(); } @@ -30,4 +36,14 @@ export class SeasonPeriodReadOrchestrator extends BaseReadOrchestrator> { + const params = new FilterItemRateDto(); + params.season_period_ids = [id]; + + this.indexItemManager.setFilterParam(params); + this.indexItemManager.setService(this.itemServiceRead, TABLE_NAME.SEASON_PERIOD); + await this.indexItemManager.execute(); + return this.indexItemManager.getResult(); + } } diff --git a/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts b/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts index efd3807..c6f4f05 100644 --- a/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts +++ b/src/modules/season-related/season-period/infrastructure/season-period-data.controller.ts @@ -19,12 +19,12 @@ import { Public } from 'src/core/guards'; import { UpdateSeasonPeriodDto } from './dto/update-season-period.dto'; import { UpdateSeasonPeriodItemDto } from './dto/update-season-period-item.dto'; -@ApiTags(`${MODULE_NAME.SEASON_PERIOD.split('-').join(' ')} - data`) +@ApiTags(`${ MODULE_NAME.SEASON_PERIOD.split('-').join(' ') } - data`) @Controller(MODULE_NAME.SEASON_PERIOD) @Public(false) @ApiBearerAuth('JWT') export class SeasonPeriodDataController { - constructor(private orchestrator: SeasonPeriodDataOrchestrator) {} + constructor(private orchestrator: SeasonPeriodDataOrchestrator) { } @Post() async create(@Body() data: SeasonPeriodDto): Promise { @@ -74,6 +74,7 @@ export class SeasonPeriodDataController { return await this.orchestrator.update(dataId, data); } + // pemisahan update data dengan update items dikarenakan payload (based on tampilan) berbeda @Put(':id/items') async updateItems( @Param('id') dataId: string, diff --git a/src/modules/season-related/season-period/infrastructure/season-period-read.controller.ts b/src/modules/season-related/season-period/infrastructure/season-period-read.controller.ts index 5d64393..2fd09fb 100644 --- a/src/modules/season-related/season-period/infrastructure/season-period-read.controller.ts +++ b/src/modules/season-related/season-period/infrastructure/season-period-read.controller.ts @@ -7,13 +7,14 @@ import { SeasonPeriodReadOrchestrator } from '../domain/usecases/season-period-r import { ApiBearerAuth, ApiTags } from '@nestjs/swagger'; import { MODULE_NAME } from 'src/core/strings/constants/module.constants'; import { Public } from 'src/core/guards'; +import { ItemRateEntity } from 'src/modules/item-related/item-rate/domain/entities/item-rate.entity'; -@ApiTags(`${MODULE_NAME.SEASON_PERIOD.split('-').join(' ')} - read`) +@ApiTags(`${ MODULE_NAME.SEASON_PERIOD.split('-').join(' ') } - read`) @Controller(MODULE_NAME.SEASON_PERIOD) @Public(false) @ApiBearerAuth('JWT') export class SeasonPeriodReadController { - constructor(private orchestrator: SeasonPeriodReadOrchestrator) {} + constructor(private orchestrator: SeasonPeriodReadOrchestrator) { } @Get() @Pagination() @@ -27,4 +28,10 @@ export class SeasonPeriodReadController { async detail(@Param('id') id: string): Promise { return await this.orchestrator.detail(id); } + + @Get(':id/items') + @Pagination() + async indexItem(@Param('id') id: string): Promise> { + return await this.orchestrator.indexItem(id); + } } diff --git a/src/modules/season-related/season-period/season-period.module.ts b/src/modules/season-related/season-period/season-period.module.ts index 5efb09a..ee0f64a 100644 --- a/src/modules/season-related/season-period/season-period.module.ts +++ b/src/modules/season-related/season-period/season-period.module.ts @@ -23,11 +23,14 @@ import { BatchConfirmSeasonPeriodManager } from './domain/usecases/managers/batc import { BatchInactiveSeasonPeriodManager } from './domain/usecases/managers/batch-inactive-season-period.manager'; import { SeasonPeriodModel } from './data/models/season-period.model'; import { SeasonPeriodHolidayHandler } from './domain/usecases/handlers/season-period-created.handler'; +import { IndexSeasonPeriodeItemManager } from './domain/usecases/managers/index-season-period-item.manager'; +import { ItemRateModel } from 'src/modules/item-related/item-rate/data/models/item-rate.model'; +import { ItemRateReadService } from 'src/modules/item-related/item-rate/data/services/item-rate-read.service'; @Module({ imports: [ ConfigModule.forRoot(), - TypeOrmModule.forFeature([SeasonPeriodModel], CONNECTION_NAME.DEFAULT), + TypeOrmModule.forFeature([SeasonPeriodModel, ItemRateModel], CONNECTION_NAME.DEFAULT), CqrsModule, ], controllers: [SeasonPeriodDataController, SeasonPeriodReadController], @@ -35,6 +38,7 @@ import { SeasonPeriodHolidayHandler } from './domain/usecases/handlers/season-pe SeasonPeriodHolidayHandler, IndexSeasonPeriodManager, + IndexSeasonPeriodeItemManager, DetailSeasonPeriodManager, CreateSeasonPeriodManager, DeleteSeasonPeriodManager, @@ -49,9 +53,10 @@ import { SeasonPeriodHolidayHandler } from './domain/usecases/handlers/season-pe SeasonPeriodDataService, SeasonPeriodReadService, + ItemRateReadService, SeasonPeriodDataOrchestrator, SeasonPeriodReadOrchestrator, ], }) -export class SeasonPeriodModule {} +export class SeasonPeriodModule { } diff --git a/src/modules/user-related/tenant/infrastructure/tenant-item-data.controller.ts b/src/modules/user-related/tenant/infrastructure/tenant-item-data.controller.ts index f9745c6..7d9bfb6 100644 --- a/src/modules/user-related/tenant/infrastructure/tenant-item-data.controller.ts +++ b/src/modules/user-related/tenant/infrastructure/tenant-item-data.controller.ts @@ -16,12 +16,12 @@ import { ItemEntity } from 'src/modules/item-related/item/domain/entities/item.e import { ItemDataOrchestrator } from 'src/modules/item-related/item/domain/usecases/item-data.orchestrator'; import { ItemDto } from 'src/modules/item-related/item/infrastructure/dto/item.dto'; -@ApiTags(`${MODULE_NAME.TENANT.split('-').join(' ')} item - data`) -@Controller(`${MODULE_NAME.TENANT}/:tenant_id/item`) +@ApiTags(`${ MODULE_NAME.TENANT.split('-').join(' ') } item - data`) +@Controller(`${ MODULE_NAME.TENANT }/:tenant_id/item`) @Public(false) @ApiBearerAuth('JWT') export class TenantItemDataController { - constructor(private orchestrator: ItemDataOrchestrator) {} + constructor(private orchestrator: ItemDataOrchestrator) { } @Post() async create( 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 index 31c3799..ae42e37 100644 --- a/src/modules/user-related/tenant/infrastructure/tenant-item-read.controller.ts +++ b/src/modules/user-related/tenant/infrastructure/tenant-item-read.controller.ts @@ -8,12 +8,12 @@ import { ItemEntity } from 'src/modules/item-related/item/domain/entities/item.e 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`) +@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) {} + constructor(private orchestrator: ItemReadOrchestrator) { } @Get() @Pagination()