Untitled

mail@pastecode.io avatar
unknown
plain_text
a month ago
16 kB
2
Indexable
Never
/* eslint-disable prettier/prettier */
/* eslint-disable @typescript-eslint/no-var-requires */
import { PrismaService } from '@libs/modules/prisma/prisma.service';
import {
  ForbiddenException,
  HttpException,
  Injectable,
  NotFoundException,
} from '@nestjs/common';
import { PaginateInput } from '@common/paginate/dto/paginate.input';
import { createPaginator } from 'prisma-pagination';
import { ModelOnCampaign, Prisma } from '@prisma/client';
import { handlePaginateInput } from '@common/paginate/utils';
import { FilterRegisterCampaignInput } from './dto/filter-register-campaign.input';
import { filterByContainFunc } from '@common/query';
import { CampaignStatus, RegisterStatus, RegisterStatusFilter, ScheduleType } from '@common/guard/enum';
import { KycStatus } from '@modules/model/config';
import { TelegramService } from '@libs/modules/telegram/telegram.service';
import { FirebaseService } from '@libs/modules/firebase/firebase.service';
import { TypeNotification } from '@libs/modules/firebase/model/dataNotification';

const dayjs = require('dayjs');
const utc = require('dayjs/plugin/utc');
dayjs.extend(utc);

@Injectable()
export class RegisterCampaignService {
  constructor(private prisma: PrismaService, private telegramService: TelegramService, private firebaseService: FirebaseService) { }

  async register(modelId: number, campaignRoleId: number) {
    try {
      const check = await this.checkRegistedAndDate(modelId, campaignRoleId);

      if (check.value) {
        throw new ForbiddenException('Bạn đã đăng ký');
      }

      const result = await this.prisma.modelOnCampaign.create({
        data: { modelId, campaignRoleId, status: RegisterStatus.REGISTERED },
      });

      const message = '💥💥💥 `Yêu cầu ứng tuyển` 💥💥💥\n' +
        `👤 *Tên mẫu*: ${check.data.model.user.firstname} ${check.data.model.user.lastname}\n` +
        `✉️ *Email*: ${check.data.model.user.email}\n` +
        `🗞 *Chiến dịch*: ${check.data.campaignRole.campaign.name}\n` +
        `🧑 *Vai trò*: ${check.data.campaignRole.name}\n` +
        `📍 *Xem ngay tại*: https://felix-admin.zackco.com/data/campaign/detail?id=${check.data.campaignRole.campaignId}`;

      this.telegramService.sendMessage(message)

      return result;
    } catch (error) {
      console.log("register campaign")
      console.log(error)
      throw new ForbiddenException(error.message);
    }
  }

  async checkRegistedAndDate(modelId: number, campaignRoleId: number) {
    try {
      const campaignRole = await this.prisma.campaignRole.findUnique({
        where: {
          id: campaignRoleId
        },
        include: {
          campaign: true,
        }
      })

      if (!campaignRole) {
        throw new ForbiddenException("Campaign role không tồn tại")
      }

      if (campaignRole.campaign.status !== CampaignStatus.PROCESSING) {
        throw new ForbiddenException('Casting không hợp lệ');
      }

      const available = await this.prisma.modelOnCampaign.findMany({
        where: {
          campaignRoleId,
          status: RegisterStatus.ACCEPTED,
        },
        take: Number(campaignRole.quantity)
      });

      if (available.length >= Number(campaignRole.quantity)) {
        throw new ForbiddenException("Vai trò này đã tuyển đủ số lượng mẫu")
      }

      const check = await this.prisma.modelOnCampaign.findUnique({
        where: {
          campaignRoleId_modelId: { campaignRoleId, modelId },
        },
        include: {
          campaignRole: {
            include: {
              campaign: true
            }
          },
          model: {
            include: {
              user: true,
            }
          },
        },
      });

      if (check) {
        return {
          data: check,
          value: true
        };
      }
      const model = await this.prisma.model.findUnique({
        where: {
          id: modelId,
        },
        include: {
          user: true
        }
      })

      if (model.kycStatus !== KycStatus.VERIFIED) {
        throw new ForbiddenException("Bạn chưa xác minh thông tin cá nhân")
      }

      const schedule = await this.findScheduleInRange(
        modelId,
        campaignRole.campaign.startFittingDate,
        campaignRole.campaign.endFittingDate,
        campaignRole.startShootingDate,
        campaignRole.endShootingDate,
      )

      if (schedule) {
        throw new ForbiddenException("Bạn đã có lịch bận/làm việc trùng với ngày thử đồ hoặc ngày quay")
      }

      return {
        data: {
          campaignRole,
          model
        },
        value: false
      };
    } catch (error) {
      console.log(error);
      throw new ForbiddenException(error.message);
    }
  }

  async findAll(
    paginateInput: PaginateInput,
    filter?: FilterRegisterCampaignInput,
  ) {
    const paginateInputHandle = handlePaginateInput(paginateInput);
    const paginate = createPaginator({ ...paginateInputHandle });
    const { startFittingDate, endFittingDate, startShootingDate, endShootingDate, name: n, status, campaignId, ...fil } = filter;
    const name = filterByContainFunc(filter?.name);
    const now = dayjs().add(7, 'hour').toISOString(); // Set the timezone offset as needed

    const result = await paginate<
      ModelOnCampaign,
      Prisma.ModelOnCampaignFindManyArgs
    >(this.prisma.modelOnCampaign, {
      where: {
        AND: [
          { ...fil, status: status && status !== RegisterStatusFilter.UPCOMING ? status : {} },
          {
            campaignRole: {
              AND: [
                {
                  campaign: {
                    AND: [
                      { id: campaignId },
                      { name },
                      status && status === RegisterStatusFilter.UPCOMING ? { startFittingDate: { gte: now } } : {},
                      { startFittingDate: { gte: startFittingDate } },
                      { endFittingDate: { lte: endFittingDate } },
                    ],
                  }
                },
                { startShootingDate: { gte: startShootingDate } },
                { endShootingDate: { lte: endShootingDate } },
              ]
            },
          },
        ],
      },
      include: {
        campaignRole: {
          include: {
            campaign: true
          }
        },
        model: {
          include: {
            user: true
          }
        }
      },
    });

    return result;
  }

  async findOne(modelId: number, campaignRoleId: number) {
    try {
      const data = await this.prisma.modelOnCampaign.findUnique({
        where: {
          campaignRoleId_modelId: { campaignRoleId, modelId },
        },
        include: {
          campaignRole: {
            include: {
              campaign: true
            }
          },
          model: {
            include: {
              user: true
            }
          },
        },
      });

      if (!data) {
        throw new NotFoundException('Không tìm thấy');
      }
      return data;
    } catch (error) {
      if (error instanceof NotFoundException) {
        throw error;
      } else {
        throw new ForbiddenException('Có lỗi xảy ra');
      }
    }
  }

  async createScheduleWhenAccept(modelId: number, campaignRoleId: number, name: string, startFittingDate: Date, endFittingDate: Date, startShootingDate: Date, endShootingDate: Date) {
    try {
      return await this.prisma.schedule.createMany({
        data: [
          {
            modelId,
            campaignRoleId,
            startDate: startFittingDate,
            endDate: endFittingDate,
            type: ScheduleType.WORK,
            detail: `Lịch thử đồ cho casting ${name}`
          },
          {
            modelId,
            campaignRoleId,
            startDate: startShootingDate,
            endDate: endShootingDate,
            type: ScheduleType.WORK,
            detail: `Lịch quay cho casting ${name}`
          },
        ]
      })
    } catch (error) {
      console.log(error)
    }
  }

  async removeScheduleWhenReject(campaignRoleId: number) {
    return this.prisma.schedule.deleteMany({
      where: {
        campaignRoleId
      }
    })
  }

  findScheduleInRange(modelId: number, startFittingDate: Date, endFittingDate: Date, startShootingDate: Date, endShootingDate: Date) {
    return this.prisma.schedule.findFirst({
      where: {
        modelId,
        type: { in: [ScheduleType.BUSY, ScheduleType.WORK] },
        OR: [
          {
            startDate: {
              gte: startFittingDate,
              lte: endFittingDate,
            },
          },
          {
            endDate: {
              gte: startFittingDate,
              lte: endFittingDate,
            },
          },
          {
            startDate: {
              lte: startFittingDate,
            },
            endDate: {
              gte: startFittingDate,
            },
          },
          {
            startDate: {
              lte: endFittingDate,
            },
            endDate: {
              gte: endFittingDate,
            },
          },
          // Shooting
          {
            startDate: {
              gte: startShootingDate,
              lte: endShootingDate,
            },
          },
          {
            endDate: {
              gte: startShootingDate,
              lte: endShootingDate,
            },
          },
          {
            startDate: {
              lte: startShootingDate,
            },
            endDate: {
              gte: startShootingDate,
            },
          },
          {
            startDate: {
              lte: endShootingDate,
            },
            endDate: {
              gte: endShootingDate,
            },
          },
        ],
      }
    })
  }

  async update(modelId: number, campaignRoleId: number, status: RegisterStatus, role) {
    const data = await this.findOne(modelId, campaignRoleId);

    if (role === 'ADMIN') {
      if (status && data.status === RegisterStatus.REJECTED && (status !== RegisterStatus.ACCEPTED && status !== RegisterStatus.REJECTED && status !== RegisterStatus.REGISTERED)) {
        throw new ForbiddenException('Chuyển trạng thái không hợp lệ');
      }

      if (status && data.status === RegisterStatus.COMPLETED) {
        throw new ForbiddenException('Không thể cập nhật trạng thái khi đã từ chối hoặc hoàn thành');
      }

      if (status && status === RegisterStatus.COMPLETED && data.status === RegisterStatus.REGISTERED) {
        throw new ForbiddenException('Không thể cập nhật trạng thái từ đăng ký sang hoàn thành');
      }

      if (status && status === RegisterStatus.COMPLETED && data.status === RegisterStatus.REJECTED) {
        throw new ForbiddenException('Không thể cập nhật trạng thái từ hủy sang hoàn thành');
      }

      if (status && status === RegisterStatus.ACCEPTED) {
        const schedule = await this.findScheduleInRange(
          modelId,
          data.campaignRole.campaign.startFittingDate,
          data.campaignRole.campaign.endFittingDate,
          data.campaignRole.startShootingDate,
          data.campaignRole.endShootingDate,
        )

        if (schedule) {
          throw new ForbiddenException("Mẫu đã có lịch bận/du lịch trùng với ngày thử đồ hoặc ngày quay")
        } else {
          this.createScheduleWhenAccept(modelId, campaignRoleId, data.campaignRole.name, data.campaignRole.campaign.startFittingDate, data.campaignRole.campaign.endFittingDate, data.campaignRole.startShootingDate, data.campaignRole.endShootingDate)

          const message = '💥💥💥 `Ứng tuyển chờ duyệt thành công` 💥💥💥\n' +
            `👤 *Tên mẫu*: ${data.model.user.firstname} ${data.model.user.lastname}\n` +
            `✉️ *Email*: ${data.model.user.email}\n` +
            `🗞 *Chiến dịch*: ${data.campaignRole.campaign.name}\n` +
            `🧑 *Vai trò*: ${data.campaignRole.name}\n` +
            `📍 *Xem ngay tại*: https://felix-admin.zackco.com/data/campaign/detail?id=${data.campaignRole.campaignId}`;

          this.telegramService.sendMessage(message)
        }
      }

      if (status && status === RegisterStatus.REJECTED) {
        this.removeScheduleWhenReject(campaignRoleId)

        const message = '💥💥💥 `Ứng tuyển bị từ chối` 💥💥💥\n' +
          `👤 *Tên mẫu*: ${data.model.user.firstname} ${data.model.user.lastname}\n` +
          `✉️ *Email*: ${data.model.user.email}\n` +
          `🗞 *Chiến dịch*: ${data.campaignRole.campaign.name}\n` +
          `🧑 *Vai trò*: ${data.campaignRole.name}\n` +
          `📍 *Xem ngay tại*: https://felix-admin.zackco.com/data/campaign/detail?id=${data.campaignRole.campaignId}`;

        this.telegramService.sendMessage(message)
      }

      const now = dayjs().add(7, 'hour');
      if (status && status === RegisterStatus.COMPLETED && dayjs(data.campaignRole.endShootingDate).isAfter(now)) {
        throw new ForbiddenException("Không thể cập nhật sang trạng thái hoàn thành vì ngày quay của phân vai này chưa qua")
      }
    } else {
      if (
        status &&
        status === RegisterStatus.CANCELED &&
        data.status !== RegisterStatus.REGISTERED
      ) {
        throw new ForbiddenException('Không thể cập nhật trạng thái');
      }

      if (
        status &&
        status === RegisterStatus.CANCELED &&
        data.status === RegisterStatus.REGISTERED
      ) {
        try {
          await this.prisma.modelOnCampaign.delete({
            where: { campaignRoleId_modelId: { campaignRoleId, modelId } },
          });

          return "Hủy thành công"
        } catch (error) {
          throw new ForbiddenException(error.message);
        }
      }
    }

    try {
      const result = await this.prisma.modelOnCampaign.update({
        where: { campaignRoleId_modelId: { campaignRoleId, modelId } },
        data: { status },
      });

      if (status === RegisterStatus.ACCEPTED || status === RegisterStatus.REJECTED) {
        const mes = status === RegisterStatus.ACCEPTED ? 
          msg: `Chúc mừng bạn đã được chọn cho job "..." với vai "..."."`
         :
          `Rất tiếc bạn chưa phù hợp cho job "...". Hãy tiếp tục theo dõi Felix Zone để cập nhật những job mới phù hợp sắp tới nhé`

        this.firebaseService.sendNotificationToUser(data.modelId, `Ứng tuyển ${mes.stt}`, `Yêu cầu ứng tuyển vào sự kiện ${data.campaignRole.campaign.name} với vai trò ${data.campaignRole.name} ${mes.stt}`, {
          type: TypeNotification.processing_campaign,
          data: {
            message: 'Có sự kiện mới. Truy cập vào ứng dụng ngay để xem chi tiết'
          } as any
        })
      }

      return result;
    } catch (error) {
      throw new ForbiddenException(error.message);
    }
  }

  async remove(modelId: number, campaignRoleId: number) {
    await this.findOne(modelId, campaignRoleId);

    try {
      await this.prisma.modelOnCampaign.delete({
        where: { campaignRoleId_modelId: { campaignRoleId, modelId } },
      });

      return 'Xóa thành công'
    } catch (error) {
      throw new ForbiddenException(error.message);
    }
  }
}
Leave a Comment