diff --git a/apps/web/src/components/person-assets/PersonAssetsPanel.vue b/apps/web/src/components/person-assets/PersonAssetsPanel.vue index a5eb7f1..8a57b8b 100644 --- a/apps/web/src/components/person-assets/PersonAssetsPanel.vue +++ b/apps/web/src/components/person-assets/PersonAssetsPanel.vue @@ -555,7 +555,7 @@ onMounted(async () => { {{ formatMandehAmount(v.amount, v.unit) }} {{ v.unit }} - {{ v.status === 'بس' ? 'بد' : 'بس' }} + {{ Number(v.amount) >= 0 ? 'بد' : 'بس' }} | diff --git a/packages/shared/src/index.ts b/packages/shared/src/index.ts index 9010ea2..c7454c3 100644 --- a/packages/shared/src/index.ts +++ b/packages/shared/src/index.ts @@ -3,13 +3,13 @@ export type UserRole = "owner" | "admin" | "sales" | "support"; export const USER_ROLES: UserRole[] = ["owner", "admin", "sales", "support"]; export const USER_ROLE_LABELS: Record = { - owner: "مالک", - admin: "مدیر", - sales: "فروش", - support: "پشتیبانی", + owner: "مالک", + admin: "مدیر", + sales: "فروش", + support: "پشتیبانی", }; -/** تنظیمات سازمانی و مدیریت کاربران */ +/** تنظیمات سازمانی و مدیریت کاربران */ export function canManageSettings(role: UserRole | string | null | undefined): boolean { return role === "owner" || role === "admin"; } @@ -18,12 +18,12 @@ export function canManageUsers(role: UserRole | string | null | undefined): bool return role === "owner" || role === "admin"; } -/** مشاهده همه پرونده‌های سازمان (نه فقط مالکیت خود) */ +/** مشاهده همه پرونده‌های سازمان (نه فقط مالکیت خود) */ export function canViewAllRecords(role: UserRole | string | null | undefined): boolean { return role === "owner" || role === "admin"; } -/** تغییر مالک پرونده */ +/** تغییر مالک پرونده */ export function canReassignRecords(role: UserRole | string | null | undefined): boolean { return role === "owner" || role === "admin"; } @@ -37,10 +37,10 @@ export interface AuthUserDto { organizationId: string; organizationName?: string; hasAvatar?: boolean; - /** مالک محیط فعلی — اشتراک متعلق به مالک است نه عضو زیرمجموعه */ + /** مالک محیط فعلی — اشتراک متعلق به مالک است نه عضو زیرمجموعه */ isOrgOwner?: boolean; enabledModules?: OrgModuleKey[]; - /** خلاصه اشتراک مالک محیط (برای اعضا فقط جهت نمایش/گیت ورود) */ + /** خلاصه اشتراک مالک محیط (برای اعضا فقط جهت نمایش/گیت ورود) */ subscription?: SubscriptionSummaryDto | null; } @@ -64,15 +64,15 @@ export const BILLING_PLAN_CODES: BillingPlanCode[] = [ ]; export const BILLING_PLAN_LABELS: Record = { - trial: "دمو Û±Ûµ روزه", - monthly: "ماهانه", - quarterly: "سه‌ماهه", - semiannual: "شش‌ماهه", - yearly: "یکساله", - custom: "سفارشی", + trial: "دمو Û±Ûµ روزه", + monthly: "ماهانه", + quarterly: "سه‌ماهه", + semiannual: "شش‌ماهه", + yearly: "یکساله", + custom: "سفارشی", }; -/** مدت پیش‌فرض پلن‌ها (روز) — custom ندارد */ +/** مدت پیش‌فرض پلن‌ها (روز) — custom ندارد */ export const BILLING_PLAN_DAYS: Record, number> = { trial: 15, monthly: 30, @@ -164,49 +164,49 @@ export const ORG_MODULE_KEYS: OrgModuleKey[] = [ ]; export const ORG_MODULE_LABELS: Record = { - customers: "مشتریان", - pipeline: "کاریز فروش", - products: "محصولات", - invoices: "فاکتورها", - quotes: "پیش‌فاکتورها", - commissions: "پورسانت", - sales_forecast: "هدف و پیش‌بینی", - activities: "فعالیت‌ها", - tickets: "تیکت‌ها", - workflow_automations: "اتوماسیون گردش کار", - message_automations: "اتوماسیون پیامک", - lead_forms: "فرم‌ساز سرنخ", - leads: "مدیریت لیدها", - project_boards: "کاریز پروژه", - inventory: "انبار", - cheques: "چک‌ها", - attachments: "پیوست‌ها", - loyalty: "باشگاه مشتریان", - reports: "گزارش‌ها", - notes: "یادداشت‌ها", - tahesab: "ته‌حساب", - custom_fields: "فیلدهای سفارشی", - currencies: "ارزها", - team_settings: "تیم و تنظیمات سازمان", + customers: "مشتریان", + pipeline: "کاریز فروش", + products: "محصولات", + invoices: "فاکتورها", + quotes: "پیش‌فاکتورها", + commissions: "پورسانت", + sales_forecast: "هدف و پیش‌بینی", + activities: "فعالیت‌ها", + tickets: "تیکت‌ها", + workflow_automations: "اتوماسیون گردش کار", + message_automations: "اتوماسیون پیامک", + lead_forms: "فرم‌ساز سرنخ", + leads: "مدیریت لیدها", + project_boards: "کاریز پروژه", + inventory: "انبار", + cheques: "چک‌ها", + attachments: "پیوست‌ها", + loyalty: "باشگاه مشتریان", + reports: "گزارش‌ها", + notes: "یادداشت‌ها", + tahesab: "ته‌حساب", + custom_fields: "فیلدهای سفارشی", + currencies: "ارزها", + team_settings: "تیم و تنظیمات سازمان", faq: "FAQ", - audit_logs: "لاگ فعالیت کاربران", - saved_views: "فیلترهای ذخیره‌شده", - public_api: "API و وب‌هوک", - sms_campaigns: "پیامک گروهی", - teams: "تیم‌ها و سطح دسترسی به پرونده‌ها", - woocommerce: "ووکامرس", - voip: "تلفن سازمانی", - reservations: "رزرو و نوبت‌دهی", + audit_logs: "لاگ فعالیت کاربران", + saved_views: "فیلترهای ذخیره‌شده", + public_api: "API و وب‌هوک", + sms_campaigns: "پیامک گروهی", + teams: "تیم‌ها و سطح دسترسی به پرونده‌ها", + woocommerce: "ووکامرس", + voip: "تلفن سازمانی", + reservations: "رزرو و نوبت‌دهی", }; export const ORG_MODULE_GROUPS: Array<{ title: string; keys: OrgModuleKey[]; }> = [ - { title: "مشتریان", keys: ["customers"] }, - { title: "لیدها", keys: ["leads", "lead_forms"] }, + { title: "مشتریان", keys: ["customers"] }, + { title: "لیدها", keys: ["leads", "lead_forms"] }, { - title: "فروش", + title: "فروش", keys: [ "pipeline", "products", @@ -216,10 +216,10 @@ export const ORG_MODULE_GROUPS: Array<{ "sales_forecast", ], }, - { title: "فعالیت‌ها", keys: ["activities", "notes"] }, - { title: "پشتیبانی", keys: ["tickets", "faq"] }, + { title: "فعالیت‌ها", keys: ["activities", "notes"] }, + { title: "پشتیبانی", keys: ["tickets", "faq"] }, { - title: "اتوماسیون", + title: "اتوماسیون", keys: [ "workflow_automations", "message_automations", @@ -227,7 +227,7 @@ export const ORG_MODULE_GROUPS: Array<{ ], }, { - title: "ابزارها", + title: "ابزارها", keys: [ "project_boards", "inventory", @@ -242,7 +242,7 @@ export const ORG_MODULE_GROUPS: Array<{ ], }, { - title: "تنظیمات", + title: "تنظیمات", keys: [ "team_settings", "teams", @@ -312,7 +312,7 @@ export interface OrgUserDto { lastLoginAt?: string | null; hasAvatar?: boolean; commissionPercent?: number; - /** own = فقط خود | team = هم‌تیمی‌ها | org = کل سازمان */ + /** own = فقط خود | team = هم‌تیمی‌ها | org = کل سازمان */ dataVisibility?: DataVisibility; createdAt: string; } @@ -322,9 +322,9 @@ export type DataVisibility = "own" | "team" | "org"; export const DATA_VISIBILITIES: DataVisibility[] = ["own", "team", "org"]; export const DATA_VISIBILITY_LABELS: Record = { - own: "فقط پرونده‌های خود", - team: "تیم‌های عضو", - org: "کل سازمان", + own: "فقط پرونده‌های خود", + team: "تیم‌های عضو", + org: "کل سازمان", }; export interface UpdateUserVisibilityRequest { @@ -345,14 +345,14 @@ export const ROLE_PERMISSION_ITEMS: Array<{ key: RolePermissionKey; label: string; }> = [ - { key: "customers", label: "مشتریان" }, - { key: "sales", label: "فروش و معاملات" }, - { key: "billing", label: "پیش‌فاکتورها و فاکتورها" }, - { key: "products", label: "محصولات و خدمات" }, - { key: "activities", label: "فعالیت‌ها" }, - { key: "notes", label: "یادداشت‌ها" }, - { key: "reports", label: "گزارش‌ها" }, - { key: "audit", label: "لاگ فعالیت کاربران" }, + { key: "customers", label: "مشتریان" }, + { key: "sales", label: "فروش و معاملات" }, + { key: "billing", label: "پیش‌فاکتورها و فاکتورها" }, + { key: "products", label: "محصولات و خدمات" }, + { key: "activities", label: "فعالیت‌ها" }, + { key: "notes", label: "یادداشت‌ها" }, + { key: "reports", label: "گزارش‌ها" }, + { key: "audit", label: "لاگ فعالیت کاربران" }, ]; export interface OrgRoleMemberDto { @@ -422,7 +422,7 @@ export interface ApiErrorBody { } export interface LoginRequest { - /** ایمیل یا شماره موبایل */ + /** ایمیل یا شماره موبایل */ identifier: string; password: string; } @@ -444,7 +444,7 @@ export interface LoginChallengeResponse { channel: 'email' | 'mobile'; expiresInSeconds: number; maskedDestination?: string; - /** فقط در محیط توسعه / AUTH_RETURN_OTP */ + /** فقط در محیط توسعه / AUTH_RETURN_OTP */ devCode?: string; } @@ -453,7 +453,7 @@ export interface RegisterChallengeResponse { expiresInSeconds: number; maskedEmail?: string; maskedMobile?: string; - /** وقتی سرویس ایمیل خاموش است false — فقط OTP موبایل لازم است */ + /** وقتی سرویس ایمیل خاموش است false — فقط OTP موبایل لازم است */ emailOtpRequired?: boolean; devEmailCode?: string; devMobileCode?: string; @@ -531,7 +531,7 @@ export interface UpdateOrganizationRequest { businessField?: BusinessField; } -/** زمینه فعالیت سازمان — هم‌تراز صنایع دیدار */ +/** زمینه فعالیت سازمان — هم‌تراز صنایع دیدار */ export const BUSINESS_FIELDS = [ "education", "beauty", @@ -558,26 +558,26 @@ export const BUSINESS_FIELDS = [ export type BusinessField = (typeof BUSINESS_FIELDS)[number]; export const BUSINESS_FIELD_LABELS: Record = { - education: "آموزشگاه و مؤسسات آموزشی", - beauty: "کلینیک زیبایی و آرایشگاه", - real_estate: "املاک و مشاورین مسکن", - construction: "صنعت ساختمان", - advertising: "تبلیغات و مشاوره کسب‌وکار", - insurance: "بیمه", - consulting: "شرکت‌های مشاور", - startup: "استارتاپ و کسب‌وکار آنلاین", - medical_devices: "تجهیزات پزشکی", - travel: "گردشگری و مهاجرت", - contractor: "پیمانکاری و پروژه‌ای", - trading: "بازرگانی", - manufacturing: "تولیدی و صنعتی", - personal: "کسب‌وکار شخصی و خانگی", - tech: "نرم‌افزار و سخت‌افزار", - legal: "وکلا و مشاورین حقوقی", - repair: "خدمات و تعمیرات", - retail: "خرده‌فروشی", - jewelry: "طلا و جواهر", - other: "سایر", + education: "آموزشگاه و مؤسسات آموزشی", + beauty: "کلینیک زیبایی و آرایشگاه", + real_estate: "املاک و مشاورین مسکن", + construction: "صنعت ساختمان", + advertising: "تبلیغات و مشاوره کسب‌وکار", + insurance: "بیمه", + consulting: "شرکت‌های مشاور", + startup: "استارتاپ و کسب‌وکار آنلاین", + medical_devices: "تجهیزات پزشکی", + travel: "گردشگری و مهاجرت", + contractor: "پیمانکاری و پروژه‌ای", + trading: "بازرگانی", + manufacturing: "تولیدی و صنعتی", + personal: "کسب‌وکار شخصی و خانگی", + tech: "نرم‌افزار و سخت‌افزار", + legal: "وکلا و مشاورین حقوقی", + repair: "خدمات و تعمیرات", + retail: "خرده‌فروشی", + jewelry: "طلا و جواهر", + other: "سایر", }; export function isBusinessField(value: string): value is BusinessField { @@ -593,7 +593,7 @@ export interface ExchangeRateDto { export interface UpdateOrgCurrenciesRequest { baseCurrency?: string; enabledCurrencies?: string[]; - /** نرخ‌ها نسبت به ارز پایه؛ ارز پایه نیازی به نرخ ندارد */ + /** نرخ‌ها نسبت به ارز پایه؛ ارز پایه نیازی به نرخ ندارد */ rates?: Array<{ currency: string; rateToBase: number }>; } @@ -602,12 +602,12 @@ export const CURRENCY_CATALOG: Array<{ labelFa: string; suffix: string; }> = [ - { code: "IRR", labelFa: "ریال ایران", suffix: "ریال" }, - { code: "USD", labelFa: "دلار آمریکا", suffix: "دلار" }, - { code: "EUR", labelFa: "یورو", suffix: "یورو" }, - { code: "AED", labelFa: "درهم امارات", suffix: "درهم" }, - { code: "TRY", labelFa: "لیر ترکیه", suffix: "لیر" }, - { code: "GBP", labelFa: "پوند انگلیس", suffix: "پوند" }, + { code: "IRR", labelFa: "ریال ایران", suffix: "ریال" }, + { code: "USD", labelFa: "دلار آمریکا", suffix: "دلار" }, + { code: "EUR", labelFa: "یورو", suffix: "یورو" }, + { code: "AED", labelFa: "درهم امارات", suffix: "درهم" }, + { code: "TRY", labelFa: "لیر ترکیه", suffix: "لیر" }, + { code: "GBP", labelFa: "پوند انگلیس", suffix: "پوند" }, ]; export function currencySuffix(code: string): string { @@ -677,10 +677,10 @@ export const PERSON_MOODS = ["newcomer", "happy", "unhappy", "special"] as const export type PersonMood = (typeof PERSON_MOODS)[number]; export const PERSON_MOOD_LABELS: Record = { - newcomer: "مشتری تازه وارد", - happy: "مشتری خوشحال", - unhappy: "مشتری ناراضی", - special: "مشتری خاص", + newcomer: "مشتری تازه وارد", + happy: "مشتری خوشحال", + unhappy: "مشتری ناراضی", + special: "مشتری خاص", }; export interface PersonDto { @@ -777,7 +777,7 @@ export interface DealDto { person: PersonSummaryDto | null; company: CompanySummaryDto | null; owner: UserSummaryDto | null; - /** مسئولان مشترک معامله (علاوه بر مالک اصلی) */ + /** مسئولان مشترک معامله (علاوه بر مالک اصلی) */ assignees: UserSummaryDto[]; lineItems: DealLineItemDto[]; createdAt: string; @@ -849,7 +849,7 @@ export interface UpdateDealRequest { lineItems?: DealLineItemInput[]; } -/** فیلتر ذخیره‌شدهٔ لیست اشخاص */ +/** فیلتر ذخیره‌شدهٔ لیست اشخاص */ export interface PeopleViewFilters { q?: string; sort?: string; @@ -857,7 +857,7 @@ export interface PeopleViewFilters { page?: number; } -/** فیلتر ذخیره‌شدهٔ کاریز / معاملات */ +/** فیلتر ذخیره‌شدهٔ کاریز / معاملات */ export interface DealsViewFilters { q?: string; amountMin?: string; @@ -1014,7 +1014,7 @@ export interface NoteDto { title: string | null; body: string; noteType: NoteType | string; - /** team = تیمی | personal = فقط نویسنده */ + /** team = تیمی | personal = فقط نویسنده */ visibility: NoteVisibility; pinned: boolean; color: string | null; @@ -1029,7 +1029,7 @@ export interface NoteDto { activity: { id: string; title: string } | null; author: UserSummaryDto | null; attachments: NoteAttachmentDto[]; - /** تعداد نسخه‌های قبلی (برای نمایش دکمه تاریخچه) */ + /** تعداد نسخه‌های قبلی (برای نمایش دکمه تاریخچه) */ revisionCount?: number; createdAt: string; updatedAt: string; @@ -1040,8 +1040,8 @@ export type NoteVisibility = "team" | "personal"; export const NOTE_VISIBILITIES: NoteVisibility[] = ["team", "personal"]; export const NOTE_VISIBILITY_LABELS: Record = { - team: "تیمی", - personal: "شخصی (فقط من)", + team: "تیمی", + personal: "شخصی (فقط من)", }; export interface NoteRevisionDto { @@ -1865,7 +1865,7 @@ export interface CreateSalesGoalRequest { probability?: number | null; currency?: string; notes?: string; - /** فقط مالک/مدیر؛ در غیر این صورت هدف برای خود کاربر */ + /** فقط مالک/مدیر؛ در غیر این صورت هدف برای خود کاربر */ userId?: string | null; } @@ -1896,13 +1896,13 @@ export interface SalesForecastDto { periodStart: string; periodEnd: string; currency: string; - /** مجموع اهداف هم‌پوشان با بازه */ + /** مجموع اهداف هم‌پوشان با بازه */ targetAmount: number; - /** معاملات برنده‌شده در بازه */ + /** معاملات برنده‌شده در بازه */ wonAmount: number; - /** معاملات باز فعلی */ + /** معاملات باز فعلی */ openPipelineAmount: number; - /** پیش‌بینی: تحقق + کاریز باز × میانگین احتمال */ + /** پیش‌بینی: تحقق + کاریز باز × میانگین احتمال */ forecastAmount: number; progressPercent: number | null; openDealsCount: number; @@ -1910,7 +1910,7 @@ export interface SalesForecastDto { goals: SalesGoalDto[]; kpis: SalesForecastKpiDto[]; newCustomersCount: number; - /** معاملات ایجادشده در بازه */ + /** معاملات ایجادشده در بازه */ newDealsCount: number; } @@ -2011,7 +2011,7 @@ export interface UpdateFaqArticleRequest { position?: number; } -/** ساعات مهلت پاسخ اول بر اساس اولویت */ +/** ساعات مهلت پاسخ اول بر اساس اولویت */ export const TICKET_SLA_HOURS: Record = { urgent: 4, high: 8, @@ -2019,7 +2019,7 @@ export const TICKET_SLA_HOURS: Record = { low: 48, }; -/* ——— پرتال مشتری (OTP) ——— */ +/* ——— پرتال مشتری (OTP) ——— */ export interface PortalOrgInfoDto { name: string; @@ -2032,7 +2032,7 @@ export interface PortalRequestOtpRequest { export interface PortalRequestOtpResponse { ok: true; - /** فقط در حالت توسعه / دمو وقتی SMS واقعی وصل نیست */ + /** فقط در حالت توسعه / دمو وقتی SMS واقعی وصل نیست */ devCode?: string; expiresInSeconds: number; } @@ -2089,7 +2089,7 @@ export interface PortalTicketDto { updatedAt: string; } -/* ——— گزارشات و داشبورد ——— */ +/* ——— گزارشات و داشبورد ——— */ export interface ReportsKpiDto { key: string; @@ -2127,7 +2127,7 @@ export interface ReportsTeamRowDto { activitiesDone: number; } -/** گونه‌های drill-down گزارش عمیق (فاز Û± BI) */ +/** گونه‌های drill-down گزارش عمیق (فاز Û± BI) */ export type ReportsDrillKind = | "stage_open" | "team_won" @@ -2152,25 +2152,25 @@ export interface ReportsFunnelStageDto { pipelineName: string; count: number; amount: number; - /** درصد تبدیل نسبت به مرحله قبل همان کاریز؛ null برای اولین مرحله */ + /** درصد تبدیل نسبت به مرحله قبل همان کاریز؛ null برای اولین مرحله */ conversionFromPrevPercent: number | null; - /** سهم از کل معاملات باز همان کاریز */ + /** سهم از کل معاملات باز همان کاریز */ shareOfPipelinePercent: number; } -/** یک ردیف نرخ تبدیل (ورودی → موفق) مثل دیدار */ +/** یک ردیف نرخ تبدیل (ورودی → موفق) مثل دیدار */ export interface ReportsConversionRateRowDto { key: string; label: string; incomingCount: number; wonCount: number; - /** درصد؛ اگر ورودی صفر باشد Û° */ + /** درصد؛ اگر ورودی صفر باشد Û° */ conversionPercent: number; } /** - * نرخ تبدیل به سبک دیدار: - * از معاملات تازه‌ساخته‌شده در بازه، چند درصد الان برنده شده‌اند. + * نرخ تبدیل به سبک دیدار: + * از معاملات تازه‌ساخته‌شده در بازه، چند درصد الان برنده شده‌اند. */ export interface ReportsConversionRateDto { incomingCount: number; @@ -2192,7 +2192,7 @@ export interface ReportsPeriodCompareRowDto { current: number; previous: number; changePercent: number | null; - /** اگر قابل کلیک برای لیست پرونده باشد */ + /** اگر قابل کلیک برای لیست پرونده باشد */ drillKind?: ReportsDrillKind; } @@ -2249,9 +2249,9 @@ export interface ReportsDashboardDto { winRate: number; }; funnel: ReportsFunnelStageDto[]; - /** نرخ تبدیل ورودی→موفق (سبک دیدار) */ + /** نرخ تبدیل ورودی→موفق (سبک دیدار) */ conversionRate: ReportsConversionRateDto; - /** مقایسه صریح بازه فعلی با دوره قبل هم‌طول */ + /** مقایسه صریح بازه فعلی با دوره قبل هم‌طول */ periodCompare: ReportsPeriodCompareRowDto[]; tickets: { open: number; @@ -2309,7 +2309,7 @@ export interface HomeDashboardDto { topCustomers: HomeDashboardTopCustomerDto[]; } -/** برد پروژه / کاریز کارت */ +/** برد پروژه / کاریز کارت */ export interface ProjectBoardStageDto { id: string; name: string; @@ -2373,7 +2373,7 @@ export interface MoveProjectCardRequest { position?: number; } -/** باشگاه مشتریان */ +/** باشگاه مشتریان */ export interface LoyaltyTierDto { id: string; name: string; @@ -2476,7 +2476,7 @@ export interface RedeemLoyaltyRewardRequest { personId: string; } -/** اتوماسیون اگر/آنگاه */ +/** اتوماسیون اگر/آنگاه */ export type AutomationTrigger = | "person_created" | "lead_submitted" @@ -2495,23 +2495,23 @@ export type AutomationAction = | "add_loyalty_points"; export const AUTOMATION_TRIGGER_LABELS: Record = { - person_created: "مخاطب جدید ساخته شد", - lead_submitted: "فرم سرنخ ارسال شد", - deal_created: "معامله جدید ساخته شد", - deal_stage_changed: "مرحله معامله عوض شد", - deal_won: "معامله برنده شد", - deal_lost: "معامله باخت", - ticket_created: "تیکت جدید ساخته شد", - ticket_resolved: "تیکت حل شد", - invoice_issued: "فاکتور صادر شد", - invoice_paid: "پرداخت روی فاکتور ثبت شد", - activity_done: "فعالیت تمام شد", + person_created: "مخاطب جدید ساخته شد", + lead_submitted: "فرم سرنخ ارسال شد", + deal_created: "معامله جدید ساخته شد", + deal_stage_changed: "مرحله معامله عوض شد", + deal_won: "معامله برنده شد", + deal_lost: "معامله باخت", + ticket_created: "تیکت جدید ساخته شد", + ticket_resolved: "تیکت حل شد", + invoice_issued: "فاکتور صادر شد", + invoice_paid: "پرداخت روی فاکتور ثبت شد", + activity_done: "فعالیت تمام شد", }; export const AUTOMATION_ACTION_LABELS: Record = { - create_activity: "ساخت فعالیت", - create_notification: "ارسال اعلان", - add_loyalty_points: "افزودن امتیاز باشگاه", + create_activity: "ساخت فعالیت", + create_notification: "ارسال اعلان", + add_loyalty_points: "افزودن امتیاز باشگاه", }; export const MAX_AUTOMATION_STEPS = 8; @@ -2540,14 +2540,14 @@ export const AUTOMATION_TRIGGER_GROUPS: { label: string; items: AutomationTrigger[]; }[] = [ - { label: "مخاطب", items: ["person_created", "lead_submitted"] }, + { label: "مخاطب", items: ["person_created", "lead_submitted"] }, { - label: "معامله", + label: "معامله", items: ["deal_created", "deal_stage_changed", "deal_won", "deal_lost"], }, - { label: "تیکت", items: ["ticket_created", "ticket_resolved"] }, - { label: "فعالیت", items: ["activity_done"] }, - { label: "مالی", items: ["invoice_issued", "invoice_paid"] }, + { label: "تیکت", items: ["ticket_created", "ticket_resolved"] }, + { label: "فعالیت", items: ["activity_done"] }, + { label: "مالی", items: ["invoice_issued", "invoice_paid"] }, ]; export type AutomationStepKind = "action" | "condition"; @@ -2573,31 +2573,31 @@ export const AUTOMATION_CONDITION_FIELD_LABELS: Record< AutomationConditionField, string > = { - deal_amount: "مبلغ معامله", - has_person: "مخاطب دارد", - has_company: "شرکت دارد", - ticket_priority: "اولویت تیکت", + deal_amount: "مبلغ معامله", + has_person: "مخاطب دارد", + has_company: "شرکت دارد", + ticket_priority: "اولویت تیکت", }; export const AUTOMATION_CONDITION_OP_LABELS: Record< AutomationConditionOp, string > = { - gte: "بزرگ‌تر یا مساوی", - lte: "کوچک‌تر یا مساوی", - eq: "مساوی", - neq: "نامساوی", - is_set: "دارد", - is_empty: "ندارد", + gte: "بزرگ‌تر یا مساوی", + lte: "کوچک‌تر یا مساوی", + eq: "مساوی", + neq: "نامساوی", + is_set: "دارد", + is_empty: "ندارد", }; export const AUTOMATION_NOTIFY_CHANNEL_LABELS: Record< AutomationNotifyChannel, string > = { - app: "ناتیفیکیشن داخلی", - sms: "پیامک", - both: "هر دو", + app: "ناتیفیکیشن داخلی", + sms: "پیامک", + both: "هر دو", }; export const AUTOMATION_NOTIFY_CHANNELS = [ @@ -2660,7 +2660,7 @@ export interface AutomationRuleConfig { notifyTarget?: AutomationNotifyTarget; activityType?: "call" | "meeting" | "task" | "note"; points?: number; - /** زنجیرهٔ اعمال؛ اگر خالی باشد همان action تکی استفاده می‌شود */ + /** زنجیرهٔ اعمال؛ اگر خالی باشد همان action تکی استفاده می‌شود */ steps?: AutomationStep[]; } @@ -2756,7 +2756,7 @@ export function automationStepToConfig(step: AutomationStep): AutomationRuleConf }; } -// —— ته‌حساب / حسابداری —— +// —— ته‌حساب / حسابداری —— export const TAHSAB_SANAD_TYPES = [ "buy_sale_gold", @@ -2769,11 +2769,11 @@ export const TAHSAB_SANAD_TYPES = [ export type TahesabSanadType = (typeof TAHSAB_SANAD_TYPES)[number]; export const TAHSAB_SANAD_LABELS: Record = { - buy_sale_gold: "خرید/فروش آبشده", - buy_sale_sekeh: "خرید/فروش سکه", - talab_bedehi: "طلب/بدهی", - vkh_gold: "واریز/خروج طلا", - vkh_bank: "واریز/خروج بانکی", + buy_sale_gold: "خرید/فروش آبشده", + buy_sale_sekeh: "خرید/فروش سکه", + talab_bedehi: "طلب/بدهی", + vkh_gold: "واریز/خروج طلا", + vkh_bank: "واریز/خروج بانکی", }; export interface TahesabConnectionDto { @@ -2822,7 +2822,8 @@ export interface PersonAccountingLinkDto { export interface MandehValueDto { amount: string | number; unit: string; - status: "بس" | "بد"; + /** بس = بستانکار | بد = بدهکار */ + status: "بس" | "بد" | string; } export interface MandehDetailItemDto { @@ -2843,7 +2844,7 @@ export interface PersonAssetsDto { fetchedAt: string; } -// —— پیام خودکار (جدا از اتوماسیون گردش کار) —— +// —— پیام خودکار (جدا از اتوماسیون گردش کار) —— export type MessageAutomationTrigger = | "person_created" @@ -2887,37 +2888,37 @@ export const MESSAGE_AUTOMATION_TRIGGER_LABELS: Record< MessageAutomationTrigger, string > = { - person_created: "مخاطب جدید ساخته شد", - lead_submitted: "فرم سرنخ ارسال شد", - deal_created: "معامله جدید ساخته شد", - deal_stage_changed: "مرحله معامله عوض شد", - deal_won: "معامله برنده شد", - deal_lost: "معامله باخت", - ticket_created: "تیکت جدید ساخته شد", - ticket_resolved: "تیکت حل شد", - invoice_issued: "فاکتور صادر شد", - invoice_paid: "پرداخت روی فاکتور ثبت شد", - activity_created: "فعالیت ثبت شد", - activity_done: "فعالیت تمام شد", + person_created: "مخاطب جدید ساخته شد", + lead_submitted: "فرم سرنخ ارسال شد", + deal_created: "معامله جدید ساخته شد", + deal_stage_changed: "مرحله معامله عوض شد", + deal_won: "معامله برنده شد", + deal_lost: "معامله باخت", + ticket_created: "تیکت جدید ساخته شد", + ticket_resolved: "تیکت حل شد", + invoice_issued: "فاکتور صادر شد", + invoice_paid: "پرداخت روی فاکتور ثبت شد", + activity_created: "فعالیت ثبت شد", + activity_done: "فعالیت تمام شد", }; export const MESSAGE_AUTOMATION_UNIT_LABELS: Record< MessageAutomationDelayUnit, string > = { - minutes: "دقیقه", - hours: "ساعت", - days: "روز", - weeks: "هفته", - months: "ماه", + minutes: "دقیقه", + hours: "ساعت", + days: "روز", + weeks: "هفته", + months: "ماه", }; export const MESSAGE_AUTOMATION_FIELDS = [ - { token: "{نام}", label: "نام مشتری" }, - { token: "{شماره}", label: "شماره موبایل" }, - { token: "{تاریخ}", label: "تاریخ ارسال" }, - { token: "{عنوان}", label: "عنوان رکورد" }, - { token: "{شرکت}", label: "نام شرکت" }, + { token: "{نام}", label: "نام مشتری" }, + { token: "{شماره}", label: "شماره موبایل" }, + { token: "{تاریخ}", label: "تاریخ ارسال" }, + { token: "{عنوان}", label: "عنوان رکورد" }, + { token: "{شرکت}", label: "نام شرکت" }, ] as const; export const MESSAGE_AUTOMATION_SMS_SEGMENT = 70; @@ -2926,18 +2927,18 @@ export const MESSAGE_AUTOMATION_CHANNEL_LABELS: Record< MessageAutomationChannel, string > = { - app: "ناتیف داخل برنامه", - sms: "پیامک", - both: "پیامک و ناتیف", + app: "ناتیف داخل برنامه", + sms: "پیامک", + both: "پیامک و ناتیف", }; export const MESSAGE_AUTOMATION_TARGET_LABELS: Record< MessageAutomationTarget, string > = { - staff: "مسئول پرونده", - person: "مشتری", - both: "مشتری و مسئول", + staff: "مسئول پرونده", + person: "مشتری", + both: "مشتری و مسئول", }; export interface MessageAutomationRuleDto { @@ -3064,7 +3065,7 @@ export interface PlatformUserDto { lastLoginAt?: string | null; createdAt: string; memberships: PlatformUserMembershipDto[]; - /** فقط اگر حداقل یک عضویت مالک فعال دارد */ + /** فقط اگر حداقل یک عضویت مالک فعال دارد */ isBillingOwner?: boolean; billing?: BillingAccountDto | null; } @@ -3101,7 +3102,7 @@ export { brand, APP_NAME, APP_NAME_FA, brandSuggestionFa } from "./brand"; export type { Brand } from "./brand"; export const API_PREFIX = "api"; -/* ——— لاگ فعالیت کاربران ——— */ +/* ——— لاگ فعالیت کاربران ——— */ export interface AuditLogDto { id: string; @@ -3123,7 +3124,7 @@ export interface AuditLogListResponse { limit: number; } -/* ——— فیلترهای ذخیره‌شده ——— */ +/* ——— فیلترهای ذخیره‌شده ——— */ export type SavedViewScope = | "deals" @@ -3142,7 +3143,7 @@ export const SAVED_VIEW_SCOPES: SavedViewScope[] = [ "reports", ]; -/** فیلترهای ذخیره‌شدهٔ صفحه گزارشات */ +/** فیلترهای ذخیره‌شدهٔ صفحه گزارشات */ export interface ReportsViewFilters { /** today | week | month | quarter | year | custom */ period: string; @@ -3158,7 +3159,7 @@ export interface ReportsViewFilters { }; } -/** متریک‌های گزارش‌ساز ساده */ +/** متریک‌های گزارش‌ساز ساده */ export type ReportsBuilderMetric = | "won_amount" | "won_count" @@ -3186,18 +3187,18 @@ export const REPORTS_BUILDER_METRIC_LABELS: Record< ReportsBuilderMetric, string > = { - won_amount: "مبلغ معاملات برنده", - won_count: "تعداد معاملات برنده", - lost_count: "تعداد معاملات باخته", - open_count: "تعداد معاملات باز", - open_amount: "مبلغ معاملات باز", - activities_done: "فعالیت انجام‌شده", - people_created: "مشتریان جدید", - invoice_amount: "مبلغ فاکتور", - invoice_count: "تعداد فاکتور", + won_amount: "مبلغ معاملات برنده", + won_count: "تعداد معاملات برنده", + lost_count: "تعداد معاملات باخته", + open_count: "تعداد معاملات باز", + open_amount: "مبلغ معاملات باز", + activities_done: "فعالیت انجام‌شده", + people_created: "مشتریان جدید", + invoice_amount: "مبلغ فاکتور", + invoice_count: "تعداد فاکتور", }; -/** ابعاد گروه‌بندی گزارش‌ساز */ +/** ابعاد گروه‌بندی گزارش‌ساز */ export type ReportsBuilderDimension = | "none" | "owner" @@ -3221,13 +3222,13 @@ export const REPORTS_BUILDER_DIMENSION_LABELS: Record< ReportsBuilderDimension, string > = { - none: "بدون گروه‌بندی (جمع کل)", - owner: "کاربر / مسئول", - team: "تیم", - source: "منبع", - stage: "مرحله کاریز", - month: "ماه", - status: "وضعیت معامله", + none: "بدون گروه‌بندی (جمع کل)", + owner: "کاربر / مسئول", + team: "تیم", + source: "منبع", + stage: "مرحله کاریز", + month: "ماه", + status: "وضعیت معامله", }; export interface ReportsBuilderQuery { @@ -3278,7 +3279,7 @@ export interface CreateSavedViewRequest { export type UpdateSavedViewRequest = Partial; -/* ——— API عمومی و وب‌هوک ——— */ +/* ——— API عمومی و وب‌هوک ——— */ export const WEBHOOK_EVENTS = [ "person.created", @@ -3307,7 +3308,7 @@ export interface CreateOrganizationApiKeyRequest { } export interface CreateOrganizationApiKeyResponse extends OrganizationApiKeyDto { - /** فقط یک‌بار هنگام ساخت برگردانده می‌شود */ + /** فقط یک‌بار هنگام ساخت برگردانده می‌شود */ rawKey: string; } @@ -3329,7 +3330,7 @@ export interface CreateWebhookEndpointRequest { isActive?: boolean; } -/** فقط هنگام ساخت؛ secret دوباره برنمی‌گردد */ +/** فقط هنگام ساخت؛ secret دوباره برنمی‌گردد */ export interface CreateWebhookEndpointResponse extends WebhookEndpointDto { secret: string; } @@ -3347,7 +3348,7 @@ export interface WebhookDeliveryDto { deliveredAt: string | null; } -/* ——— پیامک گروهی ——— */ +/* ——— پیامک گروهی ——— */ export type SmsCampaignStatus = | "draft" @@ -3375,7 +3376,7 @@ export interface CreateSmsCampaignRequest { body: string; personIds: string[]; scheduledAt?: string | null; - /** اگر true باشد بلافاصله صف می‌شود */ + /** اگر true باشد بلافاصله صف می‌شود */ queueNow?: boolean; } @@ -3384,7 +3385,7 @@ export interface SmsCampaignListResponse { total: number; } -/* ——— تیم‌ها و سطح دسترسی به پرونده‌ها ——— */ +/* ——— تیم‌ها و سطح دسترسی به پرونده‌ها ——— */ export type TeamMemberRole = "member" | "manager"; @@ -3421,7 +3422,7 @@ export interface SetTeamMembersRequest { members: Array<{ userId: string; role: TeamMemberRole }>; } -/* ——— ووکامرس ——— */ +/* ——— ووکامرس ——— */ export interface WooCommerceConnectionDto { id: string; @@ -3477,7 +3478,7 @@ export interface WooCommerceOrderLinkDto { syncedAt: string; } -/* ——— تلفن سازمانی / VoIP ——— */ +/* ——— تلفن سازمانی / VoIP ——— */ export type VoipCallDirection = "inbound" | "outbound"; @@ -3493,7 +3494,7 @@ export interface VoipConnectionDto { label: string; enabled: boolean; webhookSecretSet: boolean; - /** قالب URL برای شروع تماس؛ {number} جایگزین می‌شود */ + /** قالب URL برای شروع تماس؛ {number} جایگزین می‌شود */ clickToCallUrl: string | null; lastEventAt: string | null; lastError: string | null; @@ -3550,7 +3551,7 @@ export interface VoipClickToCallRequest { } export interface VoipWebhookEvent { - /** شناسه یکتای تماس در سانترال */ + /** شناسه یکتای تماس در سانترال */ callId: string; direction: VoipCallDirection; status: VoipCallStatus | string; @@ -3559,16 +3560,16 @@ export interface VoipWebhookEvent { startedAt?: string; endedAt?: string; durationSec?: number; - /** لینک فایل ضبط (برای خلاصه خودکار) */ + /** لینک فایل ضبط (برای خلاصه خودکار) */ recordingUrl?: string; - /** متن آمادهٔ تماس؛ اگر باشد STT رد می‌شود */ + /** متن آمادهٔ تماس؛ اگر باشد STT رد می‌شود */ transcript?: string; - /** برای سازگاری با فیلدهای رایج دیگر */ + /** برای سازگاری با فیلدهای رایج دیگر */ caller?: string; callee?: string; } -/* ——— رزرو و نوبت‌دهی ——— */ +/* ——— رزرو و نوبت‌دهی ——— */ export type ReservationStatus = | "pending" @@ -3584,10 +3585,10 @@ export const RESERVATION_STATUSES: ReservationStatus[] = [ ]; export const RESERVATION_STATUS_LABELS: Record = { - pending: "در انتظار", - confirmed: "تأیید شده", - canceled: "لغو شده", - done: "انجام شده", + pending: "در انتظار", + confirmed: "تأیید شده", + canceled: "لغو شده", + done: "انجام شده", }; export interface ReservationServiceDto { @@ -3595,7 +3596,7 @@ export interface ReservationServiceDto { name: string; description: string; durationMinutes: number; - /** روزهای هفته Û°=یکشنبه … Û¶=شنبه (JS getDay) */ + /** روزهای هفته Û°=یکشنبه … Û¶=شنبه (JS getDay) */ workDays: number[]; dayStartHour: number; dayEndHour: number; @@ -3663,7 +3664,7 @@ export interface ReservationListResponse { -/* ——— مدیریت لیدها ——— */ +/* ——— مدیریت لیدها ——— */ export type LeadAssignRule = "round_robin" | "equal_split";