penisularhr / src / modules / activity-record / activity-record-setting.service.ts
activity-record-setting.service.ts
Raw
import { forwardRef, Inject, Injectable } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import moment from 'moment';
import { Brackets, type FindOptionsWhere, Repository } from 'typeorm';

import { type PageDto } from '../../common/dto/page.dto';
import { OperateType } from '../../constants';
import {
  ActivityGroupNotFoundException,
  ActivitySettingInUsedException,
  SectorNotFoundException,
} from '../../exceptions';
import { AuditLogService } from '../audit-log/audit-log.service';
import { SectorService } from '../sector/sector.service';
import { type UserEntity } from '../user/user.entity';
import { ActivityGroupService } from './activity-group.service';
import { ActivityRecordService } from './activity-record.service';
import { ActivityRecordSettingEntity } from './activity-record-setting.entity';
import { type ActivityRecordSettingDto } from './dtos/activity-record-setting.dto';
import { type CreateActivityRecordSettingDto } from './dtos/create-activity-record-setting.dto';
import { type ActivityRecordSettingPageOptionsDto } from './dtos/get-activity-record-setting-page.dto';
import { type UpdateActivityRecordSettingDto } from './dtos/update-activity-record-setting.dto';

@Injectable()
export class ActivityRecordSettingService {
  constructor(
    @InjectRepository(ActivityRecordSettingEntity)
    private activityRecordSettingReposiory: Repository<ActivityRecordSettingEntity>,
    @Inject(forwardRef(() => SectorService))
    private sectorService: SectorService,
    @Inject(forwardRef(() => ActivityRecordService))
    private acitvityRecordService: ActivityRecordService,
    private activityGroupService: ActivityGroupService,
    private auditLogService: AuditLogService,
  ) {}

  async findOne(
    findData: FindOptionsWhere<ActivityRecordSettingEntity>,
  ): Promise<ActivityRecordSettingEntity | null> {
    const queryBuilder = this.activityRecordSettingReposiory.createQueryBuilder(
      'activityRecordSetting',
    );

    queryBuilder
      .leftJoin('activityRecordSetting.sector', 'sector')
      .addSelect(['sector.name'])
      .leftJoin('activityRecordSetting.activityGroup', 'activityGroup')
      .addSelect(['activityGroup.name']);

    queryBuilder.where(findData);

    return queryBuilder.getOne();
  }

  async findMany(
    pageOptionsDto: ActivityRecordSettingPageOptionsDto,
  ): Promise<PageDto<ActivityRecordSettingDto>> {
    const {
      activityName,
      incentiveName,
      isActive,
      sectorName,
      order,
      activityGroupName,
      id,
    } = pageOptionsDto;

    const queryBuilder = this.activityRecordSettingReposiory.createQueryBuilder(
      'activityRecordSetting',
    );

    queryBuilder
      .leftJoin('activityRecordSetting.sector', 'sector')
      .addSelect(['sector.name'])
      .leftJoin('activityRecordSetting.activityGroup', 'activityGroup')
      .addSelect(['activityGroup.name']);

    if (activityName) {
      queryBuilder.andWhere('activityRecordSetting.name ILIKE :activityName', {
        activityName: `%${activityName}%`,
      });
    }

    if (activityGroupName) {
      queryBuilder.andWhere('activityGroup.name ILIKE :activityGroupName', {
        activityGroupName: `%${activityGroupName}%`,
      });
    }

    if (incentiveName) {
      queryBuilder.andWhere(incentiveName, [
        'activityRecordSetting.incentiveName',
      ]);
    }

    if (id !== undefined) {
      queryBuilder.andWhere('activityRecordSetting.id = :id', {
        id,
      });
    }

    if (isActive !== undefined) {
      queryBuilder.andWhere('activityRecordSetting.isActive = :isActive', {
        isActive,
      });
    }

    if (sectorName) {
      queryBuilder.andWhere('sector.name ILIKE :sectorName', {
        sectorName: `%${sectorName}%`,
      });
    }

    queryBuilder.orderBy('activityRecordSetting.name', order);

    const [items, pageMetaDto] = await queryBuilder.paginate(pageOptionsDto);

    return items.toPageDto(pageMetaDto);
  }

  async findManyWithoutPagination(): Promise<ActivityRecordSettingEntity[]> {
    const queryBuilder = this.activityRecordSettingReposiory.createQueryBuilder(
      'activityRecordSetting',
    );

    return queryBuilder.getMany();
  }

  async findManyDropdown({
    date,
    shouldShowInOtfilter,
    showInactive = false,
  }: {
    date?: Date;
    shouldShowInOtfilter?: boolean;
    showInactive?: boolean;
  }): Promise<Array<{ name: string; value: string }>> {
    const requestDate = date
      ? moment.utc(date).startOf('date')
      : moment.utc().startOf('date');

    const queryBuilder = this.activityRecordSettingReposiory.createQueryBuilder(
      'activityRecordSetting',
    );

    if (!showInactive) {
      queryBuilder.andWhere('activityRecordSetting.isActive = :status', {
        status: true,
      });
      queryBuilder.andWhere(
        new Brackets((qb) =>
          qb
            .andWhere('activityRecordSetting.activateUntil IS NULL')
            .orWhere('activityRecordSetting.activateUntil >= :requestDate', {
              requestDate,
            }),
        ),
      );
    }

    if (shouldShowInOtfilter) {
      queryBuilder.andWhere(
        'activityRecordSetting.shouldShowInOtfilter = :shouldShowInOtfilter',
        {
          shouldShowInOtfilter,
        },
      );
    }

    queryBuilder.orderBy('activityRecordSetting.name', 'ASC');

    const returnData = await queryBuilder.getMany();

    return returnData.map((el) => ({
      name: el.name,
      value: el.name,
    }));
  }

  async createActivityRecordSetting(
    dto: CreateActivityRecordSettingDto,
    user: UserEntity,
  ): Promise<ActivityRecordSettingEntity> {
    let activateUntil: undefined | Date;

    if (dto.activateUntil) {
      activateUntil = moment.utc(dto.activateUntil).startOf('date').toDate();
    }

    const sectorEntity = await this.sectorService.findOne({
      name: dto.sector,
    });

    if (!sectorEntity) {
      throw new SectorNotFoundException();
    }

    const activityGroupEntity = await this.activityGroupService.findOne({
      name: dto.activityGroup,
    });

    if (!activityGroupEntity) {
      throw new ActivityGroupNotFoundException();
    }

    const activityRecordSettingEntity =
      this.activityRecordSettingReposiory.create({
        ...dto,
        activateUntil,
        sector: sectorEntity,
        activityGroup: activityGroupEntity,
      });

    const createdActivity = await this.activityRecordSettingReposiory.save(
      activityRecordSettingEntity,
    );

    await this.auditLogService.create({
      itemId: createdActivity.id,
      newValue: JSON.stringify(createdActivity),
      oldValue: null,
      operateType: OperateType.CREATE,
      summaryChanges: 'CREATE activity record setting',
      tableName: 'activityRecordSetting',
      user,
    });

    return activityRecordSettingEntity;
  }

  // eslint-disable-next-line sonarjs/cognitive-complexity
  async updateActivitySetting(
    activityRecordSettingEntity: ActivityRecordSettingEntity,
    dto: UpdateActivityRecordSettingDto,
    user: UserEntity,
  ): Promise<ActivityRecordSettingEntity> {
    const {
      name,
      rate,
      activityGroup,
      sector,
      activateUntil,
      incentiveName,
      isActive,
      unit,
      shouldShowInOtfilter,
    } = dto;

    let summaryChanges = 'UPDATE ';
    const oldValue = JSON.stringify({ ...activityRecordSettingEntity });

    if (name) {
      summaryChanges +=
        activityRecordSettingEntity.name === name
          ? ''
          : `Name: ${activityRecordSettingEntity.name} -> ${name}, `;
      activityRecordSettingEntity.name = name;
    }

    if (rate !== undefined) {
      summaryChanges +=
        activityRecordSettingEntity.rate === rate
          ? ''
          : `Rate: ${activityRecordSettingEntity.rate} -> ${rate}, `;
      activityRecordSettingEntity.rate = rate;
    }

    if (unit !== undefined) {
      summaryChanges +=
        activityRecordSettingEntity.unit === unit
          ? ''
          : `Unit: ${activityRecordSettingEntity.unit} -> ${unit}, `;
      activityRecordSettingEntity.unit = unit;
    }

    if (activityGroup) {
      const activityGroupEntity = await this.activityGroupService.findOne({
        name: activityGroup,
      });

      if (!activityGroupEntity) {
        throw new ActivityGroupNotFoundException();
      }

      summaryChanges +=
        activityRecordSettingEntity.activityGroup.name ===
        activityGroupEntity.name
          ? ''
          : `Activity Group: ${activityRecordSettingEntity.activityGroup.name} -> ${activityGroupEntity.name}, `;
      activityRecordSettingEntity.activityGroup = activityGroupEntity;
    }

    if (sector) {
      const sectorEntity = await this.sectorService.findOne({
        name: sector,
      });

      if (!sectorEntity) {
        throw new SectorNotFoundException();
      }

      summaryChanges +=
        activityRecordSettingEntity.sector.name === sectorEntity.name
          ? ''
          : `Sector: ${activityRecordSettingEntity.sector.name} -> ${sectorEntity.name}, `;

      activityRecordSettingEntity.sector = sectorEntity;
    }

    if (activateUntil !== undefined) {
      summaryChanges +=
        activityRecordSettingEntity.activateUntil === activateUntil
          ? ''
          : `Activate Until: ${moment
              .utc(activityRecordSettingEntity.activateUntil)
              .startOf('date')
              .toDate()} -> ${moment
              .utc(activateUntil)
              .startOf('date')
              .toDate()}, `;

      activityRecordSettingEntity.activateUntil =
        activateUntil === null
          ? (null as unknown as undefined)
          : moment.utc(activateUntil).startOf('date').toDate();
    }

    if (incentiveName !== undefined) {
      summaryChanges +=
        activityRecordSettingEntity.incentiveName === incentiveName
          ? ''
          : `Incentive: ${activityRecordSettingEntity.incentiveName} -> ${incentiveName}, `;

      activityRecordSettingEntity.incentiveName =
        incentiveName === null ? (null as unknown as undefined) : incentiveName;
    }

    if (isActive !== undefined) {
      summaryChanges +=
        activityRecordSettingEntity.isActive === isActive
          ? ''
          : `IsActive: ${activityRecordSettingEntity.isActive} -> ${isActive}, `;
      activityRecordSettingEntity.isActive = isActive;
    }

    if (shouldShowInOtfilter !== undefined) {
      summaryChanges +=
        activityRecordSettingEntity.shouldShowInOtfilter ===
        shouldShowInOtfilter
          ? ''
          : `ShouldShowInOtFilter: ${activityRecordSettingEntity.shouldShowInOtfilter} -> ${shouldShowInOtfilter}, `;
      activityRecordSettingEntity.shouldShowInOtfilter = shouldShowInOtfilter;
    }

    const updatedActivity = await this.activityRecordSettingReposiory.save(
      activityRecordSettingEntity,
    );

    await this.auditLogService.create({
      itemId: updatedActivity.id,
      newValue: JSON.stringify(updatedActivity),
      oldValue,
      operateType: OperateType.UPDATE,
      summaryChanges,
      tableName: 'activityRecordSetting',
      user,
    });

    return activityRecordSettingEntity;
  }

  async delete(
    activitySettingEntity: ActivityRecordSettingEntity,
    user: UserEntity,
  ): Promise<void> {
    const existingActivityRecord = await this.acitvityRecordService.findOne({
      activityRecordSetting: { id: activitySettingEntity.id },
    });

    if (existingActivityRecord) {
      throw new ActivitySettingInUsedException();
    }

    await this.auditLogService.create({
      itemId: activitySettingEntity.id,
      newValue: null,
      oldValue: JSON.stringify(activitySettingEntity),
      operateType: OperateType.DELETE,
      summaryChanges: 'DELETE activity record setting',
      tableName: 'activityRecordSetting',
      user,
    });

    await this.activityRecordSettingReposiory.remove(activitySettingEntity);
  }
}