2026-09-27 21:17:42 +03:30
|
|
|
export type UserRole = "owner" | "admin" | "sales" | "support";
|
2026-09-27 18:00:59 +03:30
|
|
|
|
2026-09-27 21:17:42 +03:30
|
|
|
export const USER_ROLES: UserRole[] = ["owner", "admin", "sales", "support"];
|
|
|
|
|
|
|
|
|
|
export const USER_ROLE_LABELS: Record<UserRole, string> = {
|
|
|
|
|
owner: "Ù
اÙÚ©",
|
|
|
|
|
admin: "Ù
Ø¯ÛØ±",
|
|
|
|
|
sales: "ÙØ±ÙØ´",
|
|
|
|
|
support: "Ù¾Ø´ØªÛØ¨Ø§ÙÛ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** ØªÙØ¸ÛÙ
ات سازÙ
اÙÛ Ù Ù
Ø¯ÛØ±Ûت کاربرا٠*/
|
|
|
|
|
export function canManageSettings(role: UserRole | string | null | undefined): boolean {
|
|
|
|
|
return role === "owner" || role === "admin";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function canManageUsers(role: UserRole | string | null | undefined): boolean {
|
|
|
|
|
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";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AuthUserDto {
|
|
|
|
|
id: string;
|
|
|
|
|
email: string;
|
|
|
|
|
mobile?: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
role: UserRole;
|
|
|
|
|
organizationId: string;
|
|
|
|
|
organizationName?: string;
|
|
|
|
|
hasAvatar?: boolean;
|
|
|
|
|
/** Ù
اÙÚ© Ù
ØÛØ· ÙØ¹ÙÛ â Ø§Ø´ØªØ±Ø§Ú© Ù
تعÙ٠ب٠Ù
اÙÚ© است ÙÙ Ø¹Ø¶Ù Ø²ÛØ±Ù
جÙ
ÙØ¹Ù */
|
|
|
|
|
isOrgOwner?: boolean;
|
|
|
|
|
enabledModules?: OrgModuleKey[];
|
|
|
|
|
/** Ø®ÙØ§ØµÙ اشتراک Ù
اÙÚ© Ù
ØÛØ· (Ø¨Ø±Ø§Û Ø§Ø¹Ø¶Ø§ ÙÙØ· Ø¬ÙØª ÙÙ
Ø§ÛØ´/Ú¯ÛØª ÙØ±Ùد) */
|
|
|
|
|
subscription?: SubscriptionSummaryDto | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type BillingPlanCode =
|
|
|
|
|
| "trial"
|
|
|
|
|
| "monthly"
|
|
|
|
|
| "quarterly"
|
|
|
|
|
| "semiannual"
|
|
|
|
|
| "yearly"
|
|
|
|
|
| "custom";
|
|
|
|
|
|
|
|
|
|
export type BillingAccountStatus = "active" | "expired" | "suspended";
|
|
|
|
|
|
|
|
|
|
export const BILLING_PLAN_CODES: BillingPlanCode[] = [
|
|
|
|
|
"trial",
|
|
|
|
|
"monthly",
|
|
|
|
|
"quarterly",
|
|
|
|
|
"semiannual",
|
|
|
|
|
"yearly",
|
|
|
|
|
"custom",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export const BILLING_PLAN_LABELS: Record<BillingPlanCode, string> = {
|
|
|
|
|
trial: "دÙ
Ù Û±Ûµ Ø±ÙØ²Ù",
|
|
|
|
|
monthly: "Ù
Ø§ÙØ§ÙÙ",
|
|
|
|
|
quarterly: "سÙâÙ
اÙÙ",
|
|
|
|
|
semiannual: "ششâÙ
اÙÙ",
|
|
|
|
|
yearly: "ÛکساÙÙ",
|
|
|
|
|
custom: "Ø³ÙØ§Ø±Ø´Û",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** Ù
دت Ù¾ÛØ´âÙØ±Ø¶ Ù¾ÙÙâÙØ§ (Ø±ÙØ²) â custom ÙØ¯Ø§Ø±Ø¯ */
|
|
|
|
|
export const BILLING_PLAN_DAYS: Record<Exclude<BillingPlanCode, "custom">, number> = {
|
|
|
|
|
trial: 15,
|
|
|
|
|
monthly: 30,
|
|
|
|
|
quarterly: 90,
|
|
|
|
|
semiannual: 180,
|
|
|
|
|
yearly: 365,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const BILLING_PLAN_DEFAULT_MAX_ORGS: Record<
|
|
|
|
|
Exclude<BillingPlanCode, "custom">,
|
|
|
|
|
number
|
|
|
|
|
> = {
|
|
|
|
|
trial: 1,
|
|
|
|
|
monthly: 3,
|
|
|
|
|
quarterly: 5,
|
|
|
|
|
semiannual: 10,
|
|
|
|
|
yearly: 20,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export type OrgModuleKey =
|
|
|
|
|
| "customers"
|
|
|
|
|
| "pipeline"
|
|
|
|
|
| "products"
|
|
|
|
|
| "invoices"
|
|
|
|
|
| "quotes"
|
|
|
|
|
| "commissions"
|
|
|
|
|
| "sales_forecast"
|
|
|
|
|
| "activities"
|
|
|
|
|
| "tickets"
|
|
|
|
|
| "workflow_automations"
|
|
|
|
|
| "message_automations"
|
|
|
|
|
| "lead_forms"
|
|
|
|
|
| "project_boards"
|
|
|
|
|
| "inventory"
|
|
|
|
|
| "cheques"
|
|
|
|
|
| "attachments"
|
|
|
|
|
| "loyalty"
|
|
|
|
|
| "reports"
|
|
|
|
|
| "notes"
|
|
|
|
|
| "tahesab"
|
|
|
|
|
| "custom_fields"
|
|
|
|
|
| "currencies"
|
|
|
|
|
| "team_settings"
|
|
|
|
|
| "faq"
|
|
|
|
|
| "audit_logs"
|
|
|
|
|
| "saved_views"
|
|
|
|
|
| "public_api"
|
|
|
|
|
| "sms_campaigns"
|
|
|
|
|
| "teams"
|
|
|
|
|
| "woocommerce"
|
|
|
|
|
| "voip"
|
|
|
|
|
| "reservations"
|
|
|
|
|
| "leads";
|
|
|
|
|
|
|
|
|
|
export const ORG_MODULE_KEYS: OrgModuleKey[] = [
|
|
|
|
|
"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",
|
|
|
|
|
"audit_logs",
|
|
|
|
|
"saved_views",
|
|
|
|
|
"public_api",
|
|
|
|
|
"sms_campaigns",
|
|
|
|
|
"teams",
|
|
|
|
|
"woocommerce",
|
|
|
|
|
"voip",
|
|
|
|
|
"reservations",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export const ORG_MODULE_LABELS: Record<OrgModuleKey, string> = {
|
|
|
|
|
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: "رزر٠٠ÙÙØ¨ØªâدÙÛ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const ORG_MODULE_GROUPS: Array<{
|
|
|
|
|
title: string;
|
|
|
|
|
keys: OrgModuleKey[];
|
|
|
|
|
}> = [
|
|
|
|
|
{ title: "Ù
Ø´ØªØ±ÛØ§Ù", keys: ["customers"] },
|
|
|
|
|
{ title: "ÙÛØ¯Ùا", keys: ["leads", "lead_forms"] },
|
|
|
|
|
{
|
|
|
|
|
title: "ÙØ±ÙØ´",
|
|
|
|
|
keys: [
|
|
|
|
|
"pipeline",
|
|
|
|
|
"products",
|
|
|
|
|
"invoices",
|
|
|
|
|
"quotes",
|
|
|
|
|
"commissions",
|
|
|
|
|
"sales_forecast",
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{ title: "ÙØ¹Ø§ÙÛØªâÙØ§", keys: ["activities", "notes"] },
|
|
|
|
|
{ title: "Ù¾Ø´ØªÛØ¨Ø§ÙÛ", keys: ["tickets", "faq"] },
|
|
|
|
|
{
|
|
|
|
|
title: "اتÙÙ
اسÛÙÙ",
|
|
|
|
|
keys: [
|
|
|
|
|
"workflow_automations",
|
|
|
|
|
"message_automations",
|
|
|
|
|
"sms_campaigns",
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "Ø§Ø¨Ø²Ø§Ø±ÙØ§",
|
|
|
|
|
keys: [
|
|
|
|
|
"project_boards",
|
|
|
|
|
"inventory",
|
|
|
|
|
"cheques",
|
|
|
|
|
"attachments",
|
|
|
|
|
"loyalty",
|
|
|
|
|
"reports",
|
|
|
|
|
"saved_views",
|
|
|
|
|
"woocommerce",
|
|
|
|
|
"voip",
|
|
|
|
|
"reservations",
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
{
|
|
|
|
|
title: "ØªÙØ¸ÛÙ
ات",
|
|
|
|
|
keys: [
|
|
|
|
|
"team_settings",
|
|
|
|
|
"teams",
|
|
|
|
|
"custom_fields",
|
|
|
|
|
"currencies",
|
|
|
|
|
"tahesab",
|
|
|
|
|
"audit_logs",
|
|
|
|
|
"public_api",
|
|
|
|
|
],
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export function isOrgModuleKey(value: string): value is OrgModuleKey {
|
|
|
|
|
return (ORG_MODULE_KEYS as readonly string[]).includes(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function defaultEnabledModules(): OrgModuleKey[] {
|
|
|
|
|
return [...ORG_MODULE_KEYS];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SubscriptionSummaryDto {
|
|
|
|
|
planCode: BillingPlanCode;
|
|
|
|
|
status: BillingAccountStatus;
|
|
|
|
|
startsAt: string;
|
|
|
|
|
expiresAt: string;
|
|
|
|
|
maxOrganizations: number;
|
|
|
|
|
daysRemaining: number;
|
|
|
|
|
warn: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface BillingAccountDto {
|
|
|
|
|
id: string;
|
|
|
|
|
ownerUserId: string;
|
|
|
|
|
planCode: BillingPlanCode;
|
|
|
|
|
status: BillingAccountStatus;
|
|
|
|
|
startsAt: string;
|
|
|
|
|
expiresAt: string;
|
|
|
|
|
maxOrganizations: number;
|
|
|
|
|
externalPaymentRef?: string | null;
|
|
|
|
|
notes?: string | null;
|
|
|
|
|
daysRemaining: number;
|
|
|
|
|
warn: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ApplyBillingPlanRequest {
|
|
|
|
|
planCode: BillingPlanCode;
|
|
|
|
|
maxOrganizations?: number;
|
|
|
|
|
expiresAt?: string;
|
|
|
|
|
notes?: string | null;
|
|
|
|
|
status?: BillingAccountStatus;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateOrgModulesRequest {
|
|
|
|
|
enabledModules: OrgModuleKey[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface OrgUserDto {
|
|
|
|
|
id: string;
|
|
|
|
|
email: string;
|
|
|
|
|
mobile?: string | null;
|
|
|
|
|
fullName: string;
|
|
|
|
|
role: UserRole;
|
|
|
|
|
orgRoleId?: string | null;
|
|
|
|
|
orgRoleName?: string;
|
|
|
|
|
orgRoleColor?: string;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
lastLoginAt?: string | null;
|
|
|
|
|
hasAvatar?: boolean;
|
|
|
|
|
commissionPercent?: number;
|
|
|
|
|
/** own = ÙÙØ· Ø®ÙØ¯ | team = ÙÙ
âØªÛÙ
ÛâÙØ§ | org = ک٠سازÙ
ا٠*/
|
|
|
|
|
dataVisibility?: DataVisibility;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type DataVisibility = "own" | "team" | "org";
|
|
|
|
|
|
|
|
|
|
export const DATA_VISIBILITIES: DataVisibility[] = ["own", "team", "org"];
|
|
|
|
|
|
|
|
|
|
export const DATA_VISIBILITY_LABELS: Record<DataVisibility, string> = {
|
|
|
|
|
own: "ÙÙØ· پرÙÙØ¯ÙâÙØ§Û Ø®ÙØ¯",
|
|
|
|
|
team: "تÛÙ
âÙØ§Û عضÙ",
|
|
|
|
|
org: "ک٠سازÙ
اÙ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export interface UpdateUserVisibilityRequest {
|
|
|
|
|
dataVisibility: DataVisibility;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type RolePermissionKey =
|
|
|
|
|
| "customers"
|
|
|
|
|
| "sales"
|
|
|
|
|
| "billing"
|
|
|
|
|
| "products"
|
|
|
|
|
| "activities"
|
|
|
|
|
| "notes"
|
|
|
|
|
| "reports"
|
|
|
|
|
| "audit";
|
|
|
|
|
|
|
|
|
|
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: "ÙØ§Ú¯ ÙØ¹Ø§ÙÛØª کاربراÙ" },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export interface OrgRoleMemberDto {
|
|
|
|
|
id: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
hasAvatar: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface OrgRoleDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
description: string;
|
|
|
|
|
color: string;
|
|
|
|
|
permissions: RolePermissionKey[];
|
|
|
|
|
systemKey: UserRole | null;
|
|
|
|
|
userCount: number;
|
|
|
|
|
members: OrgRoleMemberDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateOrgRoleRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
color?: string;
|
|
|
|
|
permissions?: RolePermissionKey[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateOrgRoleRequest {
|
|
|
|
|
name?: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
color?: string;
|
|
|
|
|
permissions?: RolePermissionKey[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface InviteUserRequest {
|
|
|
|
|
mobile: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
password?: string;
|
|
|
|
|
role?: Exclude<UserRole, "owner">;
|
|
|
|
|
orgRoleId?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateUserRoleRequest {
|
|
|
|
|
role?: UserRole;
|
|
|
|
|
orgRoleId?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateUserStatusRequest {
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateUserCommissionRequest {
|
|
|
|
|
commissionPercent: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateProfileRequest {
|
|
|
|
|
fullName: string;
|
|
|
|
|
email: string;
|
|
|
|
|
mobile: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type DealStatus = "open" | "won" | "lost";
|
|
|
|
|
|
|
|
|
|
export interface ApiErrorBody {
|
|
|
|
|
statusCode: number;
|
|
|
|
|
message: string | string[];
|
|
|
|
|
error?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoginRequest {
|
|
|
|
|
/** اÛÙ
ÛÙ ÛØ§ Ø´Ù
ار٠Ù
ÙØ¨Ø§ÛÙ */
|
|
|
|
|
identifier: string;
|
|
|
|
|
password: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface RegisterOrganizationRequest {
|
|
|
|
|
organizationName: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
email: string;
|
|
|
|
|
mobile: string;
|
|
|
|
|
password: string;
|
|
|
|
|
passwordConfirm: string;
|
|
|
|
|
businessField: BusinessField;
|
|
|
|
|
referralCode?: string;
|
|
|
|
|
acceptedTerms?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoginChallengeResponse {
|
|
|
|
|
challengeId: string;
|
|
|
|
|
channel: 'email' | 'mobile';
|
|
|
|
|
expiresInSeconds: number;
|
|
|
|
|
maskedDestination?: string;
|
|
|
|
|
/** ÙÙØ· در Ù
ØÛØ· ØªÙØ³Ø¹Ù / AUTH_RETURN_OTP */
|
|
|
|
|
devCode?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface RegisterChallengeResponse {
|
|
|
|
|
challengeId: string;
|
|
|
|
|
expiresInSeconds: number;
|
|
|
|
|
maskedEmail?: string;
|
|
|
|
|
maskedMobile?: string;
|
|
|
|
|
/** ÙÙØªÛ سرÙÛØ³ اÛÙ
Û٠خاÙ
ÙØ´ است false â ÙÙØ· OTP Ù
ÙØ¨Ø§ÛÙ ÙØ§Ø²Ù
است */
|
|
|
|
|
emailOtpRequired?: boolean;
|
|
|
|
|
devEmailCode?: string;
|
|
|
|
|
devMobileCode?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoginVerifyRequest {
|
|
|
|
|
challengeId: string;
|
|
|
|
|
code: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface RegisterVerifyRequest {
|
|
|
|
|
challengeId: string;
|
|
|
|
|
emailCode?: string;
|
|
|
|
|
mobileCode: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoginResponse {
|
|
|
|
|
accessToken: string;
|
|
|
|
|
user: AuthUserDto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface OrganizationMembershipDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
role: UserRole;
|
|
|
|
|
orgRoleName?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoginOrganizationChoiceResponse {
|
|
|
|
|
requiresOrganizationChoice: true;
|
|
|
|
|
selectionToken: string;
|
|
|
|
|
organizations: OrganizationMembershipDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type LoginResult = LoginResponse | LoginOrganizationChoiceResponse;
|
|
|
|
|
|
|
|
|
|
export function isLoginOrganizationChoice(
|
|
|
|
|
data: LoginResult,
|
|
|
|
|
): data is LoginOrganizationChoiceResponse {
|
|
|
|
|
return (
|
|
|
|
|
typeof data === "object" &&
|
|
|
|
|
data !== null &&
|
|
|
|
|
"requiresOrganizationChoice" in data &&
|
|
|
|
|
data.requiresOrganizationChoice === true
|
|
|
|
|
);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SelectOrganizationRequest {
|
|
|
|
|
selectionToken: string;
|
|
|
|
|
organizationId: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SwitchOrganizationRequest {
|
|
|
|
|
organizationId: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateOrganizationRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
businessField?: BusinessField;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface OrganizationDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
slug: string;
|
|
|
|
|
businessField: BusinessField | null;
|
|
|
|
|
baseCurrency: string;
|
|
|
|
|
enabledCurrencies: string[];
|
|
|
|
|
exchangeRates: ExchangeRateDto[];
|
|
|
|
|
enabledModules: OrgModuleKey[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateOrganizationRequest {
|
|
|
|
|
name?: string;
|
|
|
|
|
businessField?: BusinessField;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** زÙ
ÛÙÙ ÙØ¹Ø§ÙÛØª سازÙ
ا٠â ÙÙ
âØªØ±Ø§Ø² ØµÙØ§Ûع Ø¯ÛØ¯Ø§Ø± */
|
|
|
|
|
export const BUSINESS_FIELDS = [
|
|
|
|
|
"education",
|
|
|
|
|
"beauty",
|
|
|
|
|
"real_estate",
|
|
|
|
|
"construction",
|
|
|
|
|
"advertising",
|
|
|
|
|
"insurance",
|
|
|
|
|
"consulting",
|
|
|
|
|
"startup",
|
|
|
|
|
"medical_devices",
|
|
|
|
|
"travel",
|
|
|
|
|
"contractor",
|
|
|
|
|
"trading",
|
|
|
|
|
"manufacturing",
|
|
|
|
|
"personal",
|
|
|
|
|
"tech",
|
|
|
|
|
"legal",
|
|
|
|
|
"repair",
|
|
|
|
|
"retail",
|
|
|
|
|
"jewelry",
|
|
|
|
|
"other",
|
|
|
|
|
] as const;
|
|
|
|
|
|
|
|
|
|
export type BusinessField = (typeof BUSINESS_FIELDS)[number];
|
|
|
|
|
|
|
|
|
|
export const BUSINESS_FIELD_LABELS: Record<BusinessField, string> = {
|
|
|
|
|
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 {
|
|
|
|
|
return (BUSINESS_FIELDS as readonly string[]).includes(value);
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ExchangeRateDto {
|
|
|
|
|
currency: string;
|
|
|
|
|
rateToBase: number;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateOrgCurrenciesRequest {
|
|
|
|
|
baseCurrency?: string;
|
|
|
|
|
enabledCurrencies?: string[];
|
|
|
|
|
/** ÙØ±Ø®âÙØ§ ÙØ³Ø¨Øª ب٠ارز پاÛÙØ ارز پاÛÙ ÙÛØ§Ø²Û Ø¨Ù ÙØ±Ø® ÙØ¯Ø§Ø±Ø¯ */
|
|
|
|
|
rates?: Array<{ currency: string; rateToBase: number }>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const CURRENCY_CATALOG: Array<{
|
|
|
|
|
code: string;
|
|
|
|
|
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: "Ù¾ÙÙØ¯" },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export function currencySuffix(code: string): string {
|
|
|
|
|
return CURRENCY_CATALOG.find((c) => c.code === code)?.suffix ?? code;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function formatMoneyAmount(amount: number, currency = "IRR"): string {
|
|
|
|
|
try {
|
|
|
|
|
const n = new Intl.NumberFormat("fa-IR").format(amount);
|
|
|
|
|
return `${n} ${currencySuffix(currency)}`;
|
|
|
|
|
} catch {
|
|
|
|
|
return `${amount} ${currency}`;
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface HealthResponse {
|
|
|
|
|
status: "ok";
|
|
|
|
|
service: string;
|
|
|
|
|
timestamp: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CompanySummaryDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CompanyDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
nationalId: string | null;
|
|
|
|
|
phone: string | null;
|
|
|
|
|
email: string | null;
|
|
|
|
|
website: string | null;
|
|
|
|
|
address: string | null;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
tags: string[];
|
|
|
|
|
customFields: Record<string, unknown>;
|
|
|
|
|
peopleCount: number;
|
|
|
|
|
owner: UserSummaryDto | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateCompanyRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
nationalId?: string;
|
|
|
|
|
phone?: string;
|
|
|
|
|
email?: string;
|
|
|
|
|
website?: string;
|
|
|
|
|
address?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
customFields?: Record<string, unknown>;
|
|
|
|
|
ownerId?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateCompanyRequest = Partial<CreateCompanyRequest>;
|
|
|
|
|
|
|
|
|
|
export interface LoyaltyTierSummaryDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
minPoints: number;
|
|
|
|
|
color: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const PERSON_MOODS = ["newcomer", "happy", "unhappy", "special"] as const;
|
|
|
|
|
export type PersonMood = (typeof PERSON_MOODS)[number];
|
|
|
|
|
|
|
|
|
|
export const PERSON_MOOD_LABELS: Record<PersonMood, string> = {
|
|
|
|
|
newcomer: "Ù
Ø´ØªØ±Û ØªØ§Ø²Ù ÙØ§Ø±Ø¯",
|
|
|
|
|
happy: "Ù
Ø´ØªØ±Û Ø®ÙØ´ØØ§Ù",
|
|
|
|
|
unhappy: "Ù
Ø´ØªØ±Û ÙØ§Ø±Ø§Ø¶Û",
|
|
|
|
|
special: "Ù
Ø´ØªØ±Û Ø®Ø§Øµ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export interface PersonDto {
|
|
|
|
|
id: string;
|
|
|
|
|
firstName: string;
|
|
|
|
|
lastName: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
email: string | null;
|
|
|
|
|
phone: string | null;
|
|
|
|
|
mobile: string | null;
|
|
|
|
|
position: string | null;
|
|
|
|
|
website: string | null;
|
|
|
|
|
referrer: string | null;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
mood: PersonMood;
|
|
|
|
|
tags: string[];
|
|
|
|
|
customFields: Record<string, unknown>;
|
|
|
|
|
loyaltyPoints: number;
|
|
|
|
|
loyaltyTier: LoyaltyTierSummaryDto | null;
|
|
|
|
|
company: CompanySummaryDto | null;
|
|
|
|
|
owner: UserSummaryDto | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreatePersonRequest {
|
|
|
|
|
firstName?: string;
|
|
|
|
|
lastName?: string;
|
|
|
|
|
email?: string;
|
|
|
|
|
phone?: string;
|
|
|
|
|
mobile?: string;
|
|
|
|
|
position?: string;
|
|
|
|
|
website?: string;
|
|
|
|
|
referrer?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
mood?: PersonMood;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
customFields?: Record<string, unknown>;
|
|
|
|
|
ownerId?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdatePersonRequest = Partial<CreatePersonRequest>;
|
|
|
|
|
|
|
|
|
|
export interface PaginatedResponse<T> {
|
|
|
|
|
items: T[];
|
|
|
|
|
total: number;
|
|
|
|
|
page: number;
|
|
|
|
|
limit: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PersonSummaryDto {
|
|
|
|
|
id: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UserSummaryDto {
|
|
|
|
|
id: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PipelineStageDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
position: number;
|
|
|
|
|
isWon: boolean;
|
|
|
|
|
isLost: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PipelineDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
isDefault: boolean;
|
|
|
|
|
stages: PipelineStageDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface DealDto {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
amount: number | null;
|
|
|
|
|
currency: string;
|
|
|
|
|
status: DealStatus;
|
|
|
|
|
source: string | null;
|
|
|
|
|
lostReason: string | null;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
tags: string[];
|
|
|
|
|
isStale: boolean;
|
|
|
|
|
isRotten: boolean;
|
|
|
|
|
customFields: Record<string, unknown>;
|
|
|
|
|
expectedCloseAt: string | null;
|
|
|
|
|
position: number;
|
|
|
|
|
pipelineId: string;
|
|
|
|
|
stageId: string;
|
|
|
|
|
person: PersonSummaryDto | null;
|
|
|
|
|
company: CompanySummaryDto | null;
|
|
|
|
|
owner: UserSummaryDto | null;
|
|
|
|
|
/** Ù
سئÙÙØ§Ù Ù
شترک Ù
عاÙ
ÙÙ (Ø¹ÙØ§Ù٠بر Ù
اÙÚ© اصÙÛ) */
|
|
|
|
|
assignees: UserSummaryDto[];
|
|
|
|
|
lineItems: DealLineItemDto[];
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PipelineBoardStageDto extends PipelineStageDto {
|
|
|
|
|
deals: DealDto[];
|
|
|
|
|
totalAmount: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PipelineBoardDto {
|
|
|
|
|
pipeline: PipelineDto;
|
|
|
|
|
stages: PipelineBoardStageDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreatePipelineRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreatePipelineStageRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdatePipelineStageRequest {
|
|
|
|
|
name?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReorderPipelineStagesRequest {
|
|
|
|
|
stageIds: string[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateDealRequest {
|
|
|
|
|
title: string;
|
|
|
|
|
pipelineId?: string;
|
|
|
|
|
stageId?: string;
|
|
|
|
|
amount?: number | null;
|
|
|
|
|
currency?: string;
|
|
|
|
|
source?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
isStale?: boolean;
|
|
|
|
|
isRotten?: boolean;
|
|
|
|
|
expectedCloseAt?: string | null;
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
ownerId?: string | null;
|
|
|
|
|
assigneeIds?: string[];
|
|
|
|
|
customFields?: Record<string, unknown>;
|
|
|
|
|
lineItems?: DealLineItemInput[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateDealRequest {
|
|
|
|
|
title?: string;
|
|
|
|
|
amount?: number | null;
|
|
|
|
|
currency?: string;
|
|
|
|
|
source?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
isStale?: boolean;
|
|
|
|
|
isRotten?: boolean;
|
|
|
|
|
lostReason?: string | null;
|
|
|
|
|
expectedCloseAt?: string | null;
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
ownerId?: string | null;
|
|
|
|
|
assigneeIds?: string[];
|
|
|
|
|
customFields?: Record<string, unknown>;
|
|
|
|
|
lineItems?: DealLineItemInput[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** ÙÛÙØªØ± Ø°Ø®ÛØ±ÙâØ´Ø¯ÙÙ ÙÛØ³Øª اشخاص */
|
|
|
|
|
export interface PeopleViewFilters {
|
|
|
|
|
q?: string;
|
|
|
|
|
sort?: string;
|
|
|
|
|
mood?: string;
|
|
|
|
|
page?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** ÙÛÙØªØ± Ø°Ø®ÛØ±ÙâØ´Ø¯ÙÙ Ú©Ø§Ø±ÛØ² / Ù
عاÙ
ÙØ§Øª */
|
|
|
|
|
export interface DealsViewFilters {
|
|
|
|
|
q?: string;
|
|
|
|
|
amountMin?: string;
|
|
|
|
|
amountMax?: string;
|
|
|
|
|
pipelineId?: string;
|
|
|
|
|
viewMode?: string;
|
|
|
|
|
}
|
|
|
|
|
export interface MoveDealRequest {
|
|
|
|
|
stageId: string;
|
|
|
|
|
position?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type ActivityType = "call" | "meeting" | "task" | "note";
|
|
|
|
|
export type ActivityStatus = "open" | "done" | "canceled";
|
|
|
|
|
export type ActivityPriority = "very_low" | "low" | "medium" | "high" | "very_high";
|
|
|
|
|
export type ActivityFilter = "today" | "overdue" | "upcoming" | "done" | "all";
|
|
|
|
|
|
|
|
|
|
export type CustomFieldEntity = "person" | "company" | "deal";
|
|
|
|
|
export type CustomFieldType = "text" | "number" | "date" | "boolean" | "select";
|
|
|
|
|
|
|
|
|
|
export interface CustomFieldDefinitionDto {
|
|
|
|
|
id: string;
|
|
|
|
|
entityType: CustomFieldEntity;
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
fieldType: CustomFieldType;
|
|
|
|
|
options: string[];
|
|
|
|
|
required: boolean;
|
|
|
|
|
position: number;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateCustomFieldRequest {
|
|
|
|
|
entityType: CustomFieldEntity;
|
|
|
|
|
label: string;
|
|
|
|
|
key?: string;
|
|
|
|
|
fieldType?: CustomFieldType;
|
|
|
|
|
options?: string[];
|
|
|
|
|
required?: boolean;
|
|
|
|
|
position?: number;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateCustomFieldRequest {
|
|
|
|
|
label?: string;
|
|
|
|
|
fieldType?: CustomFieldType;
|
|
|
|
|
options?: string[];
|
|
|
|
|
required?: boolean;
|
|
|
|
|
position?: number;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface DealSummaryDto {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ActivityDto {
|
|
|
|
|
id: string;
|
|
|
|
|
type: ActivityType;
|
|
|
|
|
status: ActivityStatus;
|
|
|
|
|
priority: ActivityPriority;
|
|
|
|
|
title: string;
|
|
|
|
|
description: string | null;
|
|
|
|
|
dueAt: string | null;
|
|
|
|
|
durationMinutes: number | null;
|
|
|
|
|
reminderAt: string | null;
|
|
|
|
|
reminderNotifyApp: boolean;
|
|
|
|
|
reminderNotifySms: boolean;
|
|
|
|
|
completedAt: string | null;
|
|
|
|
|
tags: string[];
|
|
|
|
|
person: PersonSummaryDto | null;
|
|
|
|
|
company: CompanySummaryDto | null;
|
|
|
|
|
deal: DealSummaryDto | null;
|
|
|
|
|
assignee: UserSummaryDto | null;
|
|
|
|
|
createdBy: UserSummaryDto | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateActivityRequest {
|
|
|
|
|
title: string;
|
|
|
|
|
type?: ActivityType;
|
|
|
|
|
priority?: ActivityPriority;
|
|
|
|
|
description?: string;
|
|
|
|
|
dueAt?: string | null;
|
|
|
|
|
durationMinutes?: number | null;
|
|
|
|
|
reminderAt?: string | null;
|
|
|
|
|
reminderNotifyApp?: boolean;
|
|
|
|
|
reminderNotifySms?: boolean;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
assigneeId?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateActivityRequest {
|
|
|
|
|
title?: string;
|
|
|
|
|
type?: ActivityType;
|
|
|
|
|
status?: ActivityStatus;
|
|
|
|
|
priority?: ActivityPriority;
|
|
|
|
|
description?: string | null;
|
|
|
|
|
dueAt?: string | null;
|
|
|
|
|
durationMinutes?: number | null;
|
|
|
|
|
reminderAt?: string | null;
|
|
|
|
|
reminderNotifyApp?: boolean;
|
|
|
|
|
reminderNotifySms?: boolean;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
assigneeId?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ActivitySummaryDto {
|
|
|
|
|
today: ActivityDto[];
|
|
|
|
|
overdue: ActivityDto[];
|
|
|
|
|
upcoming: ActivityDto[];
|
|
|
|
|
todayCount: number;
|
|
|
|
|
overdueCount: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type NoteType =
|
|
|
|
|
| "general"
|
|
|
|
|
| "call_result"
|
|
|
|
|
| "meeting"
|
|
|
|
|
| "important"
|
|
|
|
|
| "warning"
|
|
|
|
|
| "next_action"
|
|
|
|
|
| "follow_up"
|
|
|
|
|
| "idea"
|
|
|
|
|
| "suggestion"
|
|
|
|
|
| "personal";
|
|
|
|
|
|
|
|
|
|
export interface NoteAttachmentDto {
|
|
|
|
|
id: string;
|
|
|
|
|
fileName: string;
|
|
|
|
|
mimeType: string;
|
|
|
|
|
sizeBytes: number;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface NoteChecklistItemDto {
|
|
|
|
|
id: string;
|
|
|
|
|
text: string;
|
|
|
|
|
done: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface NoteDto {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string | null;
|
|
|
|
|
body: string;
|
|
|
|
|
noteType: NoteType | string;
|
|
|
|
|
/** team = تÛÙ
Û | personal = ÙÙØ· ÙÙÛØ³Ùد٠*/
|
|
|
|
|
visibility: NoteVisibility;
|
|
|
|
|
pinned: boolean;
|
|
|
|
|
color: string | null;
|
|
|
|
|
tags: string[];
|
|
|
|
|
reminderAt: string | null;
|
|
|
|
|
checklist: NoteChecklistItemDto[];
|
|
|
|
|
locationText: string | null;
|
|
|
|
|
analyzeEnabled: boolean;
|
|
|
|
|
person: PersonSummaryDto | null;
|
|
|
|
|
company: CompanySummaryDto | null;
|
|
|
|
|
deal: DealSummaryDto | null;
|
|
|
|
|
activity: { id: string; title: string } | null;
|
|
|
|
|
author: UserSummaryDto | null;
|
|
|
|
|
attachments: NoteAttachmentDto[];
|
|
|
|
|
/** تعداد ÙØ³Ø®ÙâÙØ§Û ÙØ¨ÙÛ (Ø¨Ø±Ø§Û ÙÙ
Ø§ÛØ´ دکÙ
Ù ØªØ§Ø±ÛØ®ÚÙ) */
|
|
|
|
|
revisionCount?: number;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type NoteVisibility = "team" | "personal";
|
|
|
|
|
|
|
|
|
|
export const NOTE_VISIBILITIES: NoteVisibility[] = ["team", "personal"];
|
|
|
|
|
|
|
|
|
|
export const NOTE_VISIBILITY_LABELS: Record<NoteVisibility, string> = {
|
|
|
|
|
team: "تÛÙ
Û",
|
|
|
|
|
personal: "Ø´Ø®ØµÛ (ÙÙØ· Ù
Ù)",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export interface NoteRevisionDto {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string | null;
|
|
|
|
|
body: string;
|
|
|
|
|
noteType: string;
|
|
|
|
|
visibility: NoteVisibility;
|
|
|
|
|
tags: string[];
|
|
|
|
|
checklist: NoteChecklistItemDto[];
|
|
|
|
|
editor: UserSummaryDto | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateNoteRequest {
|
|
|
|
|
title?: string;
|
|
|
|
|
body: string;
|
|
|
|
|
noteType?: NoteType | string;
|
|
|
|
|
visibility?: NoteVisibility;
|
|
|
|
|
pinned?: boolean;
|
|
|
|
|
color?: string;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
reminderAt?: string | null;
|
|
|
|
|
checklist?: NoteChecklistItemDto[];
|
|
|
|
|
locationText?: string | null;
|
|
|
|
|
analyzeEnabled?: boolean;
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
activityId?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateNoteRequest {
|
|
|
|
|
title?: string | null;
|
|
|
|
|
body?: string;
|
|
|
|
|
noteType?: NoteType | string;
|
|
|
|
|
visibility?: NoteVisibility;
|
|
|
|
|
pinned?: boolean;
|
|
|
|
|
color?: string | null;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
reminderAt?: string | null;
|
|
|
|
|
checklist?: NoteChecklistItemDto[];
|
|
|
|
|
locationText?: string | null;
|
|
|
|
|
analyzeEnabled?: boolean;
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
activityId?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type NoteAiSuggestionStatus =
|
|
|
|
|
| 'pending'
|
|
|
|
|
| 'applied'
|
|
|
|
|
| 'dismissed'
|
|
|
|
|
| 'failed';
|
|
|
|
|
|
|
|
|
|
export type MemorySourceType = 'note' | 'manual';
|
|
|
|
|
|
|
|
|
|
export interface NoteAiNextActionDto {
|
|
|
|
|
title: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
dueAt?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface NoteAiMemoryExtractDto {
|
|
|
|
|
content: string;
|
|
|
|
|
category?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface NoteAiPayloadDto {
|
|
|
|
|
nextAction: NoteAiNextActionDto | null;
|
|
|
|
|
memoryItems: NoteAiMemoryExtractDto[];
|
|
|
|
|
summary?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface NoteAiSuggestionDto {
|
|
|
|
|
id: string;
|
|
|
|
|
noteId: string;
|
|
|
|
|
status: NoteAiSuggestionStatus;
|
|
|
|
|
payload: NoteAiPayloadDto | null;
|
|
|
|
|
errorMessage: string | null;
|
|
|
|
|
analyzedAt: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ApplyNoteAiSuggestionRequest {
|
|
|
|
|
applyNextAction?: boolean;
|
|
|
|
|
memoryIndices?: number[];
|
|
|
|
|
nextAction?: NoteAiNextActionDto;
|
|
|
|
|
memoryItems?: Array<{ index: number; content: string }>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type AskMentoSourceType = 'person' | 'note' | 'activity' | 'deal' | 'memory';
|
|
|
|
|
|
|
|
|
|
export interface AskMentoSourceDto {
|
|
|
|
|
type: AskMentoSourceType;
|
|
|
|
|
id: string;
|
|
|
|
|
label: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AskMentoRequest {
|
|
|
|
|
question: string;
|
|
|
|
|
personId?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AskMentoResponse {
|
|
|
|
|
answer: string;
|
|
|
|
|
sources: AskMentoSourceDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type VoiceCommandIntent = 'create_person' | 'create_activity' | 'none';
|
|
|
|
|
|
|
|
|
|
export interface VoicePersonDraft {
|
|
|
|
|
firstName: string;
|
|
|
|
|
lastName: string;
|
|
|
|
|
mobile: string;
|
|
|
|
|
phone: string;
|
|
|
|
|
email: string;
|
|
|
|
|
website: string;
|
|
|
|
|
referrer: string;
|
|
|
|
|
position: string;
|
|
|
|
|
notes: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface VoiceActivityDraft {
|
|
|
|
|
title: string;
|
|
|
|
|
type: ActivityType;
|
|
|
|
|
description: string;
|
|
|
|
|
dueAt: string | null;
|
|
|
|
|
personName: string;
|
|
|
|
|
personId: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface VoiceCommandDraft {
|
|
|
|
|
intent: VoiceCommandIntent;
|
|
|
|
|
summary: string;
|
|
|
|
|
missing: string[];
|
|
|
|
|
canConfirm: boolean;
|
|
|
|
|
person: VoicePersonDraft | null;
|
|
|
|
|
activity: VoiceActivityDraft | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PersonAiSummaryDto {
|
|
|
|
|
text: string;
|
|
|
|
|
cta: string;
|
|
|
|
|
ctaKind: 'call' | 'activity';
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface MemoryItemDto {
|
|
|
|
|
id: string;
|
|
|
|
|
personId: string;
|
|
|
|
|
content: string;
|
|
|
|
|
sourceType: MemorySourceType;
|
|
|
|
|
sourceId: string | null;
|
|
|
|
|
confirmedBy: UserSummaryDto | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateMemoryItemRequest {
|
|
|
|
|
personId: string;
|
|
|
|
|
content: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateMemoryItemRequest {
|
|
|
|
|
content: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ImportContactsResult {
|
|
|
|
|
created: number;
|
|
|
|
|
skipped: number;
|
|
|
|
|
errors: Array<{ row: number; message: string }>;
|
|
|
|
|
boardId?: string;
|
|
|
|
|
boards?: string[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ExcelFieldOption {
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
required?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ExcelColumnPreview {
|
|
|
|
|
header: string;
|
|
|
|
|
index: number;
|
|
|
|
|
samples: string[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ExcelPreviewResult {
|
|
|
|
|
columns: ExcelColumnPreview[];
|
|
|
|
|
fields: ExcelFieldOption[];
|
|
|
|
|
suggested: Record<string, string>;
|
|
|
|
|
needsMapping: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProductDto {
|
|
|
|
|
id: string;
|
|
|
|
|
kind: "product" | "service";
|
|
|
|
|
name: string;
|
|
|
|
|
sku: string | null;
|
|
|
|
|
description: string | null;
|
|
|
|
|
category: string | null;
|
|
|
|
|
unit: string | null;
|
|
|
|
|
stockQty: number | null;
|
|
|
|
|
brand: string | null;
|
|
|
|
|
model: string | null;
|
|
|
|
|
country: string | null;
|
|
|
|
|
tags: string[];
|
|
|
|
|
unitPrice: number | null;
|
|
|
|
|
currency: string;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateProductRequest {
|
|
|
|
|
kind?: "product" | "service";
|
|
|
|
|
name: string;
|
|
|
|
|
sku?: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
category?: string;
|
|
|
|
|
unit?: string;
|
|
|
|
|
stockQty?: number | null;
|
|
|
|
|
brand?: string;
|
|
|
|
|
model?: string;
|
|
|
|
|
country?: string;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
unitPrice?: number | null;
|
|
|
|
|
currency?: string;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateProductRequest {
|
|
|
|
|
kind?: "product" | "service";
|
|
|
|
|
name?: string;
|
|
|
|
|
sku?: string | null;
|
|
|
|
|
description?: string | null;
|
|
|
|
|
category?: string | null;
|
|
|
|
|
unit?: string | null;
|
|
|
|
|
stockQty?: number | null;
|
|
|
|
|
brand?: string | null;
|
|
|
|
|
model?: string | null;
|
|
|
|
|
country?: string | null;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
unitPrice?: number | null;
|
|
|
|
|
currency?: string;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type StockMovementType =
|
|
|
|
|
| "opening"
|
|
|
|
|
| "purchase"
|
|
|
|
|
| "sale"
|
|
|
|
|
| "credit"
|
|
|
|
|
| "adjustment";
|
|
|
|
|
|
|
|
|
|
export interface InventoryStockRowDto {
|
|
|
|
|
productId: string;
|
|
|
|
|
name: string;
|
|
|
|
|
sku: string | null;
|
|
|
|
|
unit: string | null;
|
|
|
|
|
kind: "product" | "service";
|
|
|
|
|
stockQty: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
unitPrice: number | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface StockMovementDto {
|
|
|
|
|
id: string;
|
|
|
|
|
productId: string;
|
|
|
|
|
productName: string;
|
|
|
|
|
type: StockMovementType;
|
|
|
|
|
quantity: number;
|
|
|
|
|
note: string | null;
|
|
|
|
|
invoiceId: string | null;
|
|
|
|
|
occurredAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface InventorySummaryDto {
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
warehouseName: string | null;
|
|
|
|
|
products: InventoryStockRowDto[];
|
|
|
|
|
cashTotal: number;
|
|
|
|
|
receivablesTotal: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateStockMovementRequest {
|
|
|
|
|
productId: string;
|
|
|
|
|
type: "purchase" | "adjustment";
|
|
|
|
|
quantity: number;
|
|
|
|
|
note?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PartyBalanceDto {
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
personId: string;
|
|
|
|
|
openingAmount: number;
|
|
|
|
|
invoicedAmount: number;
|
|
|
|
|
paidAmount: number;
|
|
|
|
|
balance: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdatePartyOpeningRequest {
|
|
|
|
|
amount: number;
|
|
|
|
|
note?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface DealLineItemDto {
|
|
|
|
|
id: string;
|
|
|
|
|
productId: string | null;
|
|
|
|
|
name: string;
|
|
|
|
|
quantity: number;
|
|
|
|
|
unitPrice: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
position: number;
|
|
|
|
|
lineTotal: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface DealLineItemInput {
|
|
|
|
|
productId?: string | null;
|
|
|
|
|
name: string;
|
|
|
|
|
quantity: number;
|
|
|
|
|
unitPrice: number;
|
|
|
|
|
currency?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type NotificationType =
|
|
|
|
|
| "activity_assigned"
|
|
|
|
|
| "activity_overdue"
|
|
|
|
|
| "activity_reminder"
|
|
|
|
|
| "deal_moved"
|
|
|
|
|
| "note_reminder"
|
|
|
|
|
| "cheque_due"
|
|
|
|
|
| "ticket_assigned"
|
|
|
|
|
| "automation"
|
|
|
|
|
| "system";
|
|
|
|
|
|
|
|
|
|
export interface NotificationDto {
|
|
|
|
|
id: string;
|
|
|
|
|
type: NotificationType | string;
|
|
|
|
|
title: string;
|
|
|
|
|
body: string | null;
|
|
|
|
|
link: string | null;
|
|
|
|
|
entityType: string | null;
|
|
|
|
|
entityId: string | null;
|
|
|
|
|
readAt: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface NotificationsListDto {
|
|
|
|
|
items: NotificationDto[];
|
|
|
|
|
unreadCount: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export const LEAD_FORM_FIELD_TYPES = [
|
|
|
|
|
"text",
|
|
|
|
|
"textarea",
|
|
|
|
|
"email",
|
|
|
|
|
"phone",
|
|
|
|
|
"select",
|
|
|
|
|
"radio",
|
|
|
|
|
"checkbox",
|
|
|
|
|
"date",
|
|
|
|
|
"number",
|
|
|
|
|
"file",
|
|
|
|
|
"rating",
|
|
|
|
|
"heading",
|
|
|
|
|
] as const;
|
|
|
|
|
export type LeadFormFieldType = (typeof LEAD_FORM_FIELD_TYPES)[number];
|
|
|
|
|
|
|
|
|
|
export type LeadFormMapTo =
|
|
|
|
|
| "person.firstName"
|
|
|
|
|
| "person.lastName"
|
|
|
|
|
| "person.fullName"
|
|
|
|
|
| "person.email"
|
|
|
|
|
| "person.mobile"
|
|
|
|
|
| "person.phone"
|
|
|
|
|
| "person.position"
|
|
|
|
|
| "deal.title"
|
|
|
|
|
| "deal.notes"
|
|
|
|
|
| "notes"
|
|
|
|
|
| "custom";
|
|
|
|
|
|
|
|
|
|
export interface LeadFormFieldDto {
|
|
|
|
|
id: string;
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
fieldType: LeadFormFieldType | string;
|
|
|
|
|
required: boolean;
|
|
|
|
|
mapTo: LeadFormMapTo | string;
|
|
|
|
|
position: number;
|
|
|
|
|
placeholder: string | null;
|
|
|
|
|
options: string[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadFormDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
description: string | null;
|
|
|
|
|
publicToken: string;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
createPerson: boolean;
|
|
|
|
|
createDeal: boolean;
|
|
|
|
|
pipelineId: string | null;
|
|
|
|
|
source: string | null;
|
|
|
|
|
thankYouMessage: string | null;
|
|
|
|
|
redirectUrl: string | null;
|
|
|
|
|
assigneeIds: string[];
|
|
|
|
|
submitLabel: string;
|
|
|
|
|
submitColor: string;
|
|
|
|
|
hasCover: boolean;
|
|
|
|
|
fields: LeadFormFieldDto[];
|
|
|
|
|
submissionCount?: number;
|
|
|
|
|
publicPath: string;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadFormFieldInput {
|
|
|
|
|
key?: string;
|
|
|
|
|
label: string;
|
|
|
|
|
fieldType: LeadFormFieldType | string;
|
|
|
|
|
required?: boolean;
|
|
|
|
|
mapTo: LeadFormMapTo | string;
|
|
|
|
|
position?: number;
|
|
|
|
|
placeholder?: string | null;
|
|
|
|
|
options?: string[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateLeadFormRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
description?: string | null;
|
|
|
|
|
createPerson?: boolean;
|
|
|
|
|
createDeal?: boolean;
|
|
|
|
|
pipelineId?: string | null;
|
|
|
|
|
source?: string | null;
|
|
|
|
|
thankYouMessage?: string | null;
|
|
|
|
|
redirectUrl?: string | null;
|
|
|
|
|
assigneeIds?: string[];
|
|
|
|
|
submitLabel?: string;
|
|
|
|
|
submitColor?: string;
|
|
|
|
|
fields?: LeadFormFieldInput[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateLeadFormRequest {
|
|
|
|
|
name?: string;
|
|
|
|
|
description?: string | null;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
createPerson?: boolean;
|
|
|
|
|
createDeal?: boolean;
|
|
|
|
|
pipelineId?: string | null;
|
|
|
|
|
source?: string | null;
|
|
|
|
|
thankYouMessage?: string | null;
|
|
|
|
|
redirectUrl?: string | null;
|
|
|
|
|
assigneeIds?: string[];
|
|
|
|
|
submitLabel?: string;
|
|
|
|
|
submitColor?: string;
|
|
|
|
|
fields?: LeadFormFieldInput[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PublicLeadFormDto {
|
|
|
|
|
name: string;
|
|
|
|
|
description: string | null;
|
|
|
|
|
thankYouMessage: string | null;
|
|
|
|
|
submitLabel: string;
|
|
|
|
|
submitColor: string;
|
|
|
|
|
hasCover: boolean;
|
|
|
|
|
coverPath: string | null;
|
|
|
|
|
fields: Array<{
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
fieldType: LeadFormFieldType | string;
|
|
|
|
|
required: boolean;
|
|
|
|
|
placeholder: string | null;
|
|
|
|
|
options: string[];
|
|
|
|
|
}>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadFormSubmissionDto {
|
|
|
|
|
id: string;
|
|
|
|
|
values: Record<string, string>;
|
|
|
|
|
personId: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SubmitLeadFormRequest {
|
|
|
|
|
values: Record<string, string>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SubmitLeadFormResponse {
|
|
|
|
|
ok: true;
|
|
|
|
|
thankYouMessage: string | null;
|
|
|
|
|
redirectUrl: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type QuoteStatus =
|
|
|
|
|
| "draft"
|
|
|
|
|
| "sent"
|
|
|
|
|
| "accepted"
|
|
|
|
|
| "rejected"
|
|
|
|
|
| "expired";
|
|
|
|
|
|
|
|
|
|
export interface QuoteLineItemDto {
|
|
|
|
|
id: string;
|
|
|
|
|
productId: string | null;
|
|
|
|
|
name: string;
|
|
|
|
|
quantity: number;
|
|
|
|
|
unitPrice: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
position: number;
|
|
|
|
|
lineTotal: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface QuoteDto {
|
|
|
|
|
id: string;
|
|
|
|
|
number: string;
|
|
|
|
|
title: string;
|
|
|
|
|
status: QuoteStatus | string;
|
|
|
|
|
currency: string;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
discountAmount?: number;
|
|
|
|
|
taxPercent?: number;
|
|
|
|
|
issuedAt?: string | null;
|
|
|
|
|
validUntil: string | null;
|
|
|
|
|
totalAmount: number;
|
|
|
|
|
subtotal: number;
|
|
|
|
|
taxAmount: number;
|
|
|
|
|
payableAmount: number;
|
|
|
|
|
person: PersonSummaryDto | null;
|
|
|
|
|
company: CompanySummaryDto | null;
|
|
|
|
|
deal: DealSummaryDto | null;
|
|
|
|
|
owner: UserSummaryDto | null;
|
|
|
|
|
lineItems: QuoteLineItemDto[];
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateQuoteRequest {
|
|
|
|
|
title: string;
|
|
|
|
|
status?: QuoteStatus | string;
|
|
|
|
|
currency?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
discountAmount?: number;
|
|
|
|
|
taxPercent?: number;
|
|
|
|
|
issuedAt?: string | null;
|
|
|
|
|
validityDays?: number;
|
|
|
|
|
validUntil?: string | null;
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
fromDealId?: string | null;
|
|
|
|
|
lineItems?: DealLineItemInput[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateQuoteRequest {
|
|
|
|
|
title?: string;
|
|
|
|
|
status?: QuoteStatus | string;
|
|
|
|
|
currency?: string;
|
|
|
|
|
notes?: string | null;
|
|
|
|
|
discountAmount?: number;
|
|
|
|
|
taxPercent?: number;
|
|
|
|
|
issuedAt?: string | null;
|
|
|
|
|
validUntil?: string | null;
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
lineItems?: DealLineItemInput[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type InvoiceStatus =
|
|
|
|
|
| "draft"
|
|
|
|
|
| "issued"
|
|
|
|
|
| "partially_paid"
|
|
|
|
|
| "paid"
|
|
|
|
|
| "canceled";
|
|
|
|
|
|
|
|
|
|
export type PaymentMethod =
|
|
|
|
|
| "cash"
|
|
|
|
|
| "transfer"
|
|
|
|
|
| "card"
|
|
|
|
|
| "check"
|
|
|
|
|
| "other";
|
|
|
|
|
|
|
|
|
|
export type InstallmentStatus = "pending" | "paid" | "canceled";
|
|
|
|
|
|
|
|
|
|
export interface InvoiceLineItemDto {
|
|
|
|
|
id: string;
|
|
|
|
|
productId: string | null;
|
|
|
|
|
name: string;
|
|
|
|
|
quantity: number;
|
|
|
|
|
unitPrice: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
position: number;
|
|
|
|
|
lineTotal: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type ChequeStatus = "pending" | "cleared" | "bounced";
|
|
|
|
|
export type ChequeDirection = "in" | "out";
|
|
|
|
|
|
|
|
|
|
export interface ChequeDto {
|
|
|
|
|
id: string;
|
|
|
|
|
paymentId: string | null;
|
|
|
|
|
invoiceId: string | null;
|
|
|
|
|
invoiceNumber: string | null;
|
|
|
|
|
invoiceTitle: string | null;
|
|
|
|
|
personId: string | null;
|
|
|
|
|
personName: string | null;
|
|
|
|
|
amount: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
number: string;
|
|
|
|
|
bank: string;
|
|
|
|
|
dueDate: string;
|
|
|
|
|
status: ChequeStatus | string;
|
|
|
|
|
direction: ChequeDirection | string;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
paidAt: string;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ChequeInput {
|
|
|
|
|
number: string;
|
|
|
|
|
bank: string;
|
|
|
|
|
dueDate: string;
|
|
|
|
|
status?: ChequeStatus | string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateChequeRequest {
|
|
|
|
|
personId: string;
|
|
|
|
|
amount: number;
|
|
|
|
|
currency?: string;
|
|
|
|
|
number: string;
|
|
|
|
|
bank: string;
|
|
|
|
|
dueDate: string;
|
|
|
|
|
status?: ChequeStatus | string;
|
|
|
|
|
direction?: ChequeDirection | string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateChequeRequest {
|
|
|
|
|
number?: string;
|
|
|
|
|
bank?: string;
|
|
|
|
|
dueDate?: string;
|
|
|
|
|
status?: ChequeStatus | string;
|
|
|
|
|
notes?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PaymentDto {
|
|
|
|
|
id: string;
|
|
|
|
|
amount: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
method: PaymentMethod | string;
|
|
|
|
|
paidAt: string;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
installmentId: string | null;
|
|
|
|
|
cheque?: ChequeDto | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CommissionEntryDto {
|
|
|
|
|
id: string;
|
|
|
|
|
userId: string;
|
|
|
|
|
userName: string;
|
|
|
|
|
invoiceId: string;
|
|
|
|
|
invoiceNumber: string;
|
|
|
|
|
invoiceTitle: string;
|
|
|
|
|
percent: number;
|
|
|
|
|
amount: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
status: "posted" | "void" | string;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface InvoiceInstallmentDto {
|
|
|
|
|
id: string;
|
|
|
|
|
position: number;
|
|
|
|
|
dueDate: string;
|
|
|
|
|
amount: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
status: InstallmentStatus | string;
|
|
|
|
|
paidAt: string | null;
|
|
|
|
|
paymentId: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface InvoiceDto {
|
|
|
|
|
id: string;
|
|
|
|
|
number: string;
|
|
|
|
|
title: string;
|
|
|
|
|
status: InvoiceStatus | string;
|
|
|
|
|
kind?: "invoice" | "credit";
|
|
|
|
|
currency: string;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
discountAmount?: number;
|
|
|
|
|
taxPercent?: number;
|
|
|
|
|
issuedAt: string | null;
|
|
|
|
|
dueDate: string | null;
|
|
|
|
|
totalAmount: number;
|
|
|
|
|
subtotal: number;
|
|
|
|
|
taxAmount: number;
|
|
|
|
|
payableAmount: number;
|
|
|
|
|
paidAmount: number;
|
|
|
|
|
remainingAmount: number;
|
|
|
|
|
person: PersonSummaryDto | null;
|
|
|
|
|
company: CompanySummaryDto | null;
|
|
|
|
|
deal: DealSummaryDto | null;
|
|
|
|
|
quote: { id: string; number: string; title: string } | null;
|
|
|
|
|
owner: UserSummaryDto | null;
|
|
|
|
|
lineItems: InvoiceLineItemDto[];
|
|
|
|
|
payments: PaymentDto[];
|
|
|
|
|
installments: InvoiceInstallmentDto[];
|
|
|
|
|
commissionPercent?: number | null;
|
|
|
|
|
commissionFixedAmount?: number | null;
|
|
|
|
|
commission?: {
|
|
|
|
|
percent: number;
|
|
|
|
|
amount: number;
|
|
|
|
|
status: string;
|
|
|
|
|
} | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface InvoiceInstallmentInput {
|
|
|
|
|
dueDate: string;
|
|
|
|
|
amount: number;
|
|
|
|
|
currency?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateInvoiceRequest {
|
|
|
|
|
title: string;
|
|
|
|
|
status?: InvoiceStatus | string;
|
|
|
|
|
kind?: "invoice" | "credit";
|
|
|
|
|
currency?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
discountAmount?: number;
|
|
|
|
|
taxPercent?: number;
|
|
|
|
|
issuedAt?: string | null;
|
|
|
|
|
dueDate?: string | null;
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
quoteId?: string | null;
|
|
|
|
|
fromDealId?: string | null;
|
|
|
|
|
fromQuoteId?: string | null;
|
|
|
|
|
lineItems?: DealLineItemInput[];
|
|
|
|
|
installments?: InvoiceInstallmentInput[];
|
|
|
|
|
commissionPercent?: number | null;
|
|
|
|
|
commissionFixedAmount?: number | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateInvoiceRequest {
|
|
|
|
|
title?: string;
|
|
|
|
|
status?: InvoiceStatus | string;
|
|
|
|
|
kind?: "invoice" | "credit";
|
|
|
|
|
currency?: string;
|
|
|
|
|
notes?: string | null;
|
|
|
|
|
discountAmount?: number;
|
|
|
|
|
taxPercent?: number;
|
|
|
|
|
issuedAt?: string | null;
|
|
|
|
|
dueDate?: string | null;
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
quoteId?: string | null;
|
|
|
|
|
lineItems?: DealLineItemInput[];
|
|
|
|
|
installments?: InvoiceInstallmentInput[];
|
|
|
|
|
commissionPercent?: number | null;
|
|
|
|
|
commissionFixedAmount?: number | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreatePaymentRequest {
|
|
|
|
|
amount: number;
|
|
|
|
|
currency?: string;
|
|
|
|
|
method?: PaymentMethod | string;
|
|
|
|
|
paidAt?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
installmentId?: string | null;
|
|
|
|
|
cheque?: ChequeInput;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type SalesGoalType =
|
|
|
|
|
| "sales"
|
|
|
|
|
| "customer"
|
|
|
|
|
| "revenue"
|
|
|
|
|
| "deal"
|
|
|
|
|
| "activity"
|
|
|
|
|
| "quality";
|
|
|
|
|
|
|
|
|
|
export type SalesGoalStatus = "in_progress" | "completed" | "needs_attention";
|
|
|
|
|
|
|
|
|
|
export interface SalesGoalDto {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
type: SalesGoalType | string;
|
|
|
|
|
periodStart: string;
|
|
|
|
|
periodEnd: string;
|
|
|
|
|
targetAmount: number;
|
|
|
|
|
forecastAmount: number | null;
|
|
|
|
|
probability: number | null;
|
|
|
|
|
currency: string;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
user: UserSummaryDto | null;
|
|
|
|
|
currentAmount: number;
|
|
|
|
|
progressPercent: number;
|
|
|
|
|
status: SalesGoalStatus;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateSalesGoalRequest {
|
|
|
|
|
title: string;
|
|
|
|
|
periodStart: string;
|
|
|
|
|
periodEnd: string;
|
|
|
|
|
targetAmount: number;
|
|
|
|
|
type?: SalesGoalType | string;
|
|
|
|
|
forecastAmount?: number | null;
|
|
|
|
|
/** 0-100 */
|
|
|
|
|
probability?: number | null;
|
|
|
|
|
currency?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
/** ÙÙØ· Ù
اÙÚ©/Ù
Ø¯ÛØ±Ø در ØºÛØ± اÛÙ ØµÙØ±Øª ÙØ¯Ù Ø¨Ø±Ø§Û Ø®ÙØ¯ کاربر */
|
|
|
|
|
userId?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateSalesGoalRequest {
|
|
|
|
|
title?: string;
|
|
|
|
|
periodStart?: string;
|
|
|
|
|
periodEnd?: string;
|
|
|
|
|
targetAmount?: number;
|
|
|
|
|
type?: SalesGoalType | string;
|
|
|
|
|
forecastAmount?: number | null;
|
|
|
|
|
/** 0-100 */
|
|
|
|
|
probability?: number | null;
|
|
|
|
|
currency?: string;
|
|
|
|
|
notes?: string | null;
|
|
|
|
|
userId?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SalesForecastKpiDto {
|
|
|
|
|
key: "sales" | "customer" | "deal" | "forecast";
|
|
|
|
|
label: string;
|
|
|
|
|
current: number;
|
|
|
|
|
target: number;
|
|
|
|
|
percent: number;
|
|
|
|
|
unit: "money" | "count";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SalesForecastDto {
|
|
|
|
|
periodStart: string;
|
|
|
|
|
periodEnd: string;
|
|
|
|
|
currency: string;
|
|
|
|
|
/** Ù
جÙ
ÙØ¹ Ø§ÙØ¯Ø§Ù ÙÙ
âÙ¾ÙØ´Ø§Ù با باز٠*/
|
|
|
|
|
targetAmount: number;
|
|
|
|
|
/** Ù
عاÙ
ÙØ§Øª Ø¨Ø±ÙØ¯ÙâØ´Ø¯Ù Ø¯Ø± باز٠*/
|
|
|
|
|
wonAmount: number;
|
|
|
|
|
/** Ù
عاÙ
ÙØ§Øª باز ÙØ¹ÙÛ */
|
|
|
|
|
openPipelineAmount: number;
|
|
|
|
|
/** Ù¾ÛØ´âبÛÙÛ: تØÙÙ + Ú©Ø§Ø±ÛØ² باز à Ù
ÛØ§ÙÚ¯ÛÙ Ø§ØØªÙ
ا٠*/
|
|
|
|
|
forecastAmount: number;
|
|
|
|
|
progressPercent: number | null;
|
|
|
|
|
openDealsCount: number;
|
|
|
|
|
wonDealsCount: number;
|
|
|
|
|
goals: SalesGoalDto[];
|
|
|
|
|
kpis: SalesForecastKpiDto[];
|
|
|
|
|
newCustomersCount: number;
|
|
|
|
|
/** Ù
عاÙ
ÙØ§Øª Ø§ÛØ¬Ø§Ø¯Ø´Ø¯Ù در باز٠*/
|
|
|
|
|
newDealsCount: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type TicketStatus =
|
|
|
|
|
| "open"
|
|
|
|
|
| "in_progress"
|
|
|
|
|
| "waiting"
|
|
|
|
|
| "resolved"
|
|
|
|
|
| "closed";
|
|
|
|
|
|
|
|
|
|
export type TicketPriority = "low" | "normal" | "high" | "urgent";
|
|
|
|
|
|
|
|
|
|
export interface TicketMessageDto {
|
|
|
|
|
id: string;
|
|
|
|
|
body: string;
|
|
|
|
|
isInternal: boolean;
|
|
|
|
|
author: UserSummaryDto | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface TicketDto {
|
|
|
|
|
id: string;
|
|
|
|
|
number: string;
|
|
|
|
|
subject: string;
|
|
|
|
|
description: string | null;
|
|
|
|
|
status: TicketStatus | string;
|
|
|
|
|
priority: TicketPriority | string;
|
|
|
|
|
person: PersonSummaryDto | null;
|
|
|
|
|
company: CompanySummaryDto | null;
|
|
|
|
|
deal: DealSummaryDto | null;
|
|
|
|
|
assignee: UserSummaryDto | null;
|
|
|
|
|
reporter: UserSummaryDto | null;
|
|
|
|
|
resolvedAt: string | null;
|
|
|
|
|
slaDueAt: string | null;
|
|
|
|
|
firstRespondedAt: string | null;
|
|
|
|
|
slaBreached: boolean;
|
|
|
|
|
csatScore: number | null;
|
|
|
|
|
csatComment: string | null;
|
|
|
|
|
csatAt: string | null;
|
|
|
|
|
messages: TicketMessageDto[];
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateTicketRequest {
|
|
|
|
|
subject: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
status?: TicketStatus | string;
|
|
|
|
|
priority?: TicketPriority | string;
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
assigneeId?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateTicketRequest {
|
|
|
|
|
subject?: string;
|
|
|
|
|
description?: string | null;
|
|
|
|
|
status?: TicketStatus | string;
|
|
|
|
|
priority?: TicketPriority | string;
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
assigneeId?: string | null;
|
|
|
|
|
csatScore?: number | null;
|
|
|
|
|
csatComment?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateTicketMessageRequest {
|
|
|
|
|
body: string;
|
|
|
|
|
isInternal?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface FaqArticleDto {
|
|
|
|
|
id: string;
|
|
|
|
|
question: string;
|
|
|
|
|
answer: string;
|
|
|
|
|
category: string | null;
|
|
|
|
|
isPublished: boolean;
|
|
|
|
|
position: number;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateFaqArticleRequest {
|
|
|
|
|
question: string;
|
|
|
|
|
answer: string;
|
|
|
|
|
category?: string;
|
|
|
|
|
isPublished?: boolean;
|
|
|
|
|
position?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateFaqArticleRequest {
|
|
|
|
|
question?: string;
|
|
|
|
|
answer?: string;
|
|
|
|
|
category?: string | null;
|
|
|
|
|
isPublished?: boolean;
|
|
|
|
|
position?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** ساعات Ù
ÙÙØª پاسخ اÙ٠بر اساس اÙÙÙÛØª */
|
|
|
|
|
export const TICKET_SLA_HOURS: Record<TicketPriority, number> = {
|
|
|
|
|
urgent: 4,
|
|
|
|
|
high: 8,
|
|
|
|
|
normal: 24,
|
|
|
|
|
low: 48,
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/* âââ پرتا٠Ù
Ø´ØªØ±Û (OTP) âââ */
|
|
|
|
|
|
|
|
|
|
export interface PortalOrgInfoDto {
|
|
|
|
|
name: string;
|
|
|
|
|
slug: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PortalRequestOtpRequest {
|
|
|
|
|
mobile: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PortalRequestOtpResponse {
|
|
|
|
|
ok: true;
|
|
|
|
|
/** ÙÙØ· در ØØ§Ùت ØªÙØ³Ø¹Ù / دÙ
Ù ÙÙØªÛ SMS ÙØ§ÙØ¹Û ÙØµÙ ÙÛØ³Øª */
|
|
|
|
|
devCode?: string;
|
|
|
|
|
expiresInSeconds: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PortalVerifyOtpRequest {
|
|
|
|
|
mobile: string;
|
|
|
|
|
code: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PortalPersonDto {
|
|
|
|
|
id: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
mobile: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PortalLoginResponse {
|
|
|
|
|
accessToken: string;
|
|
|
|
|
person: PortalPersonDto;
|
|
|
|
|
organization: PortalOrgInfoDto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PortalCreateTicketRequest {
|
|
|
|
|
subject: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
priority?: TicketPriority | string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PortalCreateMessageRequest {
|
|
|
|
|
body: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PortalCsatRequest {
|
|
|
|
|
csatScore: number;
|
|
|
|
|
csatComment?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PortalTicketDto {
|
|
|
|
|
id: string;
|
|
|
|
|
number: string;
|
|
|
|
|
subject: string;
|
|
|
|
|
description: string | null;
|
|
|
|
|
status: TicketStatus | string;
|
|
|
|
|
priority: TicketPriority | string;
|
|
|
|
|
resolvedAt: string | null;
|
|
|
|
|
csatScore: number | null;
|
|
|
|
|
csatComment: string | null;
|
|
|
|
|
messages: Array<{
|
|
|
|
|
id: string;
|
|
|
|
|
body: string;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
fromStaff: boolean;
|
|
|
|
|
}>;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* âââ گزارشات Ù Ø¯Ø§Ø´Ø¨ÙØ±Ø¯ âââ */
|
|
|
|
|
|
|
|
|
|
export interface ReportsKpiDto {
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
value: number;
|
|
|
|
|
format: "money" | "number";
|
|
|
|
|
changePercent: number | null;
|
|
|
|
|
changeLabel: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportsSeriesPointDto {
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
value: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportsSliceDto {
|
|
|
|
|
label: string;
|
|
|
|
|
count: number;
|
|
|
|
|
percent: number;
|
|
|
|
|
amount?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportsTopProductDto {
|
|
|
|
|
name: string;
|
|
|
|
|
quantity: number;
|
|
|
|
|
amount: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportsTeamRowDto {
|
|
|
|
|
userId: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
wonAmount: number;
|
|
|
|
|
wonCount: number;
|
|
|
|
|
activitiesDone: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Ú¯ÙÙÙâÙØ§Û drill-down گزارش عÙ
ÛÙ (ÙØ§Ø² Û± BI) */
|
|
|
|
|
export type ReportsDrillKind =
|
|
|
|
|
| "stage_open"
|
|
|
|
|
| "team_won"
|
|
|
|
|
| "period_won"
|
|
|
|
|
| "period_lost"
|
|
|
|
|
| "source"
|
|
|
|
|
| "lost_reason";
|
|
|
|
|
|
|
|
|
|
export const REPORTS_DRILL_KINDS: ReportsDrillKind[] = [
|
|
|
|
|
"stage_open",
|
|
|
|
|
"team_won",
|
|
|
|
|
"period_won",
|
|
|
|
|
"period_lost",
|
|
|
|
|
"source",
|
|
|
|
|
"lost_reason",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export interface ReportsFunnelStageDto {
|
|
|
|
|
stageId: string;
|
|
|
|
|
stageName: string;
|
|
|
|
|
pipelineId: string;
|
|
|
|
|
pipelineName: string;
|
|
|
|
|
count: number;
|
|
|
|
|
amount: number;
|
|
|
|
|
/** درصد تبدÛÙ ÙØ³Ø¨Øª ب٠Ù
رØÙÙ ÙØ¨Ù ÙÙ
Ø§Ù Ú©Ø§Ø±ÛØ²Ø null Ø¨Ø±Ø§Û Ø§ÙÙÛÙ Ù
رØÙÙ */
|
|
|
|
|
conversionFromPrevPercent: number | null;
|
|
|
|
|
/** سÙÙ
از Ú©Ù Ù
عاÙ
ÙØ§Øª باز ÙÙ
Ø§Ù Ú©Ø§Ø±ÛØ² */
|
|
|
|
|
shareOfPipelinePercent: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** ÛÚ© ردÛÙ ÙØ±Ø® تبدÛÙ (ÙØ±ÙØ¯Û â Ù
ÙÙÙ) Ù
Ø«Ù Ø¯ÛØ¯Ø§Ø± */
|
|
|
|
|
export interface ReportsConversionRateRowDto {
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
incomingCount: number;
|
|
|
|
|
wonCount: number;
|
|
|
|
|
/** Ø¯Ø±ØµØ¯Ø Ø§Ú¯Ø± ÙØ±ÙØ¯Û ØµÙØ± باشد Û° */
|
|
|
|
|
conversionPercent: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
|
* ÙØ±Ø® تبدÛ٠ب٠سبک Ø¯ÛØ¯Ø§Ø±:
|
|
|
|
|
* از Ù
عاÙ
ÙØ§Øª تازÙâØ³Ø§Ø®ØªÙâØ´Ø¯Ù Ø¯Ø± Ø¨Ø§Ø²ÙØ ÚÙØ¯ درصد Ø§ÙØ§Ù Ø¨Ø±ÙØ¯Ù شدÙâØ§ÙØ¯.
|
|
|
|
|
*/
|
|
|
|
|
export interface ReportsConversionRateDto {
|
|
|
|
|
incomingCount: number;
|
|
|
|
|
wonCount: number;
|
|
|
|
|
conversionPercent: number;
|
|
|
|
|
previousIncomingCount: number;
|
|
|
|
|
previousWonCount: number;
|
|
|
|
|
previousConversionPercent: number;
|
|
|
|
|
changePercent: number | null;
|
|
|
|
|
byTime: ReportsConversionRateRowDto[];
|
|
|
|
|
byUser: ReportsConversionRateRowDto[];
|
|
|
|
|
bySource: ReportsConversionRateRowDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportsPeriodCompareRowDto {
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
format: "money" | "number" | "percent";
|
|
|
|
|
current: number;
|
|
|
|
|
previous: number;
|
|
|
|
|
changePercent: number | null;
|
|
|
|
|
/** اگر ÙØ§Ø¨Ù Ú©ÙÛÚ© Ø¨Ø±Ø§Û ÙÛØ³Øª پرÙÙØ¯Ù باشد */
|
|
|
|
|
drillKind?: ReportsDrillKind;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportsDrillItemDto {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
status: string;
|
|
|
|
|
statusLabel: string;
|
|
|
|
|
amount: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
ownerName: string | null;
|
|
|
|
|
stageName: string | null;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
link: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportsDrilldownDto {
|
|
|
|
|
kind: ReportsDrillKind;
|
|
|
|
|
title: string;
|
|
|
|
|
from: string;
|
|
|
|
|
to: string;
|
|
|
|
|
total: number;
|
|
|
|
|
items: ReportsDrillItemDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportsDashboardDto {
|
|
|
|
|
from: string;
|
|
|
|
|
to: string;
|
|
|
|
|
currency: string;
|
|
|
|
|
kpis: ReportsKpiDto[];
|
|
|
|
|
salesTrend: ReportsSeriesPointDto[];
|
|
|
|
|
monthlyComparison: ReportsSeriesPointDto[];
|
|
|
|
|
customerGrowth: ReportsSeriesPointDto[];
|
|
|
|
|
sources: ReportsSliceDto[];
|
|
|
|
|
lostReasons: ReportsSliceDto[];
|
|
|
|
|
salesByCategory: ReportsSliceDto[];
|
|
|
|
|
topProducts: ReportsTopProductDto[];
|
|
|
|
|
customerStatus: ReportsSliceDto[];
|
|
|
|
|
activities: {
|
|
|
|
|
open: number;
|
|
|
|
|
done: number;
|
|
|
|
|
overdue: number;
|
|
|
|
|
byType: Array<{ type: string; label: string; count: number }>;
|
|
|
|
|
};
|
|
|
|
|
team: ReportsTeamRowDto[];
|
|
|
|
|
insights: string[];
|
|
|
|
|
sales: {
|
|
|
|
|
openCount: number;
|
|
|
|
|
wonCount: number;
|
|
|
|
|
lostCount: number;
|
|
|
|
|
openAmount: number;
|
|
|
|
|
wonAmount: number;
|
|
|
|
|
lostAmount: number;
|
|
|
|
|
winRate: number;
|
|
|
|
|
};
|
|
|
|
|
funnel: ReportsFunnelStageDto[];
|
|
|
|
|
/** ÙØ±Ø® تبدÛÙ ÙØ±ÙدÛâÙ
ÙÙÙ (سبک Ø¯ÛØ¯Ø§Ø±) */
|
|
|
|
|
conversionRate: ReportsConversionRateDto;
|
|
|
|
|
/** Ù
ÙØ§ÛØ³Ù ØµØ±ÛØ Ø¨Ø§Ø²Ù ÙØ¹ÙÛ Ø¨Ø§ Ø¯ÙØ±Ù ÙØ¨Ù ÙÙ
âØ·ÙÙ */
|
|
|
|
|
periodCompare: ReportsPeriodCompareRowDto[];
|
|
|
|
|
tickets: {
|
|
|
|
|
open: number;
|
|
|
|
|
resolved: number;
|
|
|
|
|
closed: number;
|
|
|
|
|
slaBreached: number;
|
|
|
|
|
avgCsat: number | null;
|
|
|
|
|
csatCount: number;
|
|
|
|
|
};
|
|
|
|
|
peopleCreated: number;
|
|
|
|
|
invoiceCount: number;
|
|
|
|
|
invoiceAmount: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface HomeDashboardKpiDto {
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
value: number;
|
|
|
|
|
changePercent: number | null;
|
|
|
|
|
changeLabel: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface HomeDashboardAlertDto {
|
|
|
|
|
key: string;
|
|
|
|
|
tone: 'urgent' | 'warning' | 'success' | 'info';
|
|
|
|
|
text: string;
|
|
|
|
|
link?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface HomeDashboardTrendPointDto {
|
|
|
|
|
monthKey: string;
|
|
|
|
|
monthLabel: string;
|
|
|
|
|
amount: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface HomeDashboardSourceDto {
|
|
|
|
|
label: string;
|
|
|
|
|
count: number;
|
|
|
|
|
percent: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface HomeDashboardTopCustomerDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
dealCount: number;
|
|
|
|
|
rank: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface HomeDashboardDto {
|
|
|
|
|
currency: string;
|
|
|
|
|
kpis: HomeDashboardKpiDto[];
|
|
|
|
|
alerts: HomeDashboardAlertDto[];
|
|
|
|
|
salesTrend: HomeDashboardTrendPointDto[];
|
|
|
|
|
sources: HomeDashboardSourceDto[];
|
|
|
|
|
topCustomers: HomeDashboardTopCustomerDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** برد پرÙÚÙ / Ú©Ø§Ø±ÛØ² کارت */
|
|
|
|
|
export interface ProjectBoardStageDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
position: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProjectBoardDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
isDefault: boolean;
|
|
|
|
|
stages: ProjectBoardStageDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProjectCardDto {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
position: number;
|
|
|
|
|
boardId: string;
|
|
|
|
|
stageId: string;
|
|
|
|
|
tags: string[];
|
|
|
|
|
person: PersonSummaryDto | null;
|
|
|
|
|
company: CompanySummaryDto | null;
|
|
|
|
|
deal: { id: string; title: string } | null;
|
|
|
|
|
owner: UserSummaryDto | null;
|
|
|
|
|
assignees: UserSummaryDto[];
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProjectBoardColumnDto extends ProjectBoardStageDto {
|
|
|
|
|
cards: ProjectCardDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ProjectBoardBoardDto {
|
|
|
|
|
board: ProjectBoardDto;
|
|
|
|
|
stages: ProjectBoardColumnDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateProjectBoardRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateProjectCardRequest {
|
|
|
|
|
title: string;
|
|
|
|
|
boardId?: string;
|
|
|
|
|
stageId?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
tags?: string[];
|
|
|
|
|
personId?: string | null;
|
|
|
|
|
companyId?: string | null;
|
|
|
|
|
dealId?: string | null;
|
|
|
|
|
ownerId?: string | null;
|
|
|
|
|
assigneeIds?: string[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateProjectCardRequest = Partial<CreateProjectCardRequest>;
|
|
|
|
|
|
|
|
|
|
export interface MoveProjectCardRequest {
|
|
|
|
|
stageId: string;
|
|
|
|
|
position?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** باشگا٠Ù
Ø´ØªØ±ÛØ§Ù */
|
|
|
|
|
export interface LoyaltyTierDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
minPoints: number;
|
|
|
|
|
position: number;
|
|
|
|
|
color: string | null;
|
|
|
|
|
memberCount?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateLoyaltyTierRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
minPoints: number;
|
|
|
|
|
color?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateLoyaltyTierRequest = Partial<CreateLoyaltyTierRequest>;
|
|
|
|
|
|
|
|
|
|
export interface AdjustLoyaltyPointsRequest {
|
|
|
|
|
delta: number;
|
|
|
|
|
reason?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoyaltyMemberDto {
|
|
|
|
|
id: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
mobile: string | null;
|
|
|
|
|
email: string | null;
|
|
|
|
|
loyaltyPoints: number;
|
|
|
|
|
loyaltyTier: LoyaltyTierSummaryDto | null;
|
|
|
|
|
company: CompanySummaryDto | null;
|
|
|
|
|
lastActivityAt: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoyaltyStatsDto {
|
|
|
|
|
memberCount: number;
|
|
|
|
|
memberDeltaPct: number | null;
|
|
|
|
|
pointsIssued: number;
|
|
|
|
|
pointsIssuedDeltaPct: number | null;
|
|
|
|
|
rewardsUsed: number;
|
|
|
|
|
rewardsUsedDeltaPct: number | null;
|
|
|
|
|
retentionRate: number;
|
|
|
|
|
retentionDeltaPct: number | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoyaltySettingsDto {
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
welcomePoints: number;
|
|
|
|
|
notifyOnAdjust: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateLoyaltySettingsRequest = Partial<LoyaltySettingsDto>;
|
|
|
|
|
|
|
|
|
|
export interface LoyaltyRewardDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
description: string | null;
|
|
|
|
|
pointsCost: number;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
position: number;
|
|
|
|
|
color: string | null;
|
|
|
|
|
redemptionCount?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateLoyaltyRewardRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
description?: string | null;
|
|
|
|
|
pointsCost: number;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
color?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateLoyaltyRewardRequest = Partial<CreateLoyaltyRewardRequest>;
|
|
|
|
|
|
|
|
|
|
export interface LoyaltyLedgerDto {
|
|
|
|
|
id: string;
|
|
|
|
|
delta: number;
|
|
|
|
|
reason: string | null;
|
|
|
|
|
source: string;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface BulkAdjustLoyaltyRequest {
|
|
|
|
|
personIds: string[];
|
|
|
|
|
delta: number;
|
|
|
|
|
reason?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoyaltyMessageRequest {
|
|
|
|
|
personIds: string[];
|
|
|
|
|
text: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LoyaltyMessageResult {
|
|
|
|
|
sent: number;
|
|
|
|
|
skipped: number;
|
|
|
|
|
failed: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface RedeemLoyaltyRewardRequest {
|
|
|
|
|
personId: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** اتÙÙ
اسÛÙ٠اگر/Ø¢Ùگا٠*/
|
|
|
|
|
export type AutomationTrigger =
|
|
|
|
|
| "person_created"
|
|
|
|
|
| "lead_submitted"
|
|
|
|
|
| "deal_created"
|
|
|
|
|
| "deal_stage_changed"
|
|
|
|
|
| "deal_won"
|
|
|
|
|
| "deal_lost"
|
|
|
|
|
| "ticket_created"
|
|
|
|
|
| "ticket_resolved"
|
|
|
|
|
| "invoice_issued"
|
|
|
|
|
| "invoice_paid"
|
|
|
|
|
| "activity_done";
|
|
|
|
|
export type AutomationAction =
|
|
|
|
|
| "create_activity"
|
|
|
|
|
| "create_notification"
|
|
|
|
|
| "add_loyalty_points";
|
|
|
|
|
|
|
|
|
|
export const AUTOMATION_TRIGGER_LABELS: Record<AutomationTrigger, string> = {
|
|
|
|
|
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<AutomationAction, string> = {
|
|
|
|
|
create_activity: "ساخت ÙØ¹Ø§ÙÛØª",
|
|
|
|
|
create_notification: "Ø§Ø±Ø³Ø§Ù Ø§Ø¹ÙØ§Ù",
|
|
|
|
|
add_loyalty_points: "Ø§ÙØ²Ùد٠اÙ
ØªÛØ§Ø² باشگاÙ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const MAX_AUTOMATION_STEPS = 8;
|
|
|
|
|
|
|
|
|
|
export const AUTOMATION_ACTIONS = [
|
|
|
|
|
"create_activity",
|
|
|
|
|
"create_notification",
|
|
|
|
|
"add_loyalty_points",
|
|
|
|
|
] as const satisfies readonly AutomationAction[];
|
|
|
|
|
|
|
|
|
|
export const AUTOMATION_TRIGGERS = [
|
|
|
|
|
"person_created",
|
|
|
|
|
"lead_submitted",
|
|
|
|
|
"deal_created",
|
|
|
|
|
"deal_stage_changed",
|
|
|
|
|
"deal_won",
|
|
|
|
|
"deal_lost",
|
|
|
|
|
"ticket_created",
|
|
|
|
|
"ticket_resolved",
|
|
|
|
|
"invoice_issued",
|
|
|
|
|
"invoice_paid",
|
|
|
|
|
"activity_done",
|
|
|
|
|
] as const satisfies readonly AutomationTrigger[];
|
|
|
|
|
|
|
|
|
|
export const AUTOMATION_TRIGGER_GROUPS: {
|
|
|
|
|
label: string;
|
|
|
|
|
items: AutomationTrigger[];
|
|
|
|
|
}[] = [
|
|
|
|
|
{ label: "Ù
خاطب", items: ["person_created", "lead_submitted"] },
|
|
|
|
|
{
|
|
|
|
|
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"] },
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export type AutomationStepKind = "action" | "condition";
|
|
|
|
|
|
|
|
|
|
export type AutomationConditionField =
|
|
|
|
|
| "deal_amount"
|
|
|
|
|
| "has_person"
|
|
|
|
|
| "has_company"
|
|
|
|
|
| "ticket_priority";
|
|
|
|
|
|
|
|
|
|
export type AutomationConditionOp =
|
|
|
|
|
| "gte"
|
|
|
|
|
| "lte"
|
|
|
|
|
| "eq"
|
|
|
|
|
| "neq"
|
|
|
|
|
| "is_set"
|
|
|
|
|
| "is_empty";
|
|
|
|
|
|
|
|
|
|
export type AutomationNotifyChannel = "app" | "sms" | "both";
|
|
|
|
|
export type AutomationNotifyTarget = "staff" | "person";
|
|
|
|
|
|
|
|
|
|
export const AUTOMATION_CONDITION_FIELD_LABELS: Record<
|
|
|
|
|
AutomationConditionField,
|
|
|
|
|
string
|
|
|
|
|
> = {
|
|
|
|
|
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: "ÙØ¯Ø§Ø±Ø¯",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const AUTOMATION_NOTIFY_CHANNEL_LABELS: Record<
|
|
|
|
|
AutomationNotifyChannel,
|
|
|
|
|
string
|
|
|
|
|
> = {
|
|
|
|
|
app: "ÙØ§ØªÛÙÛÚ©ÛØ´Ù داخÙÛ",
|
|
|
|
|
sms: "Ù¾ÛØ§Ù
Ú©",
|
|
|
|
|
both: "ÙØ± دÙ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const AUTOMATION_NOTIFY_CHANNELS = [
|
|
|
|
|
"app",
|
|
|
|
|
"sms",
|
|
|
|
|
"both",
|
|
|
|
|
] as const satisfies readonly AutomationNotifyChannel[];
|
|
|
|
|
|
|
|
|
|
export function isAutomationCondition(step: Pick<AutomationStep, "kind">): boolean {
|
|
|
|
|
return step.kind === "condition";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function firstAutomationAction(
|
|
|
|
|
steps: AutomationStep[],
|
|
|
|
|
): AutomationAction | null {
|
|
|
|
|
const step = steps.find((s) => !isAutomationCondition(s) && s.action);
|
|
|
|
|
return step?.action ?? null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function conditionFieldsForTrigger(
|
|
|
|
|
trigger: AutomationTrigger,
|
|
|
|
|
): AutomationConditionField[] {
|
|
|
|
|
if (
|
|
|
|
|
trigger === "deal_won" ||
|
|
|
|
|
trigger === "deal_lost" ||
|
|
|
|
|
trigger === "deal_created" ||
|
|
|
|
|
trigger === "deal_stage_changed"
|
|
|
|
|
) {
|
|
|
|
|
return ["deal_amount", "has_person", "has_company"];
|
|
|
|
|
}
|
|
|
|
|
if (trigger === "ticket_resolved" || trigger === "ticket_created") {
|
|
|
|
|
return ["ticket_priority", "has_person", "has_company"];
|
|
|
|
|
}
|
|
|
|
|
return ["has_person", "has_company"];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AutomationStep {
|
|
|
|
|
id: string;
|
|
|
|
|
kind?: AutomationStepKind;
|
|
|
|
|
action?: AutomationAction;
|
|
|
|
|
title?: string;
|
|
|
|
|
body?: string;
|
|
|
|
|
assigneeId?: string | null;
|
|
|
|
|
notifyUserId?: string | null;
|
|
|
|
|
notifyChannel?: AutomationNotifyChannel;
|
|
|
|
|
notifyTarget?: AutomationNotifyTarget;
|
|
|
|
|
activityType?: "call" | "meeting" | "task" | "note";
|
|
|
|
|
points?: number;
|
|
|
|
|
conditionField?: AutomationConditionField;
|
|
|
|
|
conditionOp?: AutomationConditionOp;
|
|
|
|
|
conditionValue?: string | number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AutomationRuleConfig {
|
|
|
|
|
title?: string;
|
|
|
|
|
body?: string;
|
|
|
|
|
assigneeId?: string | null;
|
|
|
|
|
notifyUserId?: string | null;
|
|
|
|
|
notifyChannel?: AutomationNotifyChannel;
|
|
|
|
|
notifyTarget?: AutomationNotifyTarget;
|
|
|
|
|
activityType?: "call" | "meeting" | "task" | "note";
|
|
|
|
|
points?: number;
|
|
|
|
|
/** Ø²ÙØ¬ÛرÙ٠اعÙ
Ø§ÙØ اگر خاÙÛ Ø¨Ø§Ø´Ø¯ ÙÙ
ا٠action ØªÚ©Û Ø§Ø³ØªÙØ§Ø¯Ù Ù
ÛâØ´ÙØ¯ */
|
|
|
|
|
steps?: AutomationStep[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AutomationRuleDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
trigger: AutomationTrigger;
|
|
|
|
|
action: AutomationAction;
|
|
|
|
|
config: AutomationRuleConfig;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateAutomationRuleRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
trigger: AutomationTrigger;
|
|
|
|
|
action: AutomationAction;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
config?: AutomationRuleConfig;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateAutomationRuleRequest = Partial<CreateAutomationRuleRequest>;
|
|
|
|
|
|
|
|
|
|
export function normalizeAutomationSteps(
|
|
|
|
|
action: AutomationAction,
|
|
|
|
|
config?: AutomationRuleConfig | null,
|
|
|
|
|
): AutomationStep[] {
|
|
|
|
|
const cfg = config ?? {};
|
|
|
|
|
if (Array.isArray(cfg.steps) && cfg.steps.length) {
|
|
|
|
|
return cfg.steps
|
|
|
|
|
.filter((s) => s && (s.kind === "condition" || s.action))
|
|
|
|
|
.map((s, i) => ({
|
|
|
|
|
id: s.id || `step-${i}`,
|
|
|
|
|
kind: s.kind === "condition" ? "condition" : "action",
|
|
|
|
|
action: s.action,
|
|
|
|
|
title: s.title,
|
|
|
|
|
body: s.body,
|
|
|
|
|
assigneeId: s.assigneeId,
|
|
|
|
|
notifyUserId: s.notifyUserId,
|
|
|
|
|
notifyChannel: s.notifyChannel,
|
|
|
|
|
notifyTarget: s.notifyTarget,
|
|
|
|
|
activityType: s.activityType,
|
|
|
|
|
points: s.points,
|
|
|
|
|
conditionField: s.conditionField,
|
|
|
|
|
conditionOp: s.conditionOp,
|
|
|
|
|
conditionValue: s.conditionValue,
|
|
|
|
|
}));
|
|
|
|
|
}
|
|
|
|
|
return [
|
|
|
|
|
{
|
|
|
|
|
id: "step-0",
|
|
|
|
|
kind: "action",
|
|
|
|
|
action,
|
|
|
|
|
title: cfg.title,
|
|
|
|
|
body: cfg.body,
|
|
|
|
|
assigneeId: cfg.assigneeId,
|
|
|
|
|
notifyUserId: cfg.notifyUserId,
|
|
|
|
|
notifyChannel: cfg.notifyChannel,
|
|
|
|
|
notifyTarget: cfg.notifyTarget,
|
|
|
|
|
activityType: cfg.activityType,
|
|
|
|
|
points: cfg.points,
|
|
|
|
|
},
|
|
|
|
|
];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function packAutomationConfig(steps: AutomationStep[]): AutomationRuleConfig {
|
|
|
|
|
const first =
|
|
|
|
|
steps.find((s) => (s.kind ?? "action") !== "condition") ?? steps[0];
|
|
|
|
|
return {
|
|
|
|
|
steps,
|
|
|
|
|
title: first?.title,
|
|
|
|
|
body: first?.body,
|
|
|
|
|
assigneeId: first?.assigneeId,
|
|
|
|
|
notifyUserId: first?.notifyUserId,
|
|
|
|
|
notifyChannel: first?.notifyChannel,
|
|
|
|
|
notifyTarget: first?.notifyTarget,
|
|
|
|
|
activityType: first?.activityType,
|
|
|
|
|
points: first?.points,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export function automationStepToConfig(step: AutomationStep): AutomationRuleConfig {
|
|
|
|
|
return {
|
|
|
|
|
title: step.title,
|
|
|
|
|
body: step.body,
|
|
|
|
|
assigneeId: step.assigneeId,
|
|
|
|
|
notifyUserId: step.notifyUserId,
|
|
|
|
|
notifyChannel: step.notifyChannel,
|
|
|
|
|
notifyTarget: step.notifyTarget,
|
|
|
|
|
activityType: step.activityType,
|
|
|
|
|
points: step.points,
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ââ ØªÙâØØ³Ø§Ø¨ / ØØ³Ø§Ø¨Ø¯Ø§Ø±Û ââ
|
|
|
|
|
|
|
|
|
|
export const TAHSAB_SANAD_TYPES = [
|
|
|
|
|
"buy_sale_gold",
|
|
|
|
|
"buy_sale_sekeh",
|
|
|
|
|
"talab_bedehi",
|
|
|
|
|
"vkh_gold",
|
|
|
|
|
"vkh_bank",
|
|
|
|
|
] as const;
|
|
|
|
|
|
|
|
|
|
export type TahesabSanadType = (typeof TAHSAB_SANAD_TYPES)[number];
|
|
|
|
|
|
|
|
|
|
export const TAHSAB_SANAD_LABELS: Record<TahesabSanadType, string> = {
|
|
|
|
|
buy_sale_gold: "Ø®Ø±ÛØ¯/ÙØ±ÙØ´ آبشدÙ",
|
|
|
|
|
buy_sale_sekeh: "Ø®Ø±ÛØ¯/ÙØ±ÙØ´ سکÙ",
|
|
|
|
|
talab_bedehi: "Ø·ÙØ¨/بدÙÛ",
|
|
|
|
|
vkh_gold: "ÙØ§Ø±Ûز/Ø®Ø±ÙØ¬ Ø·ÙØ§",
|
|
|
|
|
vkh_bank: "ÙØ§Ø±Ûز/Ø®Ø±ÙØ¬ باÙÚ©Û",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export interface TahesabConnectionDto {
|
|
|
|
|
id: string;
|
|
|
|
|
organizationId: string;
|
|
|
|
|
provider: string;
|
|
|
|
|
label: string;
|
|
|
|
|
baseUrl: string;
|
|
|
|
|
dbName: string;
|
|
|
|
|
tokenMasked: string;
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
isDefault: boolean;
|
|
|
|
|
allowInsecureTls: boolean;
|
|
|
|
|
lastHealthAt: string | null;
|
|
|
|
|
lastHealthOk: boolean | null;
|
|
|
|
|
lastError: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateTahesabConnectionRequest {
|
|
|
|
|
label: string;
|
|
|
|
|
baseUrl: string;
|
|
|
|
|
dbName: string;
|
|
|
|
|
token: string;
|
|
|
|
|
enabled?: boolean;
|
|
|
|
|
isDefault?: boolean;
|
|
|
|
|
allowInsecureTls?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateTahesabConnectionRequest = Partial<CreateTahesabConnectionRequest>;
|
|
|
|
|
|
|
|
|
|
export interface PersonAccountingLinkDto {
|
|
|
|
|
id: string;
|
|
|
|
|
personId: string;
|
|
|
|
|
connectionId: string;
|
|
|
|
|
moshtariCode: number;
|
|
|
|
|
matchMethod: string;
|
|
|
|
|
linkedAt: string;
|
|
|
|
|
lastBalanceSyncedAt: string | null;
|
|
|
|
|
connectionLabel?: string;
|
|
|
|
|
dbName?: string;
|
|
|
|
|
isDefaultConnection?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface MandehValueDto {
|
|
|
|
|
amount: string | number;
|
|
|
|
|
unit: string;
|
|
|
|
|
status: "بس" | "بد";
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface MandehDetailItemDto {
|
|
|
|
|
Name: string;
|
|
|
|
|
values: MandehValueDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PersonAssetsDto {
|
|
|
|
|
connectionId: string;
|
|
|
|
|
connectionLabel: string;
|
|
|
|
|
dbName: string;
|
|
|
|
|
moshtariCode: number;
|
|
|
|
|
goldBalance: number | null;
|
|
|
|
|
rialBalance: number | null;
|
|
|
|
|
currencyBalance: number | null;
|
|
|
|
|
totalGoldEquiv: number | null;
|
|
|
|
|
mandehDetail: MandehDetailItemDto[];
|
|
|
|
|
fetchedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
// ââ Ù¾ÛØ§Ù
Ø®ÙØ¯Ú©Ø§Ø± (جدا از اتÙÙ
اسÛÙ٠گردش کار) ââ
|
|
|
|
|
|
|
|
|
|
export type MessageAutomationTrigger =
|
|
|
|
|
| "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 type MessageAutomationDelayUnit =
|
|
|
|
|
| "minutes"
|
|
|
|
|
| "hours"
|
|
|
|
|
| "days"
|
|
|
|
|
| "weeks"
|
|
|
|
|
| "months";
|
|
|
|
|
export type MessageAutomationChannel = "app" | "sms" | "both";
|
|
|
|
|
export type MessageAutomationTarget = "staff" | "person" | "both";
|
|
|
|
|
|
|
|
|
|
export const MESSAGE_AUTOMATION_TRIGGERS = [
|
|
|
|
|
"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",
|
|
|
|
|
] as const satisfies readonly MessageAutomationTrigger[];
|
|
|
|
|
|
|
|
|
|
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: "ÙØ¹Ø§ÙÛØª تÙ
اÙ
شد",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const MESSAGE_AUTOMATION_UNIT_LABELS: Record<
|
|
|
|
|
MessageAutomationDelayUnit,
|
|
|
|
|
string
|
|
|
|
|
> = {
|
|
|
|
|
minutes: "دÙÛÙÙ",
|
|
|
|
|
hours: "ساعت",
|
|
|
|
|
days: "Ø±ÙØ²",
|
|
|
|
|
weeks: "ÙÙØªÙ",
|
|
|
|
|
months: "Ù
اÙ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const MESSAGE_AUTOMATION_FIELDS = [
|
|
|
|
|
{ token: "{ÙØ§Ù
}", label: "ÙØ§Ù
Ù
شترÛ" },
|
|
|
|
|
{ token: "{Ø´Ù
ارÙ}", label: "Ø´Ù
ار٠Ù
ÙØ¨Ø§ÛÙ" },
|
|
|
|
|
{ token: "{ØªØ§Ø±ÛØ®}", label: "ØªØ§Ø±ÛØ® ارساÙ" },
|
|
|
|
|
{ token: "{عÙÙØ§Ù}", label: "عÙÙØ§Ù Ø±Ú©ÙØ±Ø¯" },
|
|
|
|
|
{ token: "{شرکت}", label: "ÙØ§Ù
شرکت" },
|
|
|
|
|
] as const;
|
|
|
|
|
|
|
|
|
|
export const MESSAGE_AUTOMATION_SMS_SEGMENT = 70;
|
|
|
|
|
|
|
|
|
|
export const MESSAGE_AUTOMATION_CHANNEL_LABELS: Record<
|
|
|
|
|
MessageAutomationChannel,
|
|
|
|
|
string
|
|
|
|
|
> = {
|
|
|
|
|
app: "ÙØ§ØªÛÙ Ø¯Ø§Ø®Ù Ø¨Ø±ÙØ§Ù
Ù",
|
|
|
|
|
sms: "Ù¾ÛØ§Ù
Ú©",
|
|
|
|
|
both: "Ù¾ÛØ§Ù
Ú© Ù ÙØ§ØªÛÙ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export const MESSAGE_AUTOMATION_TARGET_LABELS: Record<
|
|
|
|
|
MessageAutomationTarget,
|
|
|
|
|
string
|
|
|
|
|
> = {
|
|
|
|
|
staff: "Ù
سئÙ٠پرÙÙØ¯Ù",
|
|
|
|
|
person: "Ù
شترÛ",
|
|
|
|
|
both: "Ù
Ø´ØªØ±Û Ù Ù
سئÙÙ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export interface MessageAutomationRuleDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
trigger: MessageAutomationTrigger;
|
|
|
|
|
startDelayValue: number;
|
|
|
|
|
startDelayUnit: MessageAutomationDelayUnit;
|
|
|
|
|
repeatCount: number;
|
|
|
|
|
intervalValue: number;
|
|
|
|
|
intervalUnit: MessageAutomationDelayUnit;
|
|
|
|
|
notifyTarget: MessageAutomationTarget;
|
|
|
|
|
channel: MessageAutomationChannel;
|
|
|
|
|
title: string;
|
|
|
|
|
description: string | null;
|
|
|
|
|
body: string;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateMessageAutomationRuleRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
trigger: MessageAutomationTrigger;
|
|
|
|
|
startDelayValue?: number;
|
|
|
|
|
startDelayUnit?: MessageAutomationDelayUnit;
|
|
|
|
|
repeatCount?: number;
|
|
|
|
|
intervalValue?: number;
|
|
|
|
|
intervalUnit?: MessageAutomationDelayUnit;
|
|
|
|
|
notifyTarget?: MessageAutomationTarget;
|
|
|
|
|
channel?: MessageAutomationChannel;
|
|
|
|
|
title: string;
|
|
|
|
|
description?: string | null;
|
|
|
|
|
body: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateMessageAutomationRuleRequest =
|
|
|
|
|
Partial<CreateMessageAutomationRuleRequest>;
|
|
|
|
|
|
|
|
|
|
export interface PlatformAdminDto {
|
|
|
|
|
id: string;
|
|
|
|
|
mobile?: string | null;
|
|
|
|
|
email?: string | null;
|
|
|
|
|
fullName: string;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
lastLoginAt?: string | null;
|
|
|
|
|
createdAt?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PlatformLoginRequest {
|
|
|
|
|
mobile: string;
|
|
|
|
|
password: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PlatformLoginResponse {
|
|
|
|
|
accessToken: string;
|
|
|
|
|
admin: PlatformAdminDto;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreatePlatformAdminRequest {
|
|
|
|
|
fullName: string;
|
|
|
|
|
mobile: string;
|
|
|
|
|
password: string;
|
|
|
|
|
email?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ResetPlatformAdminPasswordRequest {
|
|
|
|
|
password: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PlatformStatsDto {
|
|
|
|
|
organizationCount: number;
|
|
|
|
|
activeOrganizationCount: number;
|
|
|
|
|
userCount: number;
|
|
|
|
|
activeUserCount: number;
|
|
|
|
|
membershipCount: number;
|
|
|
|
|
expiringSoonCount?: number;
|
|
|
|
|
expiredBillingCount?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PlatformOrgMemberDto {
|
|
|
|
|
membershipId: string;
|
|
|
|
|
userId: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
email: string;
|
|
|
|
|
mobile?: string | null;
|
|
|
|
|
role: UserRole;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
userIsActive: boolean;
|
|
|
|
|
isBillingOwner?: boolean;
|
|
|
|
|
billing?: BillingAccountDto | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PlatformOrganizationDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
slug: string;
|
|
|
|
|
businessField?: string | null;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
memberCount: number;
|
|
|
|
|
personCount: number;
|
|
|
|
|
dealCount: number;
|
|
|
|
|
enabledModules?: OrgModuleKey[];
|
|
|
|
|
members?: PlatformOrgMemberDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PlatformUserMembershipDto {
|
|
|
|
|
membershipId: string;
|
|
|
|
|
organizationId: string;
|
|
|
|
|
organizationName: string;
|
|
|
|
|
organizationIsActive: boolean;
|
|
|
|
|
role: UserRole;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface PlatformUserDto {
|
|
|
|
|
id: string;
|
|
|
|
|
email: string;
|
|
|
|
|
mobile?: string | null;
|
|
|
|
|
fullName: string;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
lastLoginAt?: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
memberships: PlatformUserMembershipDto[];
|
|
|
|
|
/** ÙÙØ· اگر ØØ¯Ø§ÙÙ ÛÚ© عضÙÛØª Ù
اÙÚ© ÙØ¹Ø§Ù دارد */
|
|
|
|
|
isBillingOwner?: boolean;
|
|
|
|
|
billing?: BillingAccountDto | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdatePlatformStatusRequest {
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreatePlatformOrganizationRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
businessField?: string;
|
|
|
|
|
ownerFullName: string;
|
|
|
|
|
ownerEmail: string;
|
|
|
|
|
ownerPassword: string;
|
|
|
|
|
ownerMobile?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdatePlatformOrganizationRequest {
|
|
|
|
|
name?: string;
|
|
|
|
|
slug?: string;
|
|
|
|
|
businessField?: string | null;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdatePlatformMembershipRoleRequest {
|
|
|
|
|
role: UserRole;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ResetPlatformUserPasswordRequest {
|
|
|
|
|
password: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
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;
|
|
|
|
|
action: string;
|
|
|
|
|
method: string;
|
|
|
|
|
path: string;
|
|
|
|
|
entityType: string | null;
|
|
|
|
|
entityId: string | null;
|
|
|
|
|
summary: string;
|
|
|
|
|
actor: UserSummaryDto | null;
|
|
|
|
|
ip: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AuditLogListResponse {
|
|
|
|
|
items: AuditLogDto[];
|
|
|
|
|
total: number;
|
|
|
|
|
page: number;
|
|
|
|
|
limit: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* âââ ÙÛÙØªØ±ÙØ§Û Ø°Ø®ÛØ±ÙâØ´Ø¯Ù âââ */
|
|
|
|
|
|
|
|
|
|
export type SavedViewScope =
|
|
|
|
|
| "deals"
|
|
|
|
|
| "people"
|
|
|
|
|
| "companies"
|
|
|
|
|
| "activities"
|
|
|
|
|
| "project_cards"
|
|
|
|
|
| "reports";
|
|
|
|
|
|
|
|
|
|
export const SAVED_VIEW_SCOPES: SavedViewScope[] = [
|
|
|
|
|
"deals",
|
|
|
|
|
"people",
|
|
|
|
|
"companies",
|
|
|
|
|
"activities",
|
|
|
|
|
"project_cards",
|
|
|
|
|
"reports",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
/** ÙÛÙØªØ±ÙØ§Û Ø°Ø®ÛØ±ÙâØ´Ø¯ÙÙ ØµÙØÙ Ú¯Ø²Ø§Ø±Ø´Ø§Øª */
|
|
|
|
|
export interface ReportsViewFilters {
|
|
|
|
|
/** today | week | month | quarter | year | custom */
|
|
|
|
|
period: string;
|
|
|
|
|
from?: string;
|
|
|
|
|
to?: string;
|
|
|
|
|
/** dashboard | builder */
|
|
|
|
|
mode?: string;
|
|
|
|
|
builder?: {
|
|
|
|
|
metric?: string;
|
|
|
|
|
dimension?: string;
|
|
|
|
|
userId?: string;
|
|
|
|
|
teamId?: string;
|
|
|
|
|
};
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** Ù
ترÛÚ©âÙØ§Û Ú¯Ø²Ø§Ø±Ø´âØ³Ø§Ø² ساد٠*/
|
|
|
|
|
export type ReportsBuilderMetric =
|
|
|
|
|
| "won_amount"
|
|
|
|
|
| "won_count"
|
|
|
|
|
| "lost_count"
|
|
|
|
|
| "open_count"
|
|
|
|
|
| "open_amount"
|
|
|
|
|
| "activities_done"
|
|
|
|
|
| "people_created"
|
|
|
|
|
| "invoice_amount"
|
|
|
|
|
| "invoice_count";
|
|
|
|
|
|
|
|
|
|
export const REPORTS_BUILDER_METRICS: ReportsBuilderMetric[] = [
|
|
|
|
|
"won_amount",
|
|
|
|
|
"won_count",
|
|
|
|
|
"lost_count",
|
|
|
|
|
"open_count",
|
|
|
|
|
"open_amount",
|
|
|
|
|
"activities_done",
|
|
|
|
|
"people_created",
|
|
|
|
|
"invoice_amount",
|
|
|
|
|
"invoice_count",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
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: "تعداد ÙØ§Ú©ØªÙر",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
/** ابعاد گرÙÙâØ¨ÙØ¯Û Ú¯Ø²Ø§Ø±Ø´âØ³Ø§Ø² */
|
|
|
|
|
export type ReportsBuilderDimension =
|
|
|
|
|
| "none"
|
|
|
|
|
| "owner"
|
|
|
|
|
| "team"
|
|
|
|
|
| "source"
|
|
|
|
|
| "stage"
|
|
|
|
|
| "month"
|
|
|
|
|
| "status";
|
|
|
|
|
|
|
|
|
|
export const REPORTS_BUILDER_DIMENSIONS: ReportsBuilderDimension[] = [
|
|
|
|
|
"none",
|
|
|
|
|
"owner",
|
|
|
|
|
"team",
|
|
|
|
|
"source",
|
|
|
|
|
"stage",
|
|
|
|
|
"month",
|
|
|
|
|
"status",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export const REPORTS_BUILDER_DIMENSION_LABELS: Record<
|
|
|
|
|
ReportsBuilderDimension,
|
|
|
|
|
string
|
|
|
|
|
> = {
|
|
|
|
|
none: "بدÙ٠گرÙÙâØ¨ÙØ¯Û (جÙ
ع Ú©Ù)",
|
|
|
|
|
owner: "کاربر / Ù
سئÙÙ",
|
|
|
|
|
team: "تÛÙ
",
|
|
|
|
|
source: "Ù
ÙØ¨Ø¹",
|
|
|
|
|
stage: "Ù
رØÙÙ Ú©Ø§Ø±ÛØ²",
|
|
|
|
|
month: "Ù
اÙ",
|
|
|
|
|
status: "ÙØ¶Ø¹Ûت Ù
عاÙ
ÙÙ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export interface ReportsBuilderQuery {
|
|
|
|
|
metric: ReportsBuilderMetric;
|
|
|
|
|
dimension: ReportsBuilderDimension;
|
|
|
|
|
from?: string;
|
|
|
|
|
to?: string;
|
|
|
|
|
userId?: string;
|
|
|
|
|
teamId?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportsBuilderRowDto {
|
|
|
|
|
key: string;
|
|
|
|
|
label: string;
|
|
|
|
|
value: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReportsBuilderResultDto {
|
|
|
|
|
metric: ReportsBuilderMetric;
|
|
|
|
|
metricLabel: string;
|
|
|
|
|
dimension: ReportsBuilderDimension;
|
|
|
|
|
dimensionLabel: string;
|
|
|
|
|
from: string;
|
|
|
|
|
to: string;
|
|
|
|
|
currency: string;
|
|
|
|
|
format: "money" | "number";
|
|
|
|
|
total: number;
|
|
|
|
|
rows: ReportsBuilderRowDto[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SavedViewDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
scope: SavedViewScope;
|
|
|
|
|
filters: Record<string, unknown>;
|
|
|
|
|
isShared: boolean;
|
|
|
|
|
owner: UserSummaryDto | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateSavedViewRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
scope: SavedViewScope;
|
|
|
|
|
filters: Record<string, unknown>;
|
|
|
|
|
isShared?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateSavedViewRequest = Partial<CreateSavedViewRequest>;
|
|
|
|
|
|
|
|
|
|
/* âââ API عÙ
ÙÙ
Û Ù ÙØ¨âÙÙÚ© âââ */
|
|
|
|
|
|
|
|
|
|
export const WEBHOOK_EVENTS = [
|
|
|
|
|
"person.created",
|
|
|
|
|
"person.updated",
|
|
|
|
|
"deal.created",
|
|
|
|
|
"deal.updated",
|
|
|
|
|
"deal.won",
|
|
|
|
|
"deal.lost",
|
|
|
|
|
"invoice.paid",
|
|
|
|
|
"activity.created",
|
|
|
|
|
] as const;
|
|
|
|
|
|
|
|
|
|
export type WebhookEvent = (typeof WEBHOOK_EVENTS)[number];
|
|
|
|
|
|
|
|
|
|
export interface OrganizationApiKeyDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
prefix: string;
|
|
|
|
|
lastUsedAt: string | null;
|
|
|
|
|
revokedAt: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateOrganizationApiKeyRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateOrganizationApiKeyResponse extends OrganizationApiKeyDto {
|
|
|
|
|
/** ÙÙØ· ÛÚ©âØ¨Ø§Ø± ÙÙگاÙ
ساخت Ø¨Ø±Ú¯Ø±Ø¯Ø§ÙØ¯Ù Ù
ÛâØ´ÙØ¯ */
|
|
|
|
|
rawKey: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface WebhookEndpointDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
url: string;
|
|
|
|
|
events: string[];
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateWebhookEndpointRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
url: string;
|
|
|
|
|
events: string[];
|
|
|
|
|
secret?: string;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/** ÙÙØ· ÙÙگاÙ
Ø³Ø§Ø®ØªØ secret Ø¯ÙØ¨Ø§Ø±Ù برÙÙ
Ûâگردد */
|
|
|
|
|
export interface CreateWebhookEndpointResponse extends WebhookEndpointDto {
|
|
|
|
|
secret: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateWebhookEndpointRequest = Partial<CreateWebhookEndpointRequest>;
|
|
|
|
|
|
|
|
|
|
export interface WebhookDeliveryDto {
|
|
|
|
|
id: string;
|
|
|
|
|
event: string;
|
|
|
|
|
status: string;
|
|
|
|
|
statusCode: number | null;
|
|
|
|
|
attempts: number;
|
|
|
|
|
lastError: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
deliveredAt: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* âââ Ù¾ÛØ§Ù
Ú© گرÙÙÛ âââ */
|
|
|
|
|
|
|
|
|
|
export type SmsCampaignStatus =
|
|
|
|
|
| "draft"
|
|
|
|
|
| "queued"
|
|
|
|
|
| "sending"
|
|
|
|
|
| "done"
|
|
|
|
|
| "cancelled";
|
|
|
|
|
|
|
|
|
|
export interface SmsCampaignDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
body: string;
|
|
|
|
|
status: SmsCampaignStatus;
|
|
|
|
|
scheduledAt: string | null;
|
|
|
|
|
totalCount: number;
|
|
|
|
|
sentCount: number;
|
|
|
|
|
failedCount: number;
|
|
|
|
|
skippedCount: number;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateSmsCampaignRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
body: string;
|
|
|
|
|
personIds: string[];
|
|
|
|
|
scheduledAt?: string | null;
|
|
|
|
|
/** اگر true باشد Ø¨ÙØ§ÙاصÙ٠ص٠Ù
ÛâØ´ÙØ¯ */
|
|
|
|
|
queueNow?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SmsCampaignListResponse {
|
|
|
|
|
items: SmsCampaignDto[];
|
|
|
|
|
total: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* âââ ØªÛÙ
âÙØ§ Ù Ø³Ø·Ø Ø¯Ø³ØªØ±Ø³Û Ø¨Ù Ù¾Ø±ÙÙØ¯ÙâÙØ§ âââ */
|
|
|
|
|
|
|
|
|
|
export type TeamMemberRole = "member" | "manager";
|
|
|
|
|
|
|
|
|
|
export interface TeamMemberDto {
|
|
|
|
|
userId: string;
|
|
|
|
|
fullName: string;
|
|
|
|
|
role: TeamMemberRole;
|
|
|
|
|
hasAvatar?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface TeamDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
description: string;
|
|
|
|
|
memberCount: number;
|
|
|
|
|
members: TeamMemberDto[];
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateTeamRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
memberIds?: string[];
|
|
|
|
|
managerIds?: string[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateTeamRequest {
|
|
|
|
|
name?: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface SetTeamMembersRequest {
|
|
|
|
|
members: Array<{ userId: string; role: TeamMemberRole }>;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* âââ ÙÙکاÙ
رس âââ */
|
|
|
|
|
|
|
|
|
|
export interface WooCommerceConnectionDto {
|
|
|
|
|
id: string;
|
|
|
|
|
label: string;
|
|
|
|
|
storeUrl: string;
|
|
|
|
|
consumerKeyMasked: string;
|
|
|
|
|
webhookSecretSet: boolean;
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
lastSyncAt: string | null;
|
|
|
|
|
lastHealthAt: string | null;
|
|
|
|
|
lastHealthOk: boolean | null;
|
|
|
|
|
lastError: string | null;
|
|
|
|
|
importedOrders: number;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateWooCommerceConnectionRequest {
|
|
|
|
|
label: string;
|
|
|
|
|
storeUrl: string;
|
|
|
|
|
consumerKey: string;
|
|
|
|
|
consumerSecret: string;
|
|
|
|
|
webhookSecret?: string;
|
|
|
|
|
enabled?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateWooCommerceConnectionRequest {
|
|
|
|
|
label?: string;
|
|
|
|
|
storeUrl?: string;
|
|
|
|
|
consumerKey?: string;
|
|
|
|
|
consumerSecret?: string;
|
|
|
|
|
webhookSecret?: string | null;
|
|
|
|
|
enabled?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface WooCommerceSyncResultDto {
|
|
|
|
|
fetched: number;
|
|
|
|
|
created: number;
|
|
|
|
|
updated: number;
|
|
|
|
|
skipped: number;
|
|
|
|
|
errors: string[];
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface WooCommerceOrderLinkDto {
|
|
|
|
|
id: string;
|
|
|
|
|
wooOrderId: string;
|
|
|
|
|
wooOrderNumber: string | null;
|
|
|
|
|
invoiceId: string;
|
|
|
|
|
invoiceNumber: string;
|
|
|
|
|
status: string;
|
|
|
|
|
total: number;
|
|
|
|
|
currency: string;
|
|
|
|
|
syncedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* âââ ØªÙÙ٠سازÙ
اÙÛ / VoIP âââ */
|
|
|
|
|
|
|
|
|
|
export type VoipCallDirection = "inbound" | "outbound";
|
|
|
|
|
|
|
|
|
|
export type VoipCallStatus =
|
|
|
|
|
| "ringing"
|
|
|
|
|
| "answered"
|
|
|
|
|
| "missed"
|
|
|
|
|
| "completed"
|
|
|
|
|
| "failed";
|
|
|
|
|
|
|
|
|
|
export interface VoipConnectionDto {
|
|
|
|
|
id: string;
|
|
|
|
|
label: string;
|
|
|
|
|
enabled: boolean;
|
|
|
|
|
webhookSecretSet: boolean;
|
|
|
|
|
/** ÙØ§Ùب URL Ø¨Ø±Ø§Û Ø´Ø±ÙØ¹ تÙ
Ø§Ø³Ø {number} جاÛگزÛÙ Ù
ÛâØ´ÙØ¯ */
|
|
|
|
|
clickToCallUrl: string | null;
|
|
|
|
|
lastEventAt: string | null;
|
|
|
|
|
lastError: string | null;
|
|
|
|
|
callCount: number;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateVoipConnectionRequest {
|
|
|
|
|
label: string;
|
|
|
|
|
webhookSecret?: string;
|
|
|
|
|
clickToCallUrl?: string | null;
|
|
|
|
|
enabled?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateVoipConnectionRequest {
|
|
|
|
|
label?: string;
|
|
|
|
|
webhookSecret?: string | null;
|
|
|
|
|
clickToCallUrl?: string | null;
|
|
|
|
|
enabled?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type VoipSummaryStatus =
|
|
|
|
|
| "none"
|
|
|
|
|
| "pending"
|
|
|
|
|
| "processing"
|
|
|
|
|
| "done"
|
|
|
|
|
| "failed"
|
|
|
|
|
| "skipped";
|
|
|
|
|
|
|
|
|
|
export interface VoipCallLogDto {
|
|
|
|
|
id: string;
|
|
|
|
|
direction: VoipCallDirection;
|
|
|
|
|
status: VoipCallStatus | string;
|
|
|
|
|
fromNumber: string | null;
|
|
|
|
|
toNumber: string | null;
|
|
|
|
|
personId: string | null;
|
|
|
|
|
personName: string | null;
|
|
|
|
|
activityId: string | null;
|
|
|
|
|
durationSec: number | null;
|
|
|
|
|
startedAt: string;
|
|
|
|
|
syncedAt: string;
|
|
|
|
|
recordingUrl: string | null;
|
|
|
|
|
transcript: string | null;
|
|
|
|
|
summary: string | null;
|
|
|
|
|
summaryStatus: VoipSummaryStatus | string;
|
|
|
|
|
summaryNoteId: string | null;
|
|
|
|
|
summaryError: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface VoipClickToCallRequest {
|
|
|
|
|
number: string;
|
|
|
|
|
personId?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface VoipWebhookEvent {
|
|
|
|
|
/** Ø´ÙØ§Ø³Ù ÛÚ©ØªØ§Û ØªÙ
اس در Ø³Ø§ÙØªØ±Ø§Ù */
|
|
|
|
|
callId: string;
|
|
|
|
|
direction: VoipCallDirection;
|
|
|
|
|
status: VoipCallStatus | string;
|
|
|
|
|
from?: string;
|
|
|
|
|
to?: string;
|
|
|
|
|
startedAt?: string;
|
|
|
|
|
endedAt?: string;
|
|
|
|
|
durationSec?: number;
|
|
|
|
|
/** ÙÛÙÚ© ÙØ§Û٠ضبط (Ø¨Ø±Ø§Û Ø®ÙØ§ØµÙ Ø®ÙØ¯Ú©Ø§Ø±) */
|
|
|
|
|
recordingUrl?: string;
|
|
|
|
|
/** Ù
ت٠آÙ
ادÙ٠تÙ
Ø§Ø³Ø Ø§Ú¯Ø± باشد STT رد Ù
ÛâØ´ÙØ¯ */
|
|
|
|
|
transcript?: string;
|
|
|
|
|
/** Ø¨Ø±Ø§Û Ø³Ø§Ø²Ú¯Ø§Ø±Û Ø¨Ø§ ÙÛÙØ¯ÙØ§Û Ø±Ø§ÛØ¬ دÛگر */
|
|
|
|
|
caller?: string;
|
|
|
|
|
callee?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/* âââ Ø±Ø²Ø±Ù Ù ÙÙØ¨ØªâدÙÛ âââ */
|
|
|
|
|
|
|
|
|
|
export type ReservationStatus =
|
|
|
|
|
| "pending"
|
|
|
|
|
| "confirmed"
|
|
|
|
|
| "canceled"
|
|
|
|
|
| "done";
|
|
|
|
|
|
|
|
|
|
export const RESERVATION_STATUSES: ReservationStatus[] = [
|
|
|
|
|
"pending",
|
|
|
|
|
"confirmed",
|
|
|
|
|
"canceled",
|
|
|
|
|
"done",
|
|
|
|
|
];
|
|
|
|
|
|
|
|
|
|
export const RESERVATION_STATUS_LABELS: Record<ReservationStatus, string> = {
|
|
|
|
|
pending: "در Ø§ÙØªØ¸Ø§Ø±",
|
|
|
|
|
confirmed: "تأÛÛØ¯ شدÙ",
|
|
|
|
|
canceled: "ÙØºÙ شدÙ",
|
|
|
|
|
done: "Ø§ÙØ¬Ø§Ù
شدÙ",
|
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
export interface ReservationServiceDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
description: string;
|
|
|
|
|
durationMinutes: number;
|
|
|
|
|
/** Ø±ÙØ²ÙØ§Û ÙÙØªÙ Û°=ÛÚ©Ø´ÙØ¨Ù ⦠۶=Ø´ÙØ¨Ù (JS getDay) */
|
|
|
|
|
workDays: number[];
|
|
|
|
|
dayStartHour: number;
|
|
|
|
|
dayEndHour: number;
|
|
|
|
|
isActive: boolean;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateReservationServiceRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
description?: string;
|
|
|
|
|
durationMinutes: number;
|
|
|
|
|
workDays?: number[];
|
|
|
|
|
dayStartHour?: number;
|
|
|
|
|
dayEndHour?: number;
|
|
|
|
|
isActive?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export type UpdateReservationServiceRequest =
|
|
|
|
|
Partial<CreateReservationServiceRequest>;
|
|
|
|
|
|
|
|
|
|
export interface ReservationAppointmentDto {
|
|
|
|
|
id: string;
|
|
|
|
|
serviceId: string;
|
|
|
|
|
serviceName: string;
|
|
|
|
|
personId: string;
|
|
|
|
|
personName: string;
|
|
|
|
|
assigneeId: string | null;
|
|
|
|
|
assigneeName: string | null;
|
|
|
|
|
startsAt: string;
|
|
|
|
|
endsAt: string;
|
|
|
|
|
status: ReservationStatus;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateReservationAppointmentRequest {
|
|
|
|
|
serviceId: string;
|
|
|
|
|
personId: string;
|
|
|
|
|
assigneeId?: string | null;
|
|
|
|
|
startsAt: string;
|
|
|
|
|
status?: ReservationStatus;
|
|
|
|
|
notes?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateReservationAppointmentRequest {
|
|
|
|
|
serviceId?: string;
|
|
|
|
|
personId?: string;
|
|
|
|
|
assigneeId?: string | null;
|
|
|
|
|
startsAt?: string;
|
|
|
|
|
status?: ReservationStatus;
|
|
|
|
|
notes?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReservationSlotDto {
|
|
|
|
|
startsAt: string;
|
|
|
|
|
endsAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ReservationListResponse {
|
|
|
|
|
items: ReservationAppointmentDto[];
|
|
|
|
|
total: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/* âââ Ù
Ø¯ÛØ±Ûت ÙÛØ¯Ùا âââ */
|
|
|
|
|
|
|
|
|
|
export type LeadAssignRule = "round_robin" | "equal_split";
|
|
|
|
|
|
|
|
|
|
export interface LeadStageDto {
|
|
|
|
|
id: string;
|
|
|
|
|
name: string;
|
|
|
|
|
position: number;
|
|
|
|
|
color: string;
|
|
|
|
|
showOnBoard: boolean;
|
|
|
|
|
isConverted: boolean;
|
|
|
|
|
isLost: boolean;
|
|
|
|
|
isUnqualified: boolean;
|
|
|
|
|
leadCount?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateLeadStageRequest {
|
|
|
|
|
name: string;
|
|
|
|
|
color?: string;
|
|
|
|
|
showOnBoard?: boolean;
|
|
|
|
|
isConverted?: boolean;
|
|
|
|
|
isLost?: boolean;
|
|
|
|
|
isUnqualified?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateLeadStageRequest {
|
|
|
|
|
name?: string;
|
|
|
|
|
color?: string;
|
|
|
|
|
showOnBoard?: boolean;
|
|
|
|
|
isConverted?: boolean;
|
|
|
|
|
isLost?: boolean;
|
|
|
|
|
isUnqualified?: boolean;
|
|
|
|
|
position?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadDto {
|
|
|
|
|
id: string;
|
|
|
|
|
title: string;
|
|
|
|
|
contactName: string | null;
|
|
|
|
|
mobile: string;
|
|
|
|
|
phone: string | null;
|
|
|
|
|
city: string | null;
|
|
|
|
|
region: string | null;
|
|
|
|
|
trade: string | null;
|
|
|
|
|
source: string | null;
|
|
|
|
|
notes: string | null;
|
|
|
|
|
estimatedValue: number | null;
|
|
|
|
|
stageId: string;
|
|
|
|
|
stageName: string;
|
|
|
|
|
position: number;
|
|
|
|
|
assigneeId: string | null;
|
|
|
|
|
assigneeName: string | null;
|
|
|
|
|
lastContactAt: string | null;
|
|
|
|
|
nextFollowUpAt: string | null;
|
|
|
|
|
convertedPersonId: string | null;
|
|
|
|
|
convertedAt: string | null;
|
|
|
|
|
archivedAt: string | null;
|
|
|
|
|
daysInStage: number;
|
|
|
|
|
hasLogo: boolean;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
updatedAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadEventDto {
|
|
|
|
|
id: string;
|
|
|
|
|
type: string;
|
|
|
|
|
title: string;
|
|
|
|
|
body: string | null;
|
|
|
|
|
actorId: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface CreateLeadRequest {
|
|
|
|
|
title: string;
|
|
|
|
|
mobile: string;
|
|
|
|
|
contactName?: string | null;
|
|
|
|
|
phone?: string | null;
|
|
|
|
|
city?: string | null;
|
|
|
|
|
region?: string | null;
|
|
|
|
|
trade?: string | null;
|
|
|
|
|
source?: string | null;
|
|
|
|
|
notes?: string | null;
|
|
|
|
|
estimatedValue?: number | null;
|
|
|
|
|
stageId?: string;
|
|
|
|
|
assigneeId?: string | null;
|
|
|
|
|
nextFollowUpAt?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface UpdateLeadRequest {
|
|
|
|
|
title?: string;
|
|
|
|
|
mobile?: string;
|
|
|
|
|
contactName?: string | null;
|
|
|
|
|
phone?: string | null;
|
|
|
|
|
city?: string | null;
|
|
|
|
|
region?: string | null;
|
|
|
|
|
trade?: string | null;
|
|
|
|
|
source?: string | null;
|
|
|
|
|
notes?: string | null;
|
|
|
|
|
estimatedValue?: number | null;
|
|
|
|
|
stageId?: string;
|
|
|
|
|
assigneeId?: string | null;
|
|
|
|
|
nextFollowUpAt?: string | null;
|
|
|
|
|
lastContactAt?: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface MoveLeadRequest {
|
|
|
|
|
stageId: string;
|
|
|
|
|
position?: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AssignLeadsRequest {
|
|
|
|
|
leadIds: string[];
|
|
|
|
|
assigneeId: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface BulkLeadStageRequest {
|
|
|
|
|
leadIds: string[];
|
|
|
|
|
stageId: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface AutoAssignLeadsRequest {
|
|
|
|
|
rule?: LeadAssignRule;
|
|
|
|
|
leadIds?: string[];
|
|
|
|
|
assigneeIds?: string[];
|
|
|
|
|
onlyUnassigned?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadCallLogRequest {
|
|
|
|
|
outcome?: string;
|
|
|
|
|
body?: string;
|
|
|
|
|
nextFollowUpAt?: string | null;
|
|
|
|
|
stageId?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadNoteRequest {
|
|
|
|
|
body: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadFollowUpRequest {
|
|
|
|
|
nextFollowUpAt: string;
|
|
|
|
|
body?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ConvertLeadRequest {
|
|
|
|
|
firstName?: string;
|
|
|
|
|
lastName?: string;
|
|
|
|
|
createIfMissing?: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface ConvertLeadResult {
|
|
|
|
|
lead: LeadDto;
|
|
|
|
|
personId: string;
|
|
|
|
|
createdPerson: boolean;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadDuplicateCheckResult {
|
|
|
|
|
exists: boolean;
|
|
|
|
|
kind: "lead" | "person" | null;
|
|
|
|
|
id: string | null;
|
|
|
|
|
title: string | null;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadImportJobDto {
|
|
|
|
|
id: string;
|
|
|
|
|
fileName: string | null;
|
|
|
|
|
status: string;
|
|
|
|
|
totalCount: number;
|
|
|
|
|
processedCount: number;
|
|
|
|
|
successCount: number;
|
|
|
|
|
duplicateCount: number;
|
|
|
|
|
errorCount: number;
|
|
|
|
|
errorSamples: string[];
|
|
|
|
|
startedAt: string | null;
|
|
|
|
|
finishedAt: string | null;
|
|
|
|
|
createdAt: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadImportRow {
|
|
|
|
|
title?: string;
|
|
|
|
|
contactName?: string;
|
|
|
|
|
mobile?: string;
|
|
|
|
|
phone?: string;
|
|
|
|
|
city?: string;
|
|
|
|
|
region?: string;
|
|
|
|
|
trade?: string;
|
|
|
|
|
source?: string;
|
|
|
|
|
notes?: string;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadStatsDto {
|
|
|
|
|
total: number;
|
|
|
|
|
newCount: number;
|
|
|
|
|
unassigned: number;
|
|
|
|
|
byAssignee: Array<{ userId: string; fullName: string; count: number }>;
|
|
|
|
|
callsLogged: number;
|
|
|
|
|
withFollowUp: number;
|
|
|
|
|
interested: number;
|
|
|
|
|
converted: number;
|
|
|
|
|
lost: number;
|
|
|
|
|
conversionRate: number;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
export interface LeadBoardColumnDto {
|
|
|
|
|
stage: LeadStageDto;
|
|
|
|
|
leads: LeadDto[];
|
|
|
|
|
}
|