feat(customers): add optional group assignees with OR visibility for people, companies, and birthdays
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -51,26 +51,21 @@ export class CustomerGroupsService {
|
||||
include: {
|
||||
_count: { select: { people: true, companies: true } },
|
||||
parent: { select: { name: true } },
|
||||
assignees: { select: { id: true, fullName: true }, orderBy: { fullName: 'asc' } },
|
||||
},
|
||||
});
|
||||
return rows.map((r) => ({
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
color: r.color,
|
||||
position: r.position,
|
||||
fromTahesab: Boolean(r.tahesabGid),
|
||||
personCount: r._count.people,
|
||||
companyCount: r._count.companies,
|
||||
parentId: r.parentId,
|
||||
parentName: r.parent?.name ?? null,
|
||||
}));
|
||||
return rows.map((r) => this.toDto(r));
|
||||
}
|
||||
|
||||
async create(
|
||||
organizationId: string,
|
||||
dto: { name: string; color?: CustomerGroupColor },
|
||||
dto: { name: string; color?: CustomerGroupColor; assigneeIds?: string[] },
|
||||
): Promise<CustomerGroupDto> {
|
||||
const name = this.cleanName(dto.name);
|
||||
const assigneeIds =
|
||||
dto.assigneeIds !== undefined
|
||||
? await this.validAssigneeIds(organizationId, dto.assigneeIds)
|
||||
: [];
|
||||
const max = await this.prisma.customerGroup.aggregate({
|
||||
where: { organizationId },
|
||||
_max: { position: true },
|
||||
@@ -82,6 +77,9 @@ export class CustomerGroupsService {
|
||||
name,
|
||||
color: this.cleanColor(dto.color),
|
||||
position: (max._max.position ?? -1) + 1,
|
||||
...(assigneeIds.length
|
||||
? { assignees: { connect: assigneeIds.map((id) => ({ id })) } }
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -93,7 +91,12 @@ export class CustomerGroupsService {
|
||||
async update(
|
||||
organizationId: string,
|
||||
id: string,
|
||||
dto: { name?: string; color?: CustomerGroupColor; parentId?: string | null },
|
||||
dto: {
|
||||
name?: string;
|
||||
color?: CustomerGroupColor;
|
||||
parentId?: string | null;
|
||||
assigneeIds?: string[];
|
||||
},
|
||||
): Promise<CustomerGroupDto> {
|
||||
await this.require(organizationId, id);
|
||||
const parentId =
|
||||
@@ -101,6 +104,10 @@ export class CustomerGroupsService {
|
||||
if (parentId !== undefined) {
|
||||
await this.assertParent(organizationId, id, parentId);
|
||||
}
|
||||
const assigneeIds =
|
||||
dto.assigneeIds !== undefined
|
||||
? await this.validAssigneeIds(organizationId, dto.assigneeIds)
|
||||
: undefined;
|
||||
try {
|
||||
await this.prisma.customerGroup.update({
|
||||
where: { id },
|
||||
@@ -108,6 +115,9 @@ export class CustomerGroupsService {
|
||||
...(dto.name != null ? { name: this.cleanName(dto.name) } : {}),
|
||||
...(dto.color != null ? { color: this.cleanColor(dto.color) } : {}),
|
||||
...(parentId !== undefined ? { parentId } : {}),
|
||||
...(assigneeIds !== undefined
|
||||
? { assignees: { set: assigneeIds.map((uid) => ({ id: uid })) } }
|
||||
: {}),
|
||||
},
|
||||
});
|
||||
} catch (e) {
|
||||
@@ -317,6 +327,48 @@ export class CustomerGroupsService {
|
||||
return link?.group.name ?? null;
|
||||
}
|
||||
|
||||
private toDto(r: {
|
||||
id: string;
|
||||
name: string;
|
||||
color: string;
|
||||
position: number;
|
||||
tahesabGid: string | null;
|
||||
parentId: string | null;
|
||||
parent?: { name: string } | null;
|
||||
_count: { people: number; companies: number };
|
||||
assignees: Array<{ id: string; fullName: string }>;
|
||||
}): CustomerGroupDto {
|
||||
return {
|
||||
id: r.id,
|
||||
name: r.name,
|
||||
color: r.color,
|
||||
position: r.position,
|
||||
fromTahesab: Boolean(r.tahesabGid),
|
||||
personCount: r._count.people,
|
||||
companyCount: r._count.companies,
|
||||
parentId: r.parentId,
|
||||
parentName: r.parent?.name ?? null,
|
||||
assignees: r.assignees.map((a) => ({ id: a.id, fullName: a.fullName })),
|
||||
};
|
||||
}
|
||||
|
||||
private async validAssigneeIds(organizationId: string, ids: string[]): Promise<string[]> {
|
||||
const unique = [...new Set((ids ?? []).map((id) => id?.trim()).filter(Boolean))];
|
||||
if (!unique.length) return [];
|
||||
const rows = await this.prisma.user.findMany({
|
||||
where: {
|
||||
id: { in: unique },
|
||||
isActive: true,
|
||||
memberships: { some: { organizationId, isActive: true } },
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
if (rows.length !== unique.length) {
|
||||
throw new BadRequestException('یکی از مسئولان انتخابشده معتبر نیست');
|
||||
}
|
||||
return rows.map((r) => r.id);
|
||||
}
|
||||
|
||||
private async require(organizationId: string, id: string) {
|
||||
const row = await this.prisma.customerGroup.findFirst({
|
||||
where: { id, organizationId },
|
||||
|
||||
Reference in New Issue
Block a user