Deals Excel import/export aligned with Didar: browser-side import, new deal fields (code, probability, closedAt, creator, lostNote, referrer), Didar custom fields

This commit is contained in:
2026-10-06 16:36:04 +03:30
parent e08f1452ef
commit 2a2728e5ee
11 changed files with 1032 additions and 210 deletions
+100
View File
@@ -901,11 +901,24 @@ export interface PipelineDto {
export interface DealDto {
id: string;
title: string;
/** کد دستی معامله */
code: string | null;
/** منبع ورود: manual | didar | excel */
importSource: string;
/** شناسه در مبدأ (کد دیدار) */
sourceRef: string | null;
amount: number | null;
currency: string;
status: DealStatus;
/** احتمال موفقیت ۰ تا ۱۰۰ */
probability: number | null;
source: string | null;
sourceDetail: string | null;
referrer: string | null;
lostReason: string | null;
lostNote: string | null;
closedAt: string | null;
createdBy: UserSummaryDto | null;
notes: string | null;
tags: string[];
isStale: boolean;
@@ -955,14 +968,21 @@ export interface CreateDealRequest {
title: string;
pipelineId?: string;
stageId?: string;
code?: string | null;
amount?: number | null;
currency?: string;
probability?: number | null;
source?: string;
sourceDetail?: string | null;
referrer?: string | null;
notes?: string;
tags?: string[];
isStale?: boolean;
isRotten?: boolean;
expectedCloseAt?: string | null;
lostReason?: string | null;
lostNote?: string | null;
closedAt?: string | null;
personId?: string | null;
companyId?: string | null;
ownerId?: string | null;
@@ -973,14 +993,20 @@ export interface CreateDealRequest {
export interface UpdateDealRequest {
title?: string;
code?: string | null;
amount?: number | null;
currency?: string;
probability?: number | null;
source?: string;
sourceDetail?: string | null;
referrer?: string | null;
notes?: string;
tags?: string[];
isStale?: boolean;
isRotten?: boolean;
lostReason?: string | null;
lostNote?: string | null;
closedAt?: string | null;
expectedCloseAt?: string | null;
personId?: string | null;
companyId?: string | null;
@@ -990,6 +1016,80 @@ export interface UpdateDealRequest {
lineItems?: DealLineItemInput[];
}
/** ستون‌های اکسل معامله — هم‌ترتیب با خروجی معاملات دیدار */
export const DEAL_EXCEL_COLUMNS: Array<{ header: string; key: string; width?: number }> = [
{ header: "_type", key: "_type", width: 8 },
{ header: "کد دیدار معامله", key: "didarId", width: 14 },
{ header: "کد دستی معامله", key: "code", width: 14 },
{ header: "عنوان معامله", key: "title", width: 30 },
{ header: "ارزش معامله", key: "amount", width: 16 },
{ header: "ارز معامله", key: "currency", width: 10 },
{ header: "توضیحات معامله", key: "notes", width: 32 },
{ header: "وضعیت معامله", key: "status", width: 12 },
{ header: "تاریخ انجام معامله", key: "closedAt", width: 14 },
{ header: "تاریخ ایجاد معامله", key: "createdAt", width: 14 },
{ header: "تاریخ احتمالی انجام معامله", key: "expectedCloseAt", width: 16 },
{ header: "مسئول معامله", key: "ownerName", width: 18 },
{ header: "ثبت کننده معامله", key: "creatorName", width: 18 },
{ header: "احتمال موفقیت معامله", key: "probability", width: 12 },
{ header: "دلیل شکست معامله", key: "lostReason", width: 18 },
{ header: "یادداشت شکست معامله", key: "lostNote", width: 24 },
{ header: "مجوز مشاهده معامله", key: "visibility", width: 18 },
{ header: "شیوه آشنایی معامله", key: "source", width: 16 },
{ header: "معرف معامله", key: "referrer", width: 16 },
{ header: "شیوه آشنایی دلخواه", key: "sourceDetail", width: 16 },
{ header: "برچسب", key: "tags", width: 16 },
{ header: "کاریز معامله", key: "pipelineName", width: 20 },
{ header: "مرحله کاریز معامله", key: "stageName", width: 20 },
{ header: "نام شخص معامله", key: "personFirstName", width: 16 },
{ header: "نام خانوادگی شخص معامله", key: "personName", width: 22 },
{ header: "کد دیدار شخص معامله", key: "personCode", width: 14 },
{ header: "موبایل شخص معامله", key: "personMobile", width: 14 },
{ header: "شرکت معامله", key: "companyName", width: 20 },
{ header: "کد دیدار شرکت معامله", key: "companyCode", width: 14 },
{ header: "شماره تلفن شرکت", key: "companyPhone", width: 14 },
{ header: "عنوان محصول", key: "productName", width: 20 },
{ header: "کد محصول", key: "productCode", width: 12 },
{ header: "دسته بندی محصول", key: "productCategory", width: 14 },
{ header: "تعداد محصول", key: "productQty", width: 10 },
{ header: "قیمت", key: "productPrice", width: 14 },
{ header: "واحد قیمت محصول", key: "productCurrency", width: 12 },
{ header: "میزان تخفیف محصول", key: "productDiscount", width: 12 },
{ header: "مبلغ نهایی", key: "productTotal", width: 14 },
{ header: "گروه محصول", key: "productGroup", width: 14 },
];
/** کلید ستون‌های ناشناخته اکسل که به‌عنوان فیلد سفارشی ذخیره می‌شوند: cf:<عنوان ستون> */
export const EXCEL_CUSTOM_FIELD_PREFIX = "cf:";
export function compactExcelHeader(raw: string): string {
return raw
.trim()
.toLowerCase()
.replace(/[_-]+/g, "")
.replace(/\u200c/g, "")
.replace(/\s+/g, "")
.replace(/[()]/g, "");
}
export const DEAL_EXCEL_ALIASES: Record<string, string> = {
...Object.fromEntries(DEAL_EXCEL_COLUMNS.map((c) => [compactExcelHeader(c.header), c.key])),
type: "_type",
عنوان: "title",
مبلغمعامله: "amount",
مبلغ: "amount",
ارز: "currency",
وضعیت: "status",
توضیحات: "notes",
تاریخثبتمعامله: "createdAt",
کددیدارشخص: "personCode",
نامشرکتمعامله: "companyName",
شرکت: "companyName",
منبعمعامله: "source",
منبع: "source",
کاریز: "pipelineName",
مرحله: "stageName",
};
/** فیلتر ذخیره‌شدهٔ لیست اشخاص */
export interface PeopleViewFilters {
q?: string;