mirror of
https://github.com/SyncrowIOT/backend.git
synced 2025-07-10 15:17:41 +00:00
Merge pull request #362 from SyncrowIOT/fix-power-clamp-historical-data
Add endpoints and logic for fetching power clamp data by community or…
This commit is contained in:
@ -498,6 +498,10 @@ export class ControllerRoute {
|
||||
'Get power clamp historical data';
|
||||
public static readonly GET_ENERGY_DESCRIPTION =
|
||||
'This endpoint retrieves the historical data of a power clamp device based on the provided parameters.';
|
||||
public static readonly GET_ENERGY_BY_COMMUNITY_OR_SPACE_SUMMARY =
|
||||
'Get power clamp historical data by community or space';
|
||||
public static readonly GET_ENERGY_BY_COMMUNITY_OR_SPACE_DESCRIPTION =
|
||||
'This endpoint retrieves the historical data of power clamp devices based on the provided community or space UUID.';
|
||||
};
|
||||
};
|
||||
static DEVICE = class {
|
||||
|
@ -1,4 +1,9 @@
|
||||
import { Injectable, HttpException, HttpStatus } from '@nestjs/common';
|
||||
import {
|
||||
Injectable,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { AddCommunityDto, GetCommunityParams, ProjectParam } from '../dtos';
|
||||
import { UpdateCommunityNameDto } from '../dtos/update.community.dto';
|
||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||
@ -16,6 +21,8 @@ import { ORPHAN_COMMUNITY_NAME } from '@app/common/constants/orphan-constant';
|
||||
import { ILike, In, Not } from 'typeorm';
|
||||
import { SpaceService } from 'src/space/services';
|
||||
import { SpaceRepository } from '@app/common/modules/space';
|
||||
import { DeviceEntity } from '@app/common/modules/device/entities';
|
||||
import { SpaceEntity } from '@app/common/modules/space/entities/space.entity';
|
||||
|
||||
@Injectable()
|
||||
export class CommunityService {
|
||||
@ -303,4 +310,58 @@ export class CommunityService {
|
||||
);
|
||||
}
|
||||
}
|
||||
async getAllDevicesByCommunity(
|
||||
communityUuid: string,
|
||||
): Promise<DeviceEntity[]> {
|
||||
// Fetch the community and its top-level spaces
|
||||
const community = await this.communityRepository.findOne({
|
||||
where: { uuid: communityUuid },
|
||||
relations: [
|
||||
'spaces',
|
||||
'spaces.children',
|
||||
'spaces.devices',
|
||||
'spaces.devices.productDevice',
|
||||
],
|
||||
});
|
||||
|
||||
if (!community) {
|
||||
throw new NotFoundException('Community not found');
|
||||
}
|
||||
|
||||
const allDevices: DeviceEntity[] = [];
|
||||
|
||||
// Recursive fetch function for spaces
|
||||
const fetchSpaceDevices = async (space: SpaceEntity) => {
|
||||
if (space.devices && space.devices.length > 0) {
|
||||
allDevices.push(...space.devices);
|
||||
}
|
||||
|
||||
if (space.children && space.children.length > 0) {
|
||||
for (const childSpace of space.children) {
|
||||
const fullChildSpace = await this.spaceRepository.findOne({
|
||||
where: { uuid: childSpace.uuid },
|
||||
relations: ['children', 'devices', 'devices.productDevice'],
|
||||
});
|
||||
|
||||
if (fullChildSpace) {
|
||||
await fetchSpaceDevices(fullChildSpace);
|
||||
}
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
// Start recursive fetch for all top-level spaces
|
||||
for (const space of community.spaces) {
|
||||
const fullSpace = await this.spaceRepository.findOne({
|
||||
where: { uuid: space.uuid },
|
||||
relations: ['children', 'devices', 'devices.productDevice'],
|
||||
});
|
||||
|
||||
if (fullSpace) {
|
||||
await fetchSpaceDevices(fullSpace);
|
||||
}
|
||||
}
|
||||
|
||||
return allDevices;
|
||||
}
|
||||
}
|
||||
|
@ -4,6 +4,7 @@ import {
|
||||
ApiBearerAuth,
|
||||
ApiOperation,
|
||||
ApiParam,
|
||||
ApiQuery,
|
||||
} from '@nestjs/swagger';
|
||||
import { EnableDisableStatusEnum } from '@app/common/constants/days.enum';
|
||||
import { ControllerRoute } from '@app/common/constants/controller-route';
|
||||
@ -16,7 +17,7 @@ import {
|
||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||
import {
|
||||
PowerClampParamsDto,
|
||||
SpaceParamsDto,
|
||||
ResourceParamsDto,
|
||||
} from '../dto/power-clamp-params.dto';
|
||||
|
||||
@ApiTags('Power Clamp Module')
|
||||
@ -47,20 +48,32 @@ export class PowerClampController {
|
||||
}
|
||||
@ApiBearerAuth()
|
||||
@UseGuards(JwtAuthGuard)
|
||||
@Get('historical/space/:spaceUuid')
|
||||
@Get('historical')
|
||||
@ApiOperation({
|
||||
summary: ControllerRoute.PowerClamp.ACTIONS.GET_ENERGY_SUMMARY,
|
||||
description: ControllerRoute.PowerClamp.ACTIONS.GET_ENERGY_DESCRIPTION,
|
||||
summary:
|
||||
ControllerRoute.PowerClamp.ACTIONS
|
||||
.GET_ENERGY_BY_COMMUNITY_OR_SPACE_SUMMARY,
|
||||
description:
|
||||
ControllerRoute.PowerClamp.ACTIONS
|
||||
.GET_ENERGY_BY_COMMUNITY_OR_SPACE_DESCRIPTION,
|
||||
})
|
||||
@ApiParam({
|
||||
@ApiQuery({
|
||||
name: 'spaceUuid',
|
||||
description: 'UUID of the Space',
|
||||
required: true,
|
||||
required: false,
|
||||
})
|
||||
async getPowerClampBySpaceData(
|
||||
@Param() params: SpaceParamsDto,
|
||||
@ApiQuery({
|
||||
name: 'communityUuid',
|
||||
description: 'UUID of the Community',
|
||||
required: false,
|
||||
})
|
||||
async getPowerClampDataBySpaceOrCommunity(
|
||||
@Query() params: ResourceParamsDto,
|
||||
@Query() query: GetPowerClampBySpaceDto,
|
||||
): Promise<BaseResponseDto> {
|
||||
return await this.powerClampService.getPowerClampBySpaceData(params, query);
|
||||
return await this.powerClampService.getPowerClampDataBySpaceOrCommunity(
|
||||
params,
|
||||
query,
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -1,4 +1,4 @@
|
||||
import { IsUUID } from 'class-validator';
|
||||
import { IsNotEmpty, IsOptional, IsUUID, ValidateIf } from 'class-validator';
|
||||
|
||||
export class PowerClampParamsDto {
|
||||
@IsUUID('4', { message: 'Invalid UUID format' })
|
||||
@ -8,3 +8,16 @@ export class SpaceParamsDto {
|
||||
@IsUUID('4', { message: 'Invalid UUID format' })
|
||||
spaceUuid: string;
|
||||
}
|
||||
export class ResourceParamsDto {
|
||||
@IsUUID('4', { message: 'Invalid UUID format' })
|
||||
@IsOptional()
|
||||
spaceUuid?: string;
|
||||
|
||||
@IsUUID('4', { message: 'Invalid UUID format' })
|
||||
@IsOptional()
|
||||
communityUuid?: string;
|
||||
|
||||
@ValidateIf((o) => !o.spaceUuid && !o.communityUuid)
|
||||
@IsNotEmpty({ message: 'Either spaceUuid or communityUuid must be provided' })
|
||||
requireEither?: never; // This ensures at least one of them is provided
|
||||
}
|
||||
|
@ -1,4 +1,9 @@
|
||||
import { HttpException, HttpStatus, Injectable } from '@nestjs/common';
|
||||
import {
|
||||
BadRequestException,
|
||||
HttpException,
|
||||
HttpStatus,
|
||||
Injectable,
|
||||
} from '@nestjs/common';
|
||||
import {
|
||||
GetPowerClampBySpaceDto,
|
||||
GetPowerClampDto,
|
||||
@ -11,7 +16,7 @@ import {
|
||||
import { SuccessResponseDto } from '@app/common/dto/success.response.dto';
|
||||
import {
|
||||
PowerClampParamsDto,
|
||||
SpaceParamsDto,
|
||||
ResourceParamsDto,
|
||||
} from '../dto/power-clamp-params.dto';
|
||||
import { DeviceRepository } from '@app/common/modules/device/repositories';
|
||||
import { SpaceDeviceService } from 'src/space/services';
|
||||
@ -20,6 +25,8 @@ import { DataSource } from 'typeorm';
|
||||
import { SQL_PROCEDURES_PATH } from '@app/common/constants/sql-query-path';
|
||||
import { filterByMonth, toMMYYYY } from '@app/common/helper/date-format';
|
||||
import { ProductType } from '@app/common/constants/product-type.enum';
|
||||
import { CommunityService } from 'src/community/services';
|
||||
import { BaseResponseDto } from '@app/common/dto/base.response.dto';
|
||||
|
||||
@Injectable()
|
||||
export class PowerClampService {
|
||||
@ -31,50 +38,77 @@ export class PowerClampService {
|
||||
private readonly spaceDeviceService: SpaceDeviceService,
|
||||
private readonly sqlLoader: SqlLoaderService,
|
||||
private readonly dataSource: DataSource,
|
||||
private readonly communityService: CommunityService,
|
||||
) {}
|
||||
|
||||
async getPowerClampBySpaceData(
|
||||
params: SpaceParamsDto,
|
||||
async getPowerClampDataBySpaceOrCommunity(
|
||||
params: ResourceParamsDto,
|
||||
query: GetPowerClampBySpaceDto,
|
||||
) {
|
||||
): Promise<BaseResponseDto> {
|
||||
const { monthDate } = query;
|
||||
const { spaceUuid } = params;
|
||||
const { spaceUuid, communityUuid } = params;
|
||||
|
||||
try {
|
||||
const devices =
|
||||
await this.spaceDeviceService.getAllDevicesBySpace(spaceUuid);
|
||||
console.log('devices', devices);
|
||||
// Validate we have at least one identifier
|
||||
if (!spaceUuid && !communityUuid) {
|
||||
throw new BadRequestException(
|
||||
'Either spaceUuid or communityUuid must be provided',
|
||||
);
|
||||
}
|
||||
|
||||
// Get devices based on space or community
|
||||
const devices = spaceUuid
|
||||
? await this.spaceDeviceService.getAllDevicesBySpace(spaceUuid)
|
||||
: await this.communityService.getAllDevicesByCommunity(communityUuid);
|
||||
|
||||
if (!devices?.length) {
|
||||
return this.buildResponse(
|
||||
'No power clamp devices found for the specified criteria',
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
// Filter and prepare device UUIDs
|
||||
const deviceUuids = devices
|
||||
.filter((device) => device.productDevice.prodType === ProductType.PC)
|
||||
.map((device) => device.uuid)
|
||||
.join(',');
|
||||
console.log('deviceUuids', deviceUuids);
|
||||
.filter((device) => device.productDevice?.prodType === ProductType.PC)
|
||||
.map((device) => device.uuid);
|
||||
|
||||
if (deviceUuids.length === 0) {
|
||||
return this.buildResponse(
|
||||
'No power clamp devices (PC type) found for the specified criteria',
|
||||
[],
|
||||
);
|
||||
}
|
||||
|
||||
// Execute procedure
|
||||
const formattedMonthDate = toMMYYYY(monthDate);
|
||||
|
||||
const data = await this.executeProcedure(
|
||||
'fact_daily_space_energy_consumed_procedure',
|
||||
[formattedMonthDate, deviceUuids],
|
||||
[formattedMonthDate, deviceUuids.join(',')],
|
||||
);
|
||||
|
||||
// Format date to YYYY-MM-DD
|
||||
// Format and filter data
|
||||
const formattedData = data.map((item) => ({
|
||||
...item,
|
||||
date: new Date(item.date).toLocaleDateString('en-CA'), // YYYY-MM-DD
|
||||
}));
|
||||
|
||||
const filteredData = monthDate
|
||||
const resultData = monthDate
|
||||
? filterByMonth(formattedData, monthDate)
|
||||
: formattedData;
|
||||
|
||||
return this.buildResponse(
|
||||
`Power clamp data for space ${spaceUuid} fetched successfully`,
|
||||
filteredData,
|
||||
`Power clamp data fetched successfully for ${spaceUuid ? 'space' : 'community'}`,
|
||||
resultData,
|
||||
);
|
||||
} catch (error) {
|
||||
console.error('Error fetching power clamp data', {
|
||||
error,
|
||||
spaceUuid,
|
||||
communityUuid,
|
||||
});
|
||||
throw new HttpException(
|
||||
error.message || 'Error fetching power clamp data by space',
|
||||
error.response?.message || 'Failed to fetch power clamp data',
|
||||
error.status || HttpStatus.INTERNAL_SERVER_ERROR,
|
||||
);
|
||||
}
|
||||
|
Reference in New Issue
Block a user