2026-04-27 10:45:39 +03:30
|
|
|
import { QUERY_CONSTANTS } from '@/common/queryConstants'
|
|
|
|
|
import mapConsumerWithLicenseUtil from '@/common/utils/mappers/consumer_mappers.util'
|
2026-04-23 20:59:39 +03:30
|
|
|
import { PasswordUtil } from '@/common/utils/password.util'
|
|
|
|
|
import {
|
|
|
|
|
AccountStatus,
|
|
|
|
|
AccountType,
|
|
|
|
|
ConsumerRole,
|
|
|
|
|
ConsumerStatus,
|
2026-04-27 10:45:39 +03:30
|
|
|
ConsumerType,
|
2026-04-23 20:59:39 +03:30
|
|
|
PartnerStatus,
|
|
|
|
|
} from '@/generated/prisma/enums'
|
2026-04-27 10:45:39 +03:30
|
|
|
import {
|
|
|
|
|
ConsumerCreateInput,
|
|
|
|
|
ConsumerSelect,
|
|
|
|
|
ConsumerWhereInput,
|
|
|
|
|
} from '@/generated/prisma/models'
|
2026-04-23 20:59:39 +03:30
|
|
|
import { PrismaService } from '@/prisma/prisma.service'
|
|
|
|
|
import { BadRequestException, Injectable } from '@nestjs/common'
|
|
|
|
|
import { ResponseMapper } from 'common/response/response-mapper'
|
|
|
|
|
import { CreateConsumerDto, UpdateConsumerDto } from './dto/create-consumers.dto'
|
|
|
|
|
|
|
|
|
|
@Injectable()
|
|
|
|
|
export class PartnerConsumersService {
|
|
|
|
|
constructor(private readonly prisma: PrismaService) {}
|
|
|
|
|
|
|
|
|
|
private readonly setExpireDate = (starts_at: Date) => {
|
|
|
|
|
return new Date(
|
|
|
|
|
new Date(starts_at).setFullYear(new Date(starts_at).getFullYear() + 1),
|
|
|
|
|
).toISOString()
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
defaultSelect: ConsumerSelect = {
|
|
|
|
|
id: true,
|
|
|
|
|
status: true,
|
|
|
|
|
created_at: true,
|
2026-04-27 22:11:05 +03:30
|
|
|
...QUERY_CONSTANTS.CONSUMER.infoSelect,
|
|
|
|
|
...QUERY_CONSTANTS.CONSUMER.activeBusinessCount,
|
2026-04-23 20:59:39 +03:30
|
|
|
}
|
|
|
|
|
|
|
|
|
|
private defaultWhere = (partner_id: string): ConsumerWhereInput => ({
|
2026-04-27 10:45:39 +03:30
|
|
|
OR: [
|
|
|
|
|
{
|
|
|
|
|
legal: {
|
|
|
|
|
partner_id,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
individual: {
|
|
|
|
|
partner_id,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
],
|
2026-04-23 20:59:39 +03:30
|
|
|
})
|
|
|
|
|
|
2026-04-26 09:54:48 +03:30
|
|
|
async findAll(partner_id: string, page = 1, perPage = 10) {
|
|
|
|
|
const [consumers, total] = await this.prisma.$transaction(async tx => [
|
2026-04-23 20:59:39 +03:30
|
|
|
await tx.consumer.findMany({
|
|
|
|
|
where: this.defaultWhere(partner_id),
|
|
|
|
|
select: this.defaultSelect,
|
2026-04-26 09:54:48 +03:30
|
|
|
skip: (page - 1) * perPage,
|
2026-04-23 20:59:39 +03:30
|
|
|
take: 10,
|
|
|
|
|
}),
|
|
|
|
|
await tx.consumer.count({
|
|
|
|
|
where: this.defaultWhere(partner_id),
|
|
|
|
|
}),
|
|
|
|
|
])
|
|
|
|
|
return ResponseMapper.paginate(consumers.map(mapConsumerWithLicenseUtil), {
|
2026-04-26 09:54:48 +03:30
|
|
|
total,
|
2026-04-23 20:59:39 +03:30
|
|
|
page,
|
2026-04-26 09:54:48 +03:30
|
|
|
perPage,
|
2026-04-23 20:59:39 +03:30
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async findOne(partner_id: string, consumer_id: string) {
|
|
|
|
|
const consumer = await this.prisma.consumer.findUniqueOrThrow({
|
|
|
|
|
where: {
|
|
|
|
|
...(this.defaultWhere(partner_id) as any),
|
|
|
|
|
id: consumer_id,
|
|
|
|
|
},
|
|
|
|
|
select: this.defaultSelect,
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return ResponseMapper.single(mapConsumerWithLicenseUtil(consumer))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async create(partner_id: string, data: CreateConsumerDto) {
|
|
|
|
|
const consumer = await this.prisma.$transaction(async tx => {
|
|
|
|
|
const partnerLicense = await tx.license.findFirst({
|
|
|
|
|
where: {
|
|
|
|
|
charge_transaction: {
|
|
|
|
|
partner: {
|
|
|
|
|
id: partner_id,
|
|
|
|
|
status: PartnerStatus.ACTIVE,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
activation: null,
|
|
|
|
|
},
|
|
|
|
|
orderBy: {
|
|
|
|
|
charge_transaction: {
|
|
|
|
|
activation_expires_at: 'asc',
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
charge_transaction: {
|
|
|
|
|
select: {
|
|
|
|
|
partner: {
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
name: true,
|
|
|
|
|
status: true,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
if (!partnerLicense) {
|
|
|
|
|
throw new BadRequestException(`تعداد لایسنسهای فعلی شما به پایان رسیده است.`)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-27 22:11:05 +03:30
|
|
|
const { username, password, individual, legal, ...rest } = data
|
2026-04-23 20:59:39 +03:30
|
|
|
|
2026-04-27 10:45:39 +03:30
|
|
|
const createConsumerData: ConsumerCreateInput = {
|
|
|
|
|
...rest,
|
|
|
|
|
accounts: {
|
|
|
|
|
create: {
|
|
|
|
|
role: ConsumerRole.OWNER,
|
|
|
|
|
account: {
|
|
|
|
|
create: {
|
|
|
|
|
username,
|
|
|
|
|
password: await PasswordUtil.hash(password),
|
|
|
|
|
type: AccountType.CONSUMER,
|
|
|
|
|
status: AccountStatus.ACTIVE,
|
|
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2026-04-23 20:59:39 +03:30
|
|
|
},
|
2026-04-27 10:45:39 +03:30
|
|
|
status: ConsumerStatus.ACTIVE,
|
|
|
|
|
}
|
2026-04-23 20:59:39 +03:30
|
|
|
|
2026-04-27 10:45:39 +03:30
|
|
|
const partner = {
|
|
|
|
|
partner: { connect: { id: partner_id } },
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (!legal && !individual) {
|
|
|
|
|
throw new BadRequestException(
|
|
|
|
|
`برای ایجاد مصرف کننده باید یکی از اطلاعات فردی یا حقوقی وارد شود.`,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
if (data.type === ConsumerType.INDIVIDUAL && !individual) {
|
2026-04-23 20:59:39 +03:30
|
|
|
throw new BadRequestException(
|
2026-04-27 10:45:39 +03:30
|
|
|
`برای ایجاد مصرف کننده با نوع حقیقی باید اطلاعات فردی وارد شود.`,
|
|
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
if (data.type === ConsumerType.LEGAL && !legal) {
|
|
|
|
|
throw new BadRequestException(
|
|
|
|
|
`برای ایجاد مصرف کننده با نوع حقوقی باید اطلاعات حقوقی وارد شود.`,
|
2026-04-23 20:59:39 +03:30
|
|
|
)
|
|
|
|
|
}
|
|
|
|
|
|
2026-04-27 10:45:39 +03:30
|
|
|
let consumerExistError = ''
|
|
|
|
|
|
|
|
|
|
if (legal) {
|
|
|
|
|
const existingConsumer = await tx.consumer.findFirst({
|
|
|
|
|
where: {
|
|
|
|
|
legal: { registration_code: legal.registration_code, partner_id },
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
legal: {
|
|
|
|
|
select: {
|
|
|
|
|
name: true,
|
|
|
|
|
},
|
2026-04-23 20:59:39 +03:30
|
|
|
},
|
|
|
|
|
},
|
2026-04-27 10:45:39 +03:30
|
|
|
})
|
|
|
|
|
createConsumerData.legal = {
|
|
|
|
|
create: {
|
|
|
|
|
...legal,
|
|
|
|
|
...partner,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (existingConsumer) {
|
|
|
|
|
consumerExistError = `مشتری با نام ${existingConsumer.legal!.name} با این شماره ثبت، از قبل توسط شما ایجاد شده است.`
|
|
|
|
|
}
|
|
|
|
|
} else if (individual) {
|
|
|
|
|
const existingConsumer = await tx.consumer.findFirst({
|
|
|
|
|
where: {
|
|
|
|
|
individual: { national_code: individual.national_code, partner_id },
|
|
|
|
|
},
|
|
|
|
|
select: {
|
|
|
|
|
id: true,
|
|
|
|
|
individual: {
|
|
|
|
|
select: {
|
|
|
|
|
first_name: true,
|
|
|
|
|
last_name: true,
|
2026-04-23 20:59:39 +03:30
|
|
|
},
|
|
|
|
|
},
|
|
|
|
|
},
|
2026-04-27 10:45:39 +03:30
|
|
|
})
|
|
|
|
|
createConsumerData.individual = {
|
|
|
|
|
create: {
|
|
|
|
|
...individual,
|
|
|
|
|
...partner,
|
|
|
|
|
},
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
if (existingConsumer) {
|
|
|
|
|
;`مشتری با نام ${existingConsumer.individual!.first_name} ${existingConsumer.individual!.last_name} یا این کد ملی، از قبل توسط شما ایجاد شده است.`
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
return await tx.consumer.create({
|
|
|
|
|
data: createConsumerData,
|
2026-04-23 20:59:39 +03:30
|
|
|
select: this.defaultSelect,
|
|
|
|
|
})
|
|
|
|
|
})
|
|
|
|
|
|
|
|
|
|
return ResponseMapper.single(mapConsumerWithLicenseUtil(consumer))
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
async update(id: string, partner_id: string, data: UpdateConsumerDto) {
|
|
|
|
|
return this.prisma.consumer.update({
|
|
|
|
|
where: {
|
|
|
|
|
...(this.defaultWhere(partner_id) as any),
|
|
|
|
|
id,
|
|
|
|
|
},
|
2026-04-27 22:11:05 +03:30
|
|
|
data: {
|
|
|
|
|
status: data.status,
|
|
|
|
|
legal: {
|
|
|
|
|
update: data.legal,
|
|
|
|
|
},
|
|
|
|
|
individual: {
|
|
|
|
|
update: data.individual,
|
|
|
|
|
},
|
|
|
|
|
},
|
2026-04-23 20:59:39 +03:30
|
|
|
})
|
|
|
|
|
}
|
|
|
|
|
}
|