import { PasswordUtil } from '@/common/utils/password.util' import { ChargedLicenseTransactions } from '@/generated/prisma/client' import { AccountStatus, AccountType, PartnerRole, PartnerStatus, } from '@/generated/prisma/enums' import { PartnerSelect } from '@/generated/prisma/models' import { PrismaService } from '@/prisma/prisma.service' import { Injectable } from '@nestjs/common' import { ResponseMapper } from 'common/response/response-mapper' import { CreatePartnerDto, UpdatePartnerDto } from './dto/partner.dto' @Injectable() export class PartnersService { constructor(private readonly prisma: PrismaService) {} private readonly defaultSelect: PartnerSelect = { id: true, name: true, code: true, status: true, created_at: true, chargedLicenseTransactions: { select: { activation_expires_at: true, licenses: { select: { activated_license: { select: { id: true, }, }, }, }, }, }, } private readonly separateLicenseCount = ( transactions: ChargedLicenseTransactions[] | null, ) => { function toDateOnlyString(date) { return date.toISOString().slice(0, 10) } const startOfTodayDate = toDateOnlyString(new Date()) const used = transactions?.reduce((sum, cur) => { const license = cur as any return ( sum + license.licenses.filter(license => license.activated_license).length || 0 ) }, 0) const total = transactions?.reduce((sum, cur) => { const license = cur as any return sum + license.licenses.length || 0 }, 0) const expired = transactions?.reduce((sum, cur) => { const license = cur as any const activationExpiresDate = toDateOnlyString(license.activation_expires_at) if (startOfTodayDate > activationExpiresDate) return ( sum + license.licenses.filter(license => !license.activated_license).length || 0 ) return sum }, 0) return { total, used, expired, } } async findAll() { const partners = await this.prisma.partner.findMany({ select: this.defaultSelect, }) const mappedPartners = partners.map(partner => { const { chargedLicenseTransactions, ...rest } = partner return { ...rest, licenses_status: this.separateLicenseCount(chargedLicenseTransactions), } }) return ResponseMapper.list(mappedPartners) } async findOne(id: string) { const partner = await this.prisma.partner.findUniqueOrThrow({ where: { id }, select: this.defaultSelect, }) const { chargedLicenseTransactions, ...rest } = partner const mappedPartner = { ...rest, licenses_status: this.separateLicenseCount(chargedLicenseTransactions), } return ResponseMapper.single(mappedPartner) } async create(data: CreatePartnerDto) { const { username, password, ...rest } = data const partner = await this.prisma.partner.create({ data: { ...rest, status: PartnerStatus.ACTIVE, partner_accounts: { create: { role: PartnerRole.OWNER, account: { create: { username, password: await PasswordUtil.hash(data.password), status: AccountStatus.ACTIVE, type: AccountType.PARTNER, }, }, }, }, }, select: this.defaultSelect, }) return ResponseMapper.create(partner) } async update(id: string, data: UpdatePartnerDto) { const partner = await this.prisma.partner.update({ where: { id }, data, select: this.defaultSelect, }) return ResponseMapper.update(partner) } async delete(id: string) { await this.prisma.partner.delete({ where: { id } }) return ResponseMapper.delete() } }