import { PasswordUtil } from '@/common/utils/password.util' import { AccountStatus, AccountType, ConsumerRole, POSStatus, } from '@/generated/prisma/enums' import { PosCreateInput, PosSelect, PosWhereInput } from '@/generated/prisma/models' import { PrismaService } from '@/prisma/prisma.service' import { BadRequestException, Injectable } from '@nestjs/common' import { ResponseMapper } from 'common/response/response-mapper' import { CreatePosDto, UpdatePosDto } from './dto/pos.dto' @Injectable() export class ComplexPosesService { constructor(private readonly prisma: PrismaService) {} defaultSelect: PosSelect = { id: true, name: true, model: true, serial_number: true, status: true, created_at: true, pos_type: true, account: { select: { account: { select: { username: true, }, }, }, }, provider: { select: { id: true, name: true, }, }, device: { select: { name: true, id: true, brand: { select: { id: true, name: true, }, }, }, }, complex: { select: { id: true, name: true, business_activity: { select: { id: true, name: true, }, }, }, }, } defaultWhere = ( consumer_id: string, business_activity_id: string, complex_id: string, ): PosWhereInput => ({ complex: { id: complex_id, business_activity: { id: business_activity_id, consumer_id, }, }, }) defaultInsert = async ( consumer_id: string, complex_id: string, account_allocation_id: string, data: CreatePosDto, ): Promise => { const { device_id, provider_id, username, password, ...rest } = data return { ...rest, complex: { connect: { id: complex_id, }, }, account: { create: { role: ConsumerRole.OPERATOR, account_allocation: { connect: { id: account_allocation_id, }, }, account: { create: { username, password: await PasswordUtil.hash(password), type: AccountType.CONSUMER, status: AccountStatus.ACTIVE, }, }, consumer: { connect: { id: consumer_id, }, }, }, }, provider: provider_id ? { connect: { id: provider_id, }, } : undefined, device: device_id ? { connect: { id: device_id, }, } : undefined, } } private readonly mapPos = (pos: any) => { const { account, ...rest } = pos const { account: accountInfo } = account return { ...rest, account: { username: accountInfo.username, }, } } async findAll(consumer_id: string, business_activity_id: string, complex_id: string) { const poses = await this.prisma.pos.findMany({ where: this.defaultWhere(consumer_id, business_activity_id, complex_id), select: this.defaultSelect, }) return ResponseMapper.list(poses.map(this.mapPos)) } async findOne( consumer_id: string, business_activity_id: string, complex_id: string, id: string, ) { const pos = await this.prisma.pos.findUnique({ where: { ...(this.defaultWhere(consumer_id, business_activity_id, complex_id) as any), id, }, select: this.defaultSelect, }) return ResponseMapper.single(this.mapPos(pos)) } async create( consumer_id: string, business_activity_id: string, complex_id: string, data: CreatePosDto, ) { const now = new Date() const pos = await this.prisma.$transaction(async tx => { const account_allocation = await tx.licenseAccountAllocation.findFirst({ where: { account_id: null, license_activation: { business_activity_id, business_activity: { consumer_id, }, OR: [ { expires_at: { gte: now, }, }, { license_renews: { some: { expires_at: { gte: now, }, }, }, }, ], }, }, select: { id: true, }, }) if (!account_allocation) { throw new BadRequestException( `تعداد کاربرهای تخصیص داده شده برای این فعالیت تجاری به پایان رسیده است.`, ) } return await tx.pos.create({ data: { ...(await this.defaultInsert( consumer_id, complex_id, account_allocation.id, data, )), status: POSStatus.ACTIVE, }, }) }) return ResponseMapper.create(pos) } async update( consumer_id: string, business_activity_id: string, complex_id: string, id: string, data: UpdatePosDto, ) { const { device_id, provider_id, ...rest } = data const pos = await this.prisma.pos.update({ where: { ...(this.defaultWhere(consumer_id, business_activity_id, complex_id) as any), id, }, data: { complex: { connect: { id: complex_id, }, }, provider: provider_id ? { connect: { id: provider_id, }, } : undefined, device: device_id ? { connect: { id: device_id, }, } : undefined, ...rest, }, }) return ResponseMapper.update(pos) } }