fix(contacts): treat Iranian mobile formats as one person
Tahesab import still replaces the name and keeps the previous name. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -17,7 +17,11 @@ import type {
|
||||
} from '@mento/shared';
|
||||
import { parseBirthDate } from '../../common/excel';
|
||||
import { PrismaService } from '../../prisma/prisma.service';
|
||||
import { normalizeEmail, normalizePhone } from '../../contacts/normalize';
|
||||
import {
|
||||
normalizeEmail,
|
||||
phoneIdentityKeys,
|
||||
storedPhoneNumber,
|
||||
} from '../../contacts/normalize';
|
||||
import { carryPreviousSource } from '../../contacts/person-source';
|
||||
import { ownerWhere, type Actor } from '../../common/record-scope';
|
||||
import { MontifyConnectionsService } from './connections.service';
|
||||
@@ -100,13 +104,7 @@ function arr(v: unknown): unknown[] {
|
||||
}
|
||||
|
||||
function mobileVariants(mobile: string): string[] {
|
||||
const digits = mobile.replace(/\D/g, '');
|
||||
let core = digits;
|
||||
if (core.startsWith('0098')) core = core.slice(4);
|
||||
else if (core.startsWith('98') && core.length === 12) core = core.slice(2);
|
||||
else if (core.startsWith('0')) core = core.slice(1);
|
||||
if (!core) return [mobile];
|
||||
return [...new Set([mobile, core, `0${core}`, `98${core}`, `+98${core}`])];
|
||||
return phoneIdentityKeys(mobile);
|
||||
}
|
||||
|
||||
function formatAddress(a: MontifyAddress): string | null {
|
||||
@@ -417,7 +415,7 @@ export class MontifySyncService {
|
||||
}> {
|
||||
const externalId = String(c.id);
|
||||
const { firstName, lastName } = splitName(c);
|
||||
const mobile = normalizePhone(c.phone ?? null);
|
||||
const mobile = storedPhoneNumber(c.phone ?? null);
|
||||
const email = normalizeEmail(c.email ?? null);
|
||||
const addressLines = addresses.map(formatAddress).filter((a): a is string => Boolean(a));
|
||||
const profile: CustomerProfile = {
|
||||
|
||||
@@ -9,6 +9,7 @@ import {
|
||||
import { Prisma } from '@prisma/client';
|
||||
import { PrismaService } from '../../prisma/prisma.service';
|
||||
import { carryPreviousSource } from '../../contacts/person-source';
|
||||
import { phoneIdentityKeys, storedPhoneNumber } from '../../contacts/normalize';
|
||||
import { applyPersonGenderTitle } from '@mento/shared';
|
||||
import { TahesabConnectionsService } from './connections.service';
|
||||
import {
|
||||
@@ -577,7 +578,7 @@ export class TahesabPersonLinkService {
|
||||
const named = applyPersonGenderTitle({ firstName: name, lastName: '' });
|
||||
const firstName = named.firstName;
|
||||
const lastName = named.lastName;
|
||||
const mobile = tel || null;
|
||||
const mobile = storedPhoneNumber(tel);
|
||||
const sourceRef = String(dto.moshtariCode);
|
||||
|
||||
let personId = dto.personId;
|
||||
@@ -606,8 +607,8 @@ export class TahesabPersonLinkService {
|
||||
...(!existing.birthDate && pickBirthDate(row) ? { birthDate: pickBirthDate(row) } : {}),
|
||||
...(mobile
|
||||
? {
|
||||
mobile: existing.mobile || mobile,
|
||||
phone: existing.phone || mobile,
|
||||
mobile: storedPhoneNumber(existing.mobile) || mobile,
|
||||
phone: storedPhoneNumber(existing.phone) || mobile,
|
||||
}
|
||||
: {}),
|
||||
},
|
||||
@@ -616,15 +617,18 @@ export class TahesabPersonLinkService {
|
||||
// اگر موبایل تکراری است → همان شخص؛ نام قبلی حفظ و نام تهحساب جایگزین.
|
||||
// شخصی که روی همین اتصال به کد دیگری لینک است کنار گذاشته میشود؛
|
||||
// وگرنه upsert لینک، کد قبلی را جابهجا و آن مشتری را دوباره «واردنشده» میکند.
|
||||
const byMobile = mobile
|
||||
? await this.prisma.person.findFirst({
|
||||
const mobileKeys = phoneIdentityKeys(mobile);
|
||||
const matches = mobileKeys.length
|
||||
? await this.prisma.person.findMany({
|
||||
where: {
|
||||
organizationId,
|
||||
OR: [{ mobile }, { phone: mobile }],
|
||||
OR: [{ mobile: { in: mobileKeys } }, { phone: { in: mobileKeys } }],
|
||||
accountingLinks: { none: { connectionId: dto.connectionId } },
|
||||
},
|
||||
orderBy: { createdAt: 'asc' },
|
||||
})
|
||||
: null;
|
||||
: [];
|
||||
const byMobile = matches.find((person) => person.importSource === 'tahesab') ?? matches[0] ?? null;
|
||||
if (byMobile) {
|
||||
const nameChanged =
|
||||
`${byMobile.firstName} ${byMobile.lastName}`.trim() !==
|
||||
|
||||
@@ -11,7 +11,7 @@ import type {
|
||||
} from '@mento/shared';
|
||||
import { PrismaService } from '../../prisma/prisma.service';
|
||||
import { NotificationsService } from '../../notifications/notifications.service';
|
||||
import { normalizePhone } from '../../contacts/normalize';
|
||||
import { iranMobileLookupKeys, normalizePhone } from '../../contacts/normalize';
|
||||
import { VoipConnectionsService } from './connections.service';
|
||||
|
||||
function digitsOnly(value: string | null | undefined): string {
|
||||
@@ -35,6 +35,7 @@ function phoneVariants(raw: string | null | undefined): string[] {
|
||||
variants.add(`0${d}`);
|
||||
variants.add(`98${d}`);
|
||||
}
|
||||
for (const key of iranMobileLookupKeys(raw)) variants.add(key);
|
||||
return [...variants];
|
||||
}
|
||||
|
||||
|
||||
@@ -6,7 +6,11 @@ import type {
|
||||
WooCommerceSyncResultDto,
|
||||
} from '@mento/shared';
|
||||
import { PrismaService } from '../../prisma/prisma.service';
|
||||
import { normalizeEmail, normalizePhone } from '../../contacts/normalize';
|
||||
import {
|
||||
normalizeEmail,
|
||||
phoneIdentityKeys,
|
||||
storedPhoneNumber,
|
||||
} from '../../contacts/normalize';
|
||||
import { WooConnectionsService } from './connections.service';
|
||||
import type { WooOrder } from './woo-client';
|
||||
|
||||
@@ -374,7 +378,8 @@ export class WooSyncService {
|
||||
): Promise<string | null> {
|
||||
const billing = order.billing ?? {};
|
||||
const email = normalizeEmail(billing.email ?? null);
|
||||
const mobile = normalizePhone(billing.phone ?? null);
|
||||
const mobile = storedPhoneNumber(billing.phone ?? null);
|
||||
const mobileKeys = phoneIdentityKeys(mobile);
|
||||
const firstName = (billing.first_name ?? '').trim() || 'مشتری';
|
||||
const lastName = (billing.last_name ?? '').trim() || 'ووکامرس';
|
||||
|
||||
@@ -387,7 +392,9 @@ export class WooSyncService {
|
||||
organizationId,
|
||||
OR: [
|
||||
...(email ? [{ email }] : []),
|
||||
...(mobile ? [{ mobile }, { phone: mobile }] : []),
|
||||
...(mobileKeys.length
|
||||
? [{ mobile: { in: mobileKeys } }, { phone: { in: mobileKeys } }]
|
||||
: []),
|
||||
],
|
||||
},
|
||||
select: { id: true },
|
||||
|
||||
Reference in New Issue
Block a user