feat: باشگاه امتیازات کارکنان (موتور امتیاز، جدول رتبه، فروشگاه پاداش، نشان‌ها، پنل مدیریت و گزارش ROI)

- موتور رویدادمحور با شرط، محدودیت، تأیید مدیر و idempotency
- اتصال به لید، مشتری، معامله، فعالیت، روتین، پیش‌فاکتور، فاکتور و تیکت
- صفحه /club و /club/admin، اعلان زنده امتیاز، آیتم منو
- انتقال فرم‌ساز سرنخ به ابزارها

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-10 21:28:49 +03:30
co-authored by Cursor
parent b87ebb22e0
commit 60d797f184
51 changed files with 11298 additions and 806 deletions
+15 -1
View File
@@ -26,6 +26,7 @@ import {
import { normalizeTags } from '../common/tags';
import { normalizePersonImportSource } from './person-source';
import { buildSearchWhere, ci } from '../common/search';
import { GamificationService } from '../gamification/gamification.service';
function parseDateOrNull(raw?: string | null): Date | null {
if (!raw?.trim()) return null;
@@ -70,7 +71,10 @@ type CompanyRow = {
@Injectable()
export class CompaniesService {
constructor(private readonly prisma: PrismaService) {}
constructor(
private readonly prisma: PrismaService,
private readonly game: GamificationService,
) {}
async list(
actor: Actor,
@@ -157,6 +161,16 @@ export class CompaniesService {
data,
include: companyInclude,
});
if (row.importSource === 'manual') {
this.game.emit({
organizationId: actor.organizationId,
userId: actor.userId,
event: 'COMPANY_CREATED',
entityType: 'company',
entityId: row.id,
entityTitle: row.name,
});
}
return this.toDto(row);
}
+13
View File
@@ -31,6 +31,7 @@ import { LoyaltyService } from '../loyalty/loyalty.service';
import { AutomationsService } from '../automations/automations.service';
import { MessageAutomationsService } from '../message-automations/message-automations.service';
import { WebhooksService } from '../public-api/webhooks.service';
import { GamificationService } from '../gamification/gamification.service';
import { normalizeTags } from '../common/tags';
import { buildSearchWhere, ci } from '../common/search';
import {
@@ -90,6 +91,7 @@ export class PeopleService {
private readonly automations: AutomationsService,
private readonly messageAutomations: MessageAutomationsService,
private readonly webhooks: WebhooksService,
private readonly game: GamificationService,
) {}
async list(
@@ -226,6 +228,17 @@ export class PeopleService {
};
await this.automations.runTrigger('person_created', createdCtx);
await this.messageAutomations.onEvent('person_created', createdCtx);
if (row.importSource === 'manual') {
this.game.emit({
organizationId: actor.organizationId,
userId: actor.userId,
event: 'CUSTOMER_CREATED',
entityType: 'person',
entityId: row.id,
entityTitle: createdCtx.title,
facts: { source: row.importSource },
});
}
this.webhooks.emit(actor.organizationId, 'person.created', {
id: row.id,
fullName: createdCtx.title,