diff --git a/src/modules/reports/report-bookmark/report-bookmark.module.ts b/src/modules/reports/report-bookmark/report-bookmark.module.ts index 4a3a2a8..ed44501 100644 --- a/src/modules/reports/report-bookmark/report-bookmark.module.ts +++ b/src/modules/reports/report-bookmark/report-bookmark.module.ts @@ -1,9 +1,15 @@ import { Module } from '@nestjs/common'; import { ReportBookmarkController } from './report-bookmark.controller'; import { ReportBookmarkService } from './report-bookmark.service'; +import { ConfigModule } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { ReportBookmarkModel } from '../shared/models/report-bookmark.model'; @Module({ - imports: [], + imports: [ + TypeOrmModule.forFeature([ReportBookmarkModel], CONNECTION_NAME.DEFAULT), + ], controllers: [ReportBookmarkController], providers: [ReportBookmarkService], }) diff --git a/src/modules/reports/report-bookmark/report-bookmark.service.ts b/src/modules/reports/report-bookmark/report-bookmark.service.ts index 4f76e2b..7cbe05f 100644 --- a/src/modules/reports/report-bookmark/report-bookmark.service.ts +++ b/src/modules/reports/report-bookmark/report-bookmark.service.ts @@ -5,15 +5,45 @@ import { GetLabelReportBookmarkDto, GetReportBookmarkDto, } from '../shared/dto/report-bookmark.get.dto'; +import { Repository } from 'typeorm'; +import { InjectRepository } from '@nestjs/typeorm'; +import { ReportBookmarkModel } from '../shared/models/report-bookmark.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; @Injectable() export class ReportBookmarkService extends BaseReportService { + constructor( + @InjectRepository(ReportBookmarkModel, CONNECTION_NAME.DEFAULT) + private repo: Repository, + ) { + super(); + } + async create(body: CreateReportBookmarkDto) { return 'you hit API for create report bookmark'; } async getAll(query: GetReportBookmarkDto) { - return 'you hit API for get all report bookmark'; + const modelName = ReportBookmarkModel.name; + + const requestor_id = this.userProvider.user.id; + const unique_names = query.unique_names; + const group_names = query.group_names; + + const qb = this.repo + .createQueryBuilder(modelName) + .where((query) => { + if (unique_names) { + query.andWhere(`unique_name IN (:...unique_names)`, { unique_names }); + } + if (group_names) { + query.andWhere(`group_name =IN (:...group_names)`, { group_names }); + } + query.andWhere(`requestor_id = :requestor_id`, { requestor_id }); + }) + .orderBy(`${modelName}.created_at`, 'DESC'); + + return await qb.getMany(); } async getAllLabelHistory(query: GetLabelReportBookmarkDto) { diff --git a/src/modules/reports/report-export/report-export.module.ts b/src/modules/reports/report-export/report-export.module.ts index bbd3269..0506d59 100644 --- a/src/modules/reports/report-export/report-export.module.ts +++ b/src/modules/reports/report-export/report-export.module.ts @@ -1,9 +1,18 @@ import { Module } from '@nestjs/common'; import { ReportExportController } from './report-export.controller'; import { ReportExportService } from './report-export.service'; +import { ConfigModule } from '@nestjs/config'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ExportReportHistoryModel } from '../shared/models/export-report-history.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; @Module({ - imports: [], + imports: [ + TypeOrmModule.forFeature( + [ExportReportHistoryModel], + CONNECTION_NAME.DEFAULT, + ), + ], controllers: [ReportExportController], providers: [ReportExportService], }) diff --git a/src/modules/reports/report-export/report-export.service.ts b/src/modules/reports/report-export/report-export.service.ts index c5b6322..1586329 100644 --- a/src/modules/reports/report-export/report-export.service.ts +++ b/src/modules/reports/report-export/report-export.service.ts @@ -6,9 +6,23 @@ import { GetReportExportFileNameDto, GetReportExportProcessingDto, } from '../shared/dto/report-export.get.dto'; +import { InjectDataSource, InjectRepository } from '@nestjs/typeorm'; +import { ExportReportHistoryModel } from '../shared/models/export-report-history.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { DataSource, Repository } from 'typeorm'; @Injectable() export class ReportExportService extends BaseReportService { + constructor( + @InjectDataSource(CONNECTION_NAME.DEFAULT) + private dataSource: DataSource, + + @InjectRepository(ExportReportHistoryModel, CONNECTION_NAME.DEFAULT) + private exportHistoryRepo: Repository, + ) { + super(); + } + async create(body: CreateReportExportDto) { return 'you hit API for create report export'; } diff --git a/src/modules/reports/report/report.module.ts b/src/modules/reports/report/report.module.ts index b624fe0..805a2d1 100644 --- a/src/modules/reports/report/report.module.ts +++ b/src/modules/reports/report/report.module.ts @@ -1,9 +1,17 @@ import { Module } from '@nestjs/common'; import { ReportController } from './report.controller'; import { ReportService } from './report.service'; +import { TypeOrmModule } from '@nestjs/typeorm'; +import { ExportReportHistoryModel } from '../shared/models/export-report-history.model'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; @Module({ - imports: [], + imports: [ + TypeOrmModule.forFeature( + [ExportReportHistoryModel], + CONNECTION_NAME.DEFAULT, + ), + ], controllers: [ReportController], providers: [ReportService], }) diff --git a/src/modules/reports/report/report.service.ts b/src/modules/reports/report/report.service.ts index c494e32..9bcb8fe 100644 --- a/src/modules/reports/report/report.service.ts +++ b/src/modules/reports/report/report.service.ts @@ -1,11 +1,27 @@ -import { Injectable } from '@nestjs/common'; +import { Injectable, Logger } from '@nestjs/common'; import { BaseReportService } from '../shared/services/base-report.service'; import { GetReportConfigDto } from '../shared/dto/report-config.get.dto'; import { GetReportDataDto } from '../shared/dto/report-data.get.dto'; import { ReportConfigs } from '../shared/configs'; +import { InjectDataSource } from '@nestjs/typeorm'; +import { CONNECTION_NAME } from 'src/core/strings/constants/base.constants'; +import { DataSource } from 'typeorm'; +import { ReportConfigEntity } from '../shared/entities/report-config.entity'; +import { ReportQueryBuilder } from '../shared/helpers'; +import { DATA_FORMAT } from '../shared/constant'; +import { roundingCurrency } from '../shared/helpers/rounding-currency'; @Injectable() export class ReportService extends BaseReportService { + private readonly logger = new Logger(ReportService.name); + + constructor( + @InjectDataSource(CONNECTION_NAME.DEFAULT) + private dataSource: DataSource, + ) { + super(); + } + async getReportConfig(query: GetReportConfigDto) { const { unique_names = [], group_names = [] } = query; @@ -23,11 +39,112 @@ export class ReportService extends BaseReportService { return configs; } + getReportConfigByUniqueName(unique_name): ReportConfigEntity { + return ReportConfigs.find((item) => item.unique_name === unique_name); + } + async getReportData(body: GetReportDataDto) { - return 'you hit API for get report data'; + try { + const queryModel = body.query_model; + const reportConfig = this.getReportConfigByUniqueName(body.unique_name); + const builder = new ReportQueryBuilder(reportConfig, queryModel); + const SQL = builder.getSql(); + const queryResult = await this.dataSource.query(SQL); + + const realData = []; + const configColumns = reportConfig.column_configs; + + for (const item of queryResult) { + const realItem = {}; + for (const itemKey of Object.keys(item)) { + if (itemKey === 'count_child_group') { + const realValue = item[itemKey] ?? 0; + Object.assign(realItem, { [`${itemKey}`]: Number(realValue) }); + } else { + const confCol = configColumns.find((c) => c.column === itemKey); + const isNumber = confCol.format === DATA_FORMAT.NUMBER; + const isCurrency = confCol.format === DATA_FORMAT.CURRENCY; + const isMinusCurrency = + confCol.format === DATA_FORMAT.MINUS_CURRENCY; + const isBoolean = confCol.format === DATA_FORMAT.BOOLEAN; + const isPercentage = confCol.format === DATA_FORMAT.PERCENTAGE; + const isSetInitNull = isNumber || isCurrency || isMinusCurrency; + const isTextUpperCase = + confCol.format === DATA_FORMAT.TEXT_UPPERCASE; + const isTextLowerCase = + confCol.format === DATA_FORMAT.TEXT_LOWERCASE; + + if (isSetInitNull) { + const realValue = item[itemKey] ?? 0; + if (isCurrency) { + Object.assign(realItem, { + [`${itemKey}`]: roundingCurrency(realValue), + }); + } else if (isMinusCurrency) { + Object.assign(realItem, { + [`${itemKey}`]: roundingCurrency(realValue) * -1, + }); + } else { + Object.assign(realItem, { [`${itemKey}`]: realValue }); + } + } else if (isPercentage) { + const realValue = item[itemKey] + ? `${item[itemKey]}%` + : item[itemKey]; + Object.assign(realItem, { [`${itemKey}`]: realValue }); + } else if (isBoolean) { + let realValue = ''; + if (item[itemKey] === true || item[itemKey] === 1) + realValue = 'Yes'; + else if (item[itemKey] === false || item[itemKey] === 0) + realValue = 'No'; + Object.assign(realItem, { [`${itemKey}`]: realValue }); + } else if (isTextUpperCase) { + Object.assign(realItem, { + [`${itemKey}`]: item[itemKey]?.toUpperCase(), + }); + } else if (isTextLowerCase) { + Object.assign(realItem, { + [`${itemKey}`]: item[itemKey]?.toLowerCase(), + }); + } else { + Object.assign(realItem, { [`${itemKey}`]: item[itemKey] }); + } + } + } + realData.push(realItem); + } + + return realData; + } catch (error) { + this.logger.error(error); + throw error; + } } async getReportMeta(body: GetReportDataDto) { - return 'you hit API for get report meta'; + try { + const queryModel = body.query_model; + const reportConfig = this.getReportConfigByUniqueName(body.unique_name); + const builder = new ReportQueryBuilder(reportConfig, queryModel); + const SQL_COUNT = builder.getSqlCount(); + const queryResult = await this.dataSource.query(SQL_COUNT); + + const totalRow = parseInt(queryResult[0].count); + const startRow = queryModel.startRow; + const endRow = queryModel.endRow; + const pageSize = endRow - startRow; + + const meta = { + total_row: totalRow, + limit: pageSize, + offset: startRow, + }; + + return meta; + } catch (error) { + this.logger.error(error); + throw error; + } } } diff --git a/src/modules/reports/shared/configs/general-report/configs/sample.report.ts b/src/modules/reports/shared/configs/general-report/configs/sample.report.ts index cabbd03..a832ba5 100644 --- a/src/modules/reports/shared/configs/general-report/configs/sample.report.ts +++ b/src/modules/reports/shared/configs/general-report/configs/sample.report.ts @@ -5,7 +5,7 @@ export default { group_name: REPORT_GROUP.general_report, unique_name: `${REPORT_GROUP.general_report}__sample`, label: 'Sample General Report ', - table_schema: 'season_types', + table_schema: 'season_types main', main_table_alias: 'main', defaultOrderBy: [], lowLevelOrderBy: [], @@ -22,8 +22,8 @@ export default { format: DATA_FORMAT.DATE_EPOCH, }, { - column: 'main__update_at', - query: 'main.update_at', + column: 'main__updated_at', + query: 'main.updated_at', label: 'Updated Date', type: DATA_TYPE.DIMENSION, format: DATA_FORMAT.DATE_EPOCH, diff --git a/src/modules/reports/shared/configs/tenant-report/configs/sample.report.ts b/src/modules/reports/shared/configs/tenant-report/configs/sample.report.ts index 2c223fe..62f2871 100644 --- a/src/modules/reports/shared/configs/tenant-report/configs/sample.report.ts +++ b/src/modules/reports/shared/configs/tenant-report/configs/sample.report.ts @@ -5,7 +5,7 @@ export default { group_name: REPORT_GROUP.tenant_report, unique_name: `${REPORT_GROUP.tenant_report}__sample`, label: 'Sample Tenant Report ', - table_schema: 'season_types', + table_schema: 'season_types main', main_table_alias: 'main', defaultOrderBy: [], lowLevelOrderBy: [], @@ -21,8 +21,8 @@ export default { format: DATA_FORMAT.DATE_EPOCH, }, { - column: 'main__update_at', - query: 'main.update_at', + column: 'main__updated_at', + query: 'main.updated_at', label: 'Updated Date', type: DATA_TYPE.DIMENSION, format: DATA_FORMAT.DATE_EPOCH, diff --git a/src/modules/reports/shared/dto/report-data.get.dto.ts b/src/modules/reports/shared/dto/report-data.get.dto.ts index a66b84b..b33da70 100644 --- a/src/modules/reports/shared/dto/report-data.get.dto.ts +++ b/src/modules/reports/shared/dto/report-data.get.dto.ts @@ -1,13 +1,22 @@ import { ApiProperty } from '@nestjs/swagger'; import { IsObject, IsString, ValidateIf } from 'class-validator'; import { QueryModelEntity } from '../entities/query-model.entity'; +import { REPORT_GROUP } from '../constant'; export class GetReportDataDto { - @ApiProperty({ name: 'group_name', required: true }) + @ApiProperty({ + name: 'group_name', + required: true, + default: REPORT_GROUP.general_report, + }) @IsString() group_name: string; - @ApiProperty({ name: 'unique_name', required: true }) + @ApiProperty({ + name: 'unique_name', + required: true, + default: `${REPORT_GROUP.general_report}__sample`, + }) @IsString() unique_name: string; @@ -15,6 +24,17 @@ export class GetReportDataDto { name: 'query_model', type: Object, required: true, + default: { + startRow: 0, + endRow: 100, + rowGroupCols: [], + valueCols: [], + pivotCols: [], + pivotMode: true, + groupKeys: [], + filterModel: {}, + sortModel: [], + }, }) @IsObject() @ValidateIf((body) => body.query_model) diff --git a/src/modules/reports/shared/helpers/rounding-currency.ts b/src/modules/reports/shared/helpers/rounding-currency.ts new file mode 100644 index 0000000..323239b --- /dev/null +++ b/src/modules/reports/shared/helpers/rounding-currency.ts @@ -0,0 +1,4 @@ +export function roundingCurrency(value) { + if (!value) return value; + return Number(value).toFixed(2); +}