feat(tahesab): sync full customer profile fields into CRM people
Pull national id, address, city, and rasteh on import/refresh so person records match Tahesab, and surface them on the person form and profile. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -97,6 +97,9 @@ const website = ref('');
|
||||
const instagram = ref('');
|
||||
const birthDate = ref('');
|
||||
const referrer = ref('');
|
||||
const nationalId = ref('');
|
||||
const city = ref('');
|
||||
const rasteh = ref('');
|
||||
const addresses = ref<string[]>(['']);
|
||||
const notes = ref('');
|
||||
const tagsRaw = ref('');
|
||||
@@ -283,6 +286,16 @@ function fill(p: PersonDto) {
|
||||
mood.value = p.mood || 'newcomer';
|
||||
groupIds.value = (p.groups ?? []).map((g) => g.id);
|
||||
customFields.value = { ...(p.customFields ?? {}) };
|
||||
const cf = customFields.value;
|
||||
nationalId.value =
|
||||
typeof cf.nationalId === 'string'
|
||||
? cf.nationalId
|
||||
: typeof cf.nationalId === 'number'
|
||||
? String(cf.nationalId)
|
||||
: '';
|
||||
city.value = typeof cf.city === 'string' ? cf.city : '';
|
||||
rasteh.value =
|
||||
typeof cf.rasteh === 'string' || typeof cf.rasteh === 'number' ? String(cf.rasteh) : '';
|
||||
loyaltyPoints.value = p.loyaltyPoints ?? 0;
|
||||
loyaltyTierName.value = p.loyaltyTier?.name ?? '';
|
||||
}
|
||||
@@ -344,6 +357,18 @@ function parseTags(raw: string): string[] {
|
||||
}
|
||||
|
||||
function payload(): CreatePersonRequest {
|
||||
const fields: Record<string, unknown> = { ...customFields.value };
|
||||
const nid = nationalId.value.trim();
|
||||
if (nid) fields.nationalId = nid;
|
||||
else delete fields.nationalId;
|
||||
const cityVal = city.value.trim();
|
||||
if (cityVal) fields.city = cityVal;
|
||||
else delete fields.city;
|
||||
const rastehRaw = rasteh.value.trim();
|
||||
if (rastehRaw) {
|
||||
const n = Number(rastehRaw);
|
||||
fields.rasteh = Number.isFinite(n) && String(n) === rastehRaw ? n : rastehRaw;
|
||||
} else delete fields.rasteh;
|
||||
return {
|
||||
firstName: firstName.value,
|
||||
lastName: lastName.value,
|
||||
@@ -363,7 +388,7 @@ function payload(): CreatePersonRequest {
|
||||
companyId: companyId.value || null,
|
||||
mood: mood.value,
|
||||
groupIds: groupIds.value,
|
||||
customFields: customFields.value,
|
||||
customFields: fields,
|
||||
};
|
||||
}
|
||||
|
||||
@@ -545,6 +570,21 @@ onMounted(load);
|
||||
<a-input v-model:value="referrer" placeholder="نام معرف" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item label="کد ملی">
|
||||
<a-input v-model:value="nationalId" dir="ltr" placeholder="کد ملی (تهحساب)" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item label="شهر">
|
||||
<a-input v-model:value="city" placeholder="شهر" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
<a-col :xs="24" :md="12">
|
||||
<a-form-item label="رسته">
|
||||
<a-input v-model:value="rasteh" dir="ltr" placeholder="رسته حساب تهحساب" />
|
||||
</a-form-item>
|
||||
</a-col>
|
||||
</a-row>
|
||||
|
||||
<a-divider orientation="right">آدرسها</a-divider>
|
||||
|
||||
@@ -183,6 +183,18 @@ const externalCode = computed(() => {
|
||||
}
|
||||
return '';
|
||||
});
|
||||
function customFieldText(...keys: string[]) {
|
||||
const fields = person.value?.customFields ?? {};
|
||||
for (const key of keys) {
|
||||
const raw = fields[key];
|
||||
if (typeof raw === 'string' && raw.trim()) return raw.trim();
|
||||
if (typeof raw === 'number' && Number.isFinite(raw)) return String(raw);
|
||||
}
|
||||
return '';
|
||||
}
|
||||
const nationalIdLabel = computed(() => customFieldText('nationalId', 'CodeMelli', 'codeMeli'));
|
||||
const cityLabel = computed(() => customFieldText('city', 'City'));
|
||||
const rastehLabel = computed(() => customFieldText('rasteh', 'Rasteh'));
|
||||
const SOURCE_LABELS: Record<string, string> = {
|
||||
manual: 'دستی',
|
||||
tahesab: 'تهحساب',
|
||||
@@ -444,6 +456,9 @@ const infoEmpty = computed(() => {
|
||||
!p.instagram &&
|
||||
!p.birthDate &&
|
||||
!p.referrer &&
|
||||
!nationalIdLabel.value &&
|
||||
!cityLabel.value &&
|
||||
!rastehLabel.value &&
|
||||
!(p.addresses?.length) &&
|
||||
!p.company &&
|
||||
!externalCode.value &&
|
||||
@@ -794,6 +809,18 @@ watch(() => route.query.tab, readTab, { immediate: true });
|
||||
<dt>معرف</dt>
|
||||
<dd>{{ person.referrer }}</dd>
|
||||
</div>
|
||||
<div v-if="nationalIdLabel" class="fact">
|
||||
<dt>کد ملی</dt>
|
||||
<dd dir="ltr">{{ toFaDigits(nationalIdLabel) }}</dd>
|
||||
</div>
|
||||
<div v-if="cityLabel" class="fact">
|
||||
<dt>شهر</dt>
|
||||
<dd>{{ cityLabel }}</dd>
|
||||
</div>
|
||||
<div v-if="rastehLabel" class="fact">
|
||||
<dt>رسته</dt>
|
||||
<dd dir="ltr">{{ toFaDigits(rastehLabel) }}</dd>
|
||||
</div>
|
||||
<div v-if="person.website" class="fact">
|
||||
<dt>وبسایت</dt>
|
||||
<dd dir="ltr">{{ person.website }}</dd>
|
||||
@@ -1119,6 +1146,15 @@ watch(() => route.query.tab, readTab, { immediate: true });
|
||||
<div><dt>وبسایت</dt><dd>{{ person.website || '—' }}</dd></div>
|
||||
<div><dt>اینستاگرام</dt><dd dir="ltr">{{ person.instagram || '—' }}</dd></div>
|
||||
<div><dt>معرف</dt><dd>{{ person.referrer || '—' }}</dd></div>
|
||||
<div>
|
||||
<dt>کد ملی</dt>
|
||||
<dd dir="ltr">{{ nationalIdLabel ? toFaDigits(nationalIdLabel) : '—' }}</dd>
|
||||
</div>
|
||||
<div><dt>شهر</dt><dd>{{ cityLabel || '—' }}</dd></div>
|
||||
<div>
|
||||
<dt>رسته</dt>
|
||||
<dd dir="ltr">{{ rastehLabel ? toFaDigits(rastehLabel) : '—' }}</dd>
|
||||
</div>
|
||||
<div class="wide">
|
||||
<dt>آدرسها</dt>
|
||||
<dd>
|
||||
|
||||
Reference in New Issue
Block a user