/** * Beauty Business Service API client — real backend only. * Base: NEXT_PUBLIC_BEAUTY_BUSINESS_API_URL (default http://localhost:8011) * Always sends Authorization + X-Tenant-ID. */ import { getValidAccessToken, refreshSession } from "@/lib/auth"; const BEAUTY_BASE = typeof window !== "undefined" ? "/api/beauty-business" : process.env.BEAUTY_BUSINESS_SERVICE_URL || process.env.NEXT_PUBLIC_BEAUTY_BUSINESS_API_URL || "http://localhost:8011"; export class BeautyBusinessApiError extends Error { constructor( public status: number, public code: string, message: string ) { super(message); this.name = "BeautyBusinessApiError"; } } type RequestOptions = RequestInit & { tenantId: string; auth?: boolean }; async function request(path: string, options: RequestOptions): Promise { const { tenantId, auth = true, headers: customHeaders, ...init } = options; const headers = new Headers(customHeaders); headers.set("Content-Type", "application/json"); headers.set("X-Tenant-ID", tenantId); if (auth) { const token = await getValidAccessToken(); if (token) headers.set("Authorization", `Bearer ${token}`); } const url = path.startsWith("http") ? path : `${BEAUTY_BASE.replace(/\/$/, "")}${path.startsWith("/") ? path : `/${path}`}`; let res: Response; try { res = await fetch(url, { ...init, headers }); } catch (err) { const detail = err instanceof Error ? err.message : "network_error"; throw new Error(`اتصال به سرویس زیبایی برقرار نشد (${url}) — ${detail}`); } if (res.status === 401 && auth) { const refreshed = await refreshSession({ force: true }); if (refreshed) { headers.set("Authorization", `Bearer ${refreshed}`); res = await fetch(url, { ...init, headers }); } } if (!res.ok) { const body = await res.json().catch(() => ({})); throw new BeautyBusinessApiError( res.status, body?.error?.code || "unknown_error", body?.error?.message || res.statusText ); } if (res.status === 204) return undefined as T; return res.json() as Promise; } function qs(params?: Record) { if (!params) return ""; const sp = new URLSearchParams(); Object.entries(params).forEach(([k, v]) => { if (v !== undefined && v !== null && v !== "") sp.set(k, String(v)); }); const s = sp.toString(); return s ? `?${s}` : ""; } export type LifecycleStatus = "draft" | "active" | "inactive" | "suspended" | "archived"; export type BusinessFormat = "salon" | "clinic" | "spa" | "barbershop" | "mixed"; export type ProviderKind = | "communication" | "crm" | "loyalty" | "accounting" | "delivery" | "storage" | "ai" | "identity" | "custom"; export type ProviderStatus = "registered" | "active" | "inactive" | "failed" | "retired"; export type BookingEngineStatus = "registered" | "active" | "inactive" | "failed" | "retired"; export type AppointmentStatus = | "requested" | "confirmed" | "checked_in" | "in_progress" | "completed" | "cancelled" | "no_show"; export type ServiceStatus = "draft" | "active" | "inactive" | "archived"; export type ResourceStatus = "available" | "occupied" | "maintenance" | "inactive"; export type StaffKind = "stylist" | "therapist" | "receptionist" | "manager" | "other"; export type DayOfWeek = | "monday" | "tuesday" | "wednesday" | "thursday" | "friday" | "saturday" | "sunday"; export type ScheduleExceptionKind = "closed" | "modified_hours" | "holiday"; export type IntegrationDispatchStatus = "pending" | "sent" | "failed" | "skipped"; export type HealthResponse = { status: string; service: string; version: string; }; export type CapabilitiesResponse = { service: string; version: string; phase: string; commercial_product: string; features: Record; independence: { standalone: boolean; superapp: boolean; integrations: string[]; integration_mode: string; }; }; export type MetricsResponse = { service: string; version: string; phase: string; metrics: Record; note?: string; }; export type Organization = { id: string; tenant_id: string; code: string; name: string; description: string | null; status: LifecycleStatus; business_format: BusinessFormat; legal_name: string | null; timezone: string; language: string; currency_code: string; settings: Record | null; version: number; is_deleted: boolean; created_at: string; updated_at: string; }; export type Branch = { id: string; tenant_id: string; organization_id: string; code: string; name: string; description: string | null; status: LifecycleStatus; business_format: BusinessFormat | null; address: Record | null; timezone: string | null; working_hours: Record | null; metadata_json: Record | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type ExternalProvider = { id: string; tenant_id: string; organization_id: string | null; code: string; name: string; provider_kind: ProviderKind; adapter_key: string; status: ProviderStatus; priority: number; credentials_ref: string | null; config: Record | null; capabilities: Record | null; version: number; is_deleted: boolean; created_at: string; updated_at: string; }; export type BookingEngine = { id: string; tenant_id: string; organization_id: string | null; code: string; name: string; adapter_key: string; status: BookingEngineStatus; is_default: boolean; config: Record | null; capabilities: Record | null; version: number; is_deleted: boolean; created_at: string; updated_at: string; }; export type Configuration = { id: string; tenant_id: string; organization_id: string; branch_id: string | null; code: string; working_hours: Record | null; booking_policies: Record | null; cancellation_policies: Record | null; reminder_policies: Record | null; custom_fields: Record | null; timezone: string; language: string; currency_code: string; version: number; is_deleted: boolean; created_at: string; updated_at: string; }; export type Setting = { id: string; tenant_id: string; organization_id: string | null; branch_id: string | null; key: string; value: Record | null; description: string | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type AuditLog = { id: string; tenant_id: string; entity_type: string; entity_id: string; action: string; actor_user_id: string | null; changes: Record | null; message: string | null; created_at: string; }; export type PermissionCatalog = { prefix: string; prefixes: string[]; permissions: string[]; count: number; }; export type StaffSchedule = { id: string; tenant_id: string; organization_id: string; branch_id: string; staff_ref: string; code: string; day_of_week: DayOfWeek; start_time: string; end_time: string; is_active: boolean; metadata_json: Record | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type StaffAvailability = { id: string; tenant_id: string; organization_id: string; branch_id: string; staff_ref: string; code: string; starts_at: string; ends_at: string; is_bookable: boolean; metadata_json: Record | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type ScheduleException = { id: string; tenant_id: string; organization_id: string; branch_id: string; staff_ref: string | null; code: string; kind: ScheduleExceptionKind; exception_date: string; start_time: string | null; end_time: string | null; reason: string | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type AppointmentType = { id: string; tenant_id: string; organization_id: string; code: string; name: string; description: string | null; default_duration_minutes: number; status: LifecycleStatus; is_deleted: boolean; created_at: string; updated_at: string; }; export type Appointment = { id: string; tenant_id: string; organization_id: string; branch_id: string; appointment_type_id: string | null; code: string; customer_ref: string | null; staff_ref: string | null; room_ref: string | null; service_ref: string | null; status: AppointmentStatus; scheduled_start: string; scheduled_end: string; notes: string | null; status_reason: string | null; status_changed_at: string | null; metadata_json: Record | null; version: number; is_deleted: boolean; created_at: string; updated_at: string; }; export type AppointmentStatusHistory = { id: string; tenant_id: string; appointment_id: string; action: string; from_status: AppointmentStatus; to_status: AppointmentStatus; reason: string | null; actor_user_id: string | null; metadata_json: Record | null; created_at: string; }; export type WaitingListEntry = { id: string; tenant_id: string; organization_id: string; branch_id: string; code: string; customer_ref: string | null; service_ref: string | null; preferred_staff_ref: string | null; requested_date: string | null; notes: string | null; priority: number; is_deleted: boolean; created_at: string; updated_at: string; }; export type TreatmentRoom = { id: string; tenant_id: string; organization_id: string; branch_id: string; code: string; name: string; description: string | null; status: ResourceStatus; capacity: number; metadata_json: Record | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type Station = { id: string; tenant_id: string; organization_id: string; branch_id: string; room_id: string | null; code: string; name: string; status: ResourceStatus; metadata_json: Record | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type BranchPolicy = { id: string; tenant_id: string; organization_id: string; branch_id: string; code: string; name: string; policy_type: string; rules: Record | null; status: LifecycleStatus; is_deleted: boolean; created_at: string; updated_at: string; }; export type ServiceCategory = { id: string; tenant_id: string; organization_id: string; code: string; name: string; description: string | null; status: LifecycleStatus; sort_order: number; is_deleted: boolean; created_at: string; updated_at: string; }; export type BeautyService = { id: string; tenant_id: string; organization_id: string; category_id: string | null; code: string; name: string; description: string | null; status: ServiceStatus; base_duration_minutes: number; base_price: number | null; metadata_json: Record | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type CustomerProfile = { id: string; tenant_id: string; organization_id: string; code: string; display_name: string; external_crm_contact_ref: string | null; external_user_ref: string | null; mobile: string | null; email: string | null; status: LifecycleStatus; metadata_json: Record | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type PackageDefinition = { id: string; tenant_id: string; organization_id: string; code: string; name: string; description: string | null; total_sessions: number; price: number | null; valid_days: number | null; status: LifecycleStatus; is_deleted: boolean; created_at: string; updated_at: string; }; export type MembershipPlan = { id: string; tenant_id: string; organization_id: string; code: string; name: string; description: string | null; billing_interval_days: number; price: number | null; benefits: Record | null; status: LifecycleStatus; is_deleted: boolean; created_at: string; updated_at: string; }; export type StaffProfile = { id: string; tenant_id: string; organization_id: string; branch_id: string | null; code: string; display_name: string; kind: StaffKind; external_user_ref: string | null; mobile: string | null; email: string | null; status: LifecycleStatus; hire_date: string | null; metadata_json: Record | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type CommissionRule = { id: string; tenant_id: string; organization_id: string; code: string; name: string; rule_type: string; rate_percent: number | null; flat_amount: number | null; applies_to_service_id: string | null; status: LifecycleStatus; config: Record | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type MarketingCampaign = { id: string; tenant_id: string; organization_id: string | null; branch_id: string | null; code: string; name: string; external_campaign_ref: string | null; channel: string | null; status: LifecycleStatus; config: Record | null; is_deleted: boolean; created_at: string; updated_at: string; }; export type LoyaltyIntegration = { id: string; tenant_id: string; organization_id: string | null; code: string; name: string; external_program_ref: string | null; earn_rules: Record | null; status: LifecycleStatus; is_deleted: boolean; created_at: string; updated_at: string; }; export type CommunicationIntegration = { id: string; tenant_id: string; organization_id: string | null; code: string; name: string; template_mappings: Record | null; status: LifecycleStatus; is_deleted: boolean; created_at: string; updated_at: string; }; export type IntegrationDispatch = { id: string; tenant_id: string; organization_id: string | null; integration_kind: string; config_id: string | null; event_type: string; payload_ref: string | null; status: IntegrationDispatchStatus; response_json: Record | null; notes: string | null; is_deleted: boolean; created_at: string; updated_at: string; }; type PaginatedList = { page?: number; pageSize?: number }; function listPath(base: string, { page = 1, pageSize = 50 }: PaginatedList = {}) { return `${base}${qs({ page, page_size: pageSize })}`; } export const beautyBusinessApi = { health: () => fetch(`${BEAUTY_BASE}/health`).then((r) => r.json() as Promise), capabilities: () => fetch(`${BEAUTY_BASE}/capabilities`).then((r) => r.json() as Promise), metrics: () => fetch(`${BEAUTY_BASE}/metrics`).then((r) => r.json() as Promise), organizations: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/organizations", { page, pageSize }), { tenantId }), get: (tenantId: string, id: string) => request(`/api/v1/organizations/${id}`, { tenantId }), create: ( tenantId: string, body: { code: string; name: string; description?: string; status?: LifecycleStatus; business_format?: BusinessFormat; legal_name?: string; timezone?: string; language?: string; currency_code?: string; } ) => request("/api/v1/organizations", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ name: string; description: string; status: LifecycleStatus; business_format: BusinessFormat; legal_name: string; timezone: string; language: string; currency_code: string; version: number; }> ) => request(`/api/v1/organizations/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), delete: (tenantId: string, id: string) => request(`/api/v1/organizations/${id}/delete`, { tenantId, method: "POST" }), }, branches: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/branches", { page, pageSize }), { tenantId }), get: (tenantId: string, id: string) => request(`/api/v1/branches/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; code: string; name: string; description?: string; status?: LifecycleStatus; } ) => request("/api/v1/branches", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ name: string; description: string; status: LifecycleStatus; }> ) => request(`/api/v1/branches/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), delete: (tenantId: string, id: string) => request(`/api/v1/branches/${id}/delete`, { tenantId, method: "POST" }), }, externalProviders: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/external-providers", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/external-providers/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id?: string; code: string; name: string; provider_kind?: ProviderKind; adapter_key: string; status?: ProviderStatus; priority?: number; } ) => request("/api/v1/external-providers", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ name: string; provider_kind: ProviderKind; adapter_key: string; status: ProviderStatus; priority: number; version: number; }> ) => request(`/api/v1/external-providers/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), delete: (tenantId: string, id: string) => request(`/api/v1/external-providers/${id}/delete`, { tenantId, method: "POST", }), }, bookingEngines: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/booking-engines", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/booking-engines/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id?: string; code: string; name: string; adapter_key: string; status?: BookingEngineStatus; is_default?: boolean; } ) => request("/api/v1/booking-engines", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ name: string; adapter_key: string; status: BookingEngineStatus; is_default: boolean; version: number; }> ) => request(`/api/v1/booking-engines/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), delete: (tenantId: string, id: string) => request(`/api/v1/booking-engines/${id}/delete`, { tenantId, method: "POST", }), }, configurations: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/configurations", { page, pageSize }), { tenantId }), get: (tenantId: string, id: string) => request(`/api/v1/configurations/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; branch_id?: string; code: string; timezone?: string; language?: string; currency_code?: string; } ) => request("/api/v1/configurations", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ branch_id: string | null; timezone: string; language: string; currency_code: string; version: number; }> ) => request(`/api/v1/configurations/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), delete: (tenantId: string, id: string) => request(`/api/v1/configurations/${id}/delete`, { tenantId, method: "POST", }), }, settings: { list: (tenantId: string, page = 1, pageSize = 100) => request(listPath("/api/v1/settings", { page, pageSize }), { tenantId }), upsert: ( tenantId: string, body: { organization_id?: string; branch_id?: string; key: string; value?: Record; description?: string; } ) => request("/api/v1/settings", { tenantId, method: "PUT", body: JSON.stringify(body), }), }, audit: { list: (tenantId: string, entityType: string, entityId: string, limit = 100) => request( `/api/v1/audit${qs({ entity_type: entityType, entity_id: entityId, limit })}`, { tenantId } ), }, permissions: { catalog: (tenantId: string) => request("/api/v1/permissions/catalog", { tenantId }), }, staffSchedules: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/staff-schedules", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/staff-schedules/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; branch_id: string; staff_ref: string; code: string; day_of_week: DayOfWeek; start_time: string; end_time: string; is_active?: boolean; } ) => request("/api/v1/staff-schedules", { tenantId, method: "POST", body: JSON.stringify(body), }), }, staffAvailabilities: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/staff-availabilities", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/staff-availabilities/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; branch_id: string; staff_ref: string; code: string; starts_at: string; ends_at: string; is_bookable?: boolean; } ) => request("/api/v1/staff-availabilities", { tenantId, method: "POST", body: JSON.stringify(body), }), }, scheduleExceptions: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/schedule-exceptions", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/schedule-exceptions/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; branch_id: string; staff_ref?: string; code: string; kind: ScheduleExceptionKind; exception_date: string; start_time?: string; end_time?: string; reason?: string; } ) => request("/api/v1/schedule-exceptions", { tenantId, method: "POST", body: JSON.stringify(body), }), }, appointmentTypes: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/appointment-types", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/appointment-types/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; code: string; name: string; description?: string; default_duration_minutes?: number; status?: LifecycleStatus; } ) => request("/api/v1/appointment-types", { tenantId, method: "POST", body: JSON.stringify(body), }), }, appointments: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/appointments", { page, pageSize }), { tenantId }), get: (tenantId: string, id: string) => request(`/api/v1/appointments/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; branch_id: string; code: string; scheduled_start: string; scheduled_end: string; appointment_type_id?: string; customer_ref?: string; staff_ref?: string; room_ref?: string; service_ref?: string; status?: AppointmentStatus; notes?: string; } ) => request("/api/v1/appointments", { tenantId, method: "POST", body: JSON.stringify(body), }), update: ( tenantId: string, id: string, body: Partial<{ staff_ref: string; room_ref: string; service_ref: string; scheduled_start: string; scheduled_end: string; notes: string; version: number; }> ) => request(`/api/v1/appointments/${id}`, { tenantId, method: "PATCH", body: JSON.stringify(body), }), confirm: (tenantId: string, id: string, body: { reason?: string; version: number }) => request(`/api/v1/appointments/${id}/confirm`, { tenantId, method: "POST", body: JSON.stringify(body), }), checkIn: (tenantId: string, id: string, body: { reason?: string; version: number }) => request(`/api/v1/appointments/${id}/check-in`, { tenantId, method: "POST", body: JSON.stringify(body), }), complete: (tenantId: string, id: string, body: { reason?: string; version: number }) => request(`/api/v1/appointments/${id}/complete`, { tenantId, method: "POST", body: JSON.stringify(body), }), cancel: (tenantId: string, id: string, body: { reason?: string; version: number }) => request(`/api/v1/appointments/${id}/cancel`, { tenantId, method: "POST", body: JSON.stringify(body), }), noShow: (tenantId: string, id: string, body: { reason?: string; version: number }) => request(`/api/v1/appointments/${id}/no-show`, { tenantId, method: "POST", body: JSON.stringify(body), }), history: (tenantId: string, id: string) => request(`/api/v1/appointments/${id}/history`, { tenantId }), }, waitingList: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/waiting-list", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/waiting-list/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; branch_id: string; code: string; customer_ref?: string; service_ref?: string; preferred_staff_ref?: string; requested_date?: string; notes?: string; priority?: number; } ) => request("/api/v1/waiting-list", { tenantId, method: "POST", body: JSON.stringify(body), }), }, treatmentRooms: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/treatment-rooms", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/treatment-rooms/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; branch_id: string; code: string; name: string; description?: string; status?: ResourceStatus; capacity?: number; } ) => request("/api/v1/treatment-rooms", { tenantId, method: "POST", body: JSON.stringify(body), }), }, stations: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/stations", { page, pageSize }), { tenantId }), get: (tenantId: string, id: string) => request(`/api/v1/stations/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; branch_id: string; room_id?: string; code: string; name: string; status?: ResourceStatus; } ) => request("/api/v1/stations", { tenantId, method: "POST", body: JSON.stringify(body), }), }, branchPolicies: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/branch-policies", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/branch-policies/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; branch_id: string; code: string; name: string; policy_type: string; rules?: Record; status?: LifecycleStatus; } ) => request("/api/v1/branch-policies", { tenantId, method: "POST", body: JSON.stringify(body), }), }, serviceCategories: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/service-categories", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/service-categories/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; code: string; name: string; description?: string; status?: LifecycleStatus; sort_order?: number; } ) => request("/api/v1/service-categories", { tenantId, method: "POST", body: JSON.stringify(body), }), }, services: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/services", { page, pageSize }), { tenantId }), get: (tenantId: string, id: string) => request(`/api/v1/services/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; category_id?: string; code: string; name: string; description?: string; status?: ServiceStatus; base_duration_minutes?: number; base_price?: number; } ) => request("/api/v1/services", { tenantId, method: "POST", body: JSON.stringify(body), }), }, customers: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/customers", { page, pageSize }), { tenantId }), get: (tenantId: string, id: string) => request(`/api/v1/customers/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; code: string; display_name: string; mobile?: string; email?: string; status?: LifecycleStatus; } ) => request("/api/v1/customers", { tenantId, method: "POST", body: JSON.stringify(body), }), }, packageDefinitions: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/package-definitions", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/package-definitions/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; code: string; name: string; description?: string; total_sessions?: number; price?: number; valid_days?: number; status?: LifecycleStatus; } ) => request("/api/v1/package-definitions", { tenantId, method: "POST", body: JSON.stringify(body), }), }, membershipPlans: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/membership-plans", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/membership-plans/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; code: string; name: string; description?: string; billing_interval_days?: number; price?: number; status?: LifecycleStatus; } ) => request("/api/v1/membership-plans", { tenantId, method: "POST", body: JSON.stringify(body), }), }, staff: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/staff", { page, pageSize }), { tenantId }), get: (tenantId: string, id: string) => request(`/api/v1/staff/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; branch_id?: string; code: string; display_name: string; kind?: StaffKind; mobile?: string; email?: string; status?: LifecycleStatus; } ) => request("/api/v1/staff", { tenantId, method: "POST", body: JSON.stringify(body), }), }, commissionRules: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/commission-rules", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/commission-rules/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id: string; code: string; name: string; rule_type: string; rate_percent?: number; flat_amount?: number; applies_to_service_id?: string; status?: LifecycleStatus; } ) => request("/api/v1/commission-rules", { tenantId, method: "POST", body: JSON.stringify(body), }), }, marketingCampaigns: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/marketing-campaigns", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/marketing-campaigns/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id?: string; branch_id?: string; code: string; name: string; external_campaign_ref?: string; channel?: string; status?: LifecycleStatus; } ) => request("/api/v1/marketing-campaigns", { tenantId, method: "POST", body: JSON.stringify(body), }), }, loyaltyIntegrations: { list: (tenantId: string, page = 1, pageSize = 50) => request(listPath("/api/v1/loyalty-integrations", { page, pageSize }), { tenantId, }), get: (tenantId: string, id: string) => request(`/api/v1/loyalty-integrations/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id?: string; code: string; name: string; external_program_ref?: string; status?: LifecycleStatus; } ) => request("/api/v1/loyalty-integrations", { tenantId, method: "POST", body: JSON.stringify(body), }), }, communicationIntegrations: { list: (tenantId: string, page = 1, pageSize = 50) => request( listPath("/api/v1/communication-integrations", { page, pageSize }), { tenantId } ), get: (tenantId: string, id: string) => request(`/api/v1/communication-integrations/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id?: string; code: string; name: string; status?: LifecycleStatus; } ) => request("/api/v1/communication-integrations", { tenantId, method: "POST", body: JSON.stringify(body), }), }, integrationDispatches: { list: (tenantId: string, page = 1, pageSize = 50) => request( listPath("/api/v1/integration-dispatches", { page, pageSize }), { tenantId } ), get: (tenantId: string, id: string) => request(`/api/v1/integration-dispatches/${id}`, { tenantId }), create: ( tenantId: string, body: { organization_id?: string; integration_kind: string; config_id?: string; event_type: string; payload_ref?: string; } ) => request("/api/v1/integration-dispatches", { tenantId, method: "POST", body: JSON.stringify(body), }), }, };