fix: keep birthdays and show Shamsi dates
Imported customers keep their birthday, and assistant text plus remaining calendars use the Jalali date. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -22,6 +22,7 @@ export class CreateLeadDto {
|
||||
@IsOptional() @IsString() city?: string;
|
||||
@IsOptional() @IsString() region?: string;
|
||||
@IsOptional() @IsString() instagram?: string;
|
||||
@IsOptional() @IsString() birthDate?: string | null;
|
||||
@IsOptional() @IsArray() @IsString({ each: true }) addresses?: string[];
|
||||
@IsOptional() @IsString() trade?: string;
|
||||
@IsOptional() @IsString() source?: string;
|
||||
@@ -42,6 +43,7 @@ export class UpdateLeadDto {
|
||||
@IsOptional() @IsString() city?: string | null;
|
||||
@IsOptional() @IsString() region?: string | null;
|
||||
@IsOptional() @IsString() instagram?: string | null;
|
||||
@IsOptional() @IsString() birthDate?: string | null;
|
||||
@IsOptional() @IsArray() @IsString({ each: true }) addresses?: string[];
|
||||
@IsOptional() @IsString() trade?: string | null;
|
||||
@IsOptional() @IsString() source?: string | null;
|
||||
|
||||
@@ -4,6 +4,7 @@ import { Prisma } from '@prisma/client';
|
||||
import type { LeadImportJobDto } from '@mento/shared';
|
||||
import { PrismaService } from '../prisma/prisma.service';
|
||||
import {
|
||||
parseBirthDate,
|
||||
parseExcelMapping,
|
||||
parseJalaliDateTime,
|
||||
previewExcel,
|
||||
@@ -55,6 +56,12 @@ const LEAD_ALIASES: Record<string, string> = {
|
||||
اینستاگرام: 'instagram',
|
||||
پیجاینستاگرام: 'instagram',
|
||||
آیدیاینستاگرام: 'instagram',
|
||||
birthdate: 'birthDate',
|
||||
dateofbirth: 'birthDate',
|
||||
bdate: 'birthDate',
|
||||
تاریختولد: 'birthDate',
|
||||
تاریختولدمشتری: 'birthDate',
|
||||
تاریختولدشمسی: 'birthDate',
|
||||
registeredat: 'registeredAt',
|
||||
تاریخثبت: 'registeredAt',
|
||||
تاریخثبتمشتری: 'registeredAt',
|
||||
@@ -81,6 +88,7 @@ const LEAD_FIELDS: ExcelFieldOption[] = [
|
||||
{ key: 'homeAddress', label: 'آدرس منزل' },
|
||||
{ key: 'instagram', label: 'اینستاگرام' },
|
||||
{ key: 'registeredAt', label: 'تاریخ ثبت' },
|
||||
{ key: 'birthDate', label: 'تاریخ تولد' },
|
||||
{ key: 'trade', label: 'صنف' },
|
||||
{ key: 'source', label: 'منبع' },
|
||||
{ key: 'notes', label: 'توضیحات' },
|
||||
@@ -284,6 +292,9 @@ export class LeadsImportService {
|
||||
address2: get('address2', 'آدرس ۲', 'آدرس2', 'آدرس دوم'),
|
||||
homeAddress: get('homeAddress', 'آدرس منزل', 'آدرس خانه'),
|
||||
instagram: get('instagram', 'اینستاگرام', 'پیج اینستاگرام', 'آی دی اینستاگرام'),
|
||||
birthDate: parseBirthDate(
|
||||
get('birthDate', 'تاریخ تولد', 'تاریخ تولد مشتری', 'تاریخ تولد شمسی', 'birthdate'),
|
||||
)?.toISOString() ?? '',
|
||||
registeredAt,
|
||||
trade: get('trade', 'صنف', 'رسته'),
|
||||
source: get('source', 'منبع', 'منبع لید'),
|
||||
|
||||
@@ -5,6 +5,7 @@ import {
|
||||
NotFoundException,
|
||||
} from '@nestjs/common';
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { parseBirthDate } from '../common/excel';
|
||||
import * as path from 'node:path';
|
||||
import { randomUUID } from 'node:crypto';
|
||||
import type {
|
||||
@@ -268,6 +269,7 @@ export class LeadsService {
|
||||
city?: string | null;
|
||||
region?: string | null;
|
||||
instagram?: string | null;
|
||||
birthDate?: string | null;
|
||||
addresses?: string[];
|
||||
trade?: string | null;
|
||||
source?: string | null;
|
||||
@@ -314,6 +316,7 @@ export class LeadsService {
|
||||
city: emptyToNull(dto.city),
|
||||
region: emptyToNull(dto.region),
|
||||
instagram: emptyToNull(dto.instagram),
|
||||
birthDate: parseBirthDate(dto.birthDate),
|
||||
addresses: toJsonAddresses(dto.addresses),
|
||||
trade: emptyToNull(dto.trade),
|
||||
source: emptyToNull(dto.source),
|
||||
@@ -398,6 +401,9 @@ export class LeadsService {
|
||||
...(dto.instagram !== undefined
|
||||
? { instagram: emptyToNull(dto.instagram as string) }
|
||||
: {}),
|
||||
...(dto.birthDate !== undefined
|
||||
? { birthDate: parseBirthDate(dto.birthDate as string | null) }
|
||||
: {}),
|
||||
...(dto.addresses !== undefined
|
||||
? {
|
||||
addresses: toJsonAddresses(
|
||||
@@ -802,6 +808,7 @@ export class LeadsService {
|
||||
mobile: lead.mobile,
|
||||
phone: lead.phone,
|
||||
instagram: lead.instagram,
|
||||
birthDate: lead.birthDate,
|
||||
addresses: toJsonAddresses(asAddresses(lead.addresses)),
|
||||
notes: [
|
||||
lead.notes,
|
||||
@@ -819,6 +826,11 @@ export class LeadsService {
|
||||
},
|
||||
});
|
||||
createdPerson = true;
|
||||
} else if (!person.birthDate && lead.birthDate) {
|
||||
await this.prisma.person.update({
|
||||
where: { id: person.id },
|
||||
data: { birthDate: lead.birthDate },
|
||||
});
|
||||
}
|
||||
|
||||
const convertedStage = await this.prisma.leadStage.findFirst({
|
||||
@@ -985,6 +997,7 @@ export class LeadsService {
|
||||
address2?: string;
|
||||
homeAddress?: string;
|
||||
instagram?: string;
|
||||
birthDate?: string;
|
||||
registeredAt?: string;
|
||||
trade?: string;
|
||||
source?: string;
|
||||
@@ -996,11 +1009,20 @@ export class LeadsService {
|
||||
const title = String(row.title ?? row.contactName ?? '').trim();
|
||||
if (!mobile || !title) return 'error';
|
||||
|
||||
const birthDate = parseBirthDate(row.birthDate);
|
||||
const existingLead = await this.prisma.lead.findFirst({
|
||||
where: { organizationId, mobile },
|
||||
select: { id: true },
|
||||
});
|
||||
if (existingLead) return 'duplicate';
|
||||
if (existingLead) {
|
||||
if (birthDate) {
|
||||
await this.prisma.lead.updateMany({
|
||||
where: { id: existingLead.id, birthDate: null },
|
||||
data: { birthDate },
|
||||
});
|
||||
}
|
||||
return 'duplicate';
|
||||
}
|
||||
|
||||
const existingPerson = await this.prisma.person.findFirst({
|
||||
where: {
|
||||
@@ -1009,7 +1031,15 @@ export class LeadsService {
|
||||
},
|
||||
select: { id: true },
|
||||
});
|
||||
if (existingPerson) return 'duplicate';
|
||||
if (existingPerson) {
|
||||
if (birthDate) {
|
||||
await this.prisma.person.updateMany({
|
||||
where: { id: existingPerson.id, birthDate: null },
|
||||
data: { birthDate },
|
||||
});
|
||||
}
|
||||
return 'duplicate';
|
||||
}
|
||||
|
||||
try {
|
||||
const registeredAt = row.registeredAt ? new Date(row.registeredAt) : null;
|
||||
@@ -1023,6 +1053,7 @@ export class LeadsService {
|
||||
city: emptyToNull(row.city),
|
||||
region: emptyToNull(row.region),
|
||||
instagram: emptyToNull(row.instagram),
|
||||
birthDate,
|
||||
addresses: toJsonAddresses(
|
||||
collectAddresses(row.address, row.address2, row.homeAddress),
|
||||
),
|
||||
@@ -1101,6 +1132,7 @@ export class LeadsService {
|
||||
city: row.city,
|
||||
region: row.region,
|
||||
instagram: row.instagram,
|
||||
birthDate: row.birthDate?.toISOString() ?? null,
|
||||
addresses: asAddresses(row.addresses),
|
||||
trade: row.trade,
|
||||
source: row.source,
|
||||
|
||||
Reference in New Issue
Block a user