import { useMutation, useQuery, useQueryClient } from '@tanstack/react-query'; import { toast } from 'sonner'; import { api, ApiError, type ApiResponse } from '../lib/api'; /** * لیست قیمت بازه‌دار و فاکتور نوبت. * * لیست تا فعال نشده هیچ اثری ندارد؛ ساختن پیش‌نویس نباید قیمت امروز را عوض کند. پس * `create` و `activate` عمداً دو عمل جدا هستند، نه یک فرم با تیک «فعال». */ export interface PriceListItem { service_uuid: string; service_name?: string; price_rials: number; } export interface PriceList { uuid: string; name: string; address_uuid: string | null; address_name: string | null; valid_from: number; valid_to: number; active: boolean; items: PriceListItem[]; created_at: number; } export interface PriceSnapshotLine { label: string; rials: number; kind?: string; } export interface PriceSnapshot { base_rials: number; items_rials: number; discount_rials: number; insurance_base_rials: number; insurance_supplementary_rials: number; tax_rials: number; final_rials: number; deposit_rials: number; created_at?: number; breakdown: { discounts: PriceSnapshotLine[]; sources: Record; }; } const KEY = ['price-lists']; function fail(e: unknown, fallback: string) { toast.error(e instanceof ApiError ? e.message : fallback); } export function usePriceLists() { const qc = useQueryClient(); const query = useQuery({ queryKey: KEY, queryFn: () => api.get>('/api/v1/price-lists'), }); const invalidate = () => qc.invalidateQueries({ queryKey: KEY }); const create = useMutation({ mutationFn: (body: Record) => api.post>('/api/v1/price-lists', body), onSuccess: () => { toast.success('لیست قیمت ساخته شد — تا فعال نشود اثری ندارد'); invalidate(); }, onError: (e) => fail(e, 'ساخت لیست قیمت ناموفق بود'), }); const update = useMutation({ mutationFn: ({ uuid, body }: { uuid: string; body: Record }) => api.patch>(`/api/v1/price-list/${uuid}`, body), onSuccess: () => { toast.success('لیست قیمت به‌روزرسانی شد'); invalidate(); }, onError: (e) => fail(e, 'به‌روزرسانی ناموفق بود'), }); const setItems = useMutation({ mutationFn: ({ uuid, items }: { uuid: string; items: PriceListItem[] }) => api.put>(`/api/v1/price-list/${uuid}/items`, { items }), onSuccess: () => { toast.success('قیمت‌ها ذخیره شد'); invalidate(); }, onError: (e) => fail(e, 'ذخیرهٔ قیمت‌ها ناموفق بود'), }); /** تداخل بازه با لیست فعالِ هم‌دامنه اینجا ۴۲۲ می‌گیرد؛ پیام سرور دقیق‌تر است. */ const activate = useMutation({ mutationFn: (uuid: string) => api.post>(`/api/v1/price-list/${uuid}/activate`, {}), onSuccess: () => { toast.success('لیست قیمت فعال شد'); invalidate(); }, onError: (e) => fail(e, 'فعال‌سازی ناموفق بود'), }); const remove = useMutation({ mutationFn: (uuid: string) => api.delete>(`/api/v1/price-list/${uuid}`), onSuccess: () => { toast.success('لیست قیمت حذف شد'); invalidate(); }, onError: (e) => fail(e, 'حذف ناموفق بود'), }); return { lists: query.data?.data ?? [], loading: query.isLoading, create, update, setItems, activate, remove }; } /** فاکتور یک نوبت — همان اعداد لحظهٔ ثبت، حتی اگر قیمت‌ها بعداً عوض شده باشند. */ export function useAppointmentInvoice(appointmentUuid: string | undefined) { const query = useQuery({ queryKey: ['appointment-invoice', appointmentUuid], queryFn: () => api.get>(`/api/v1/appointment/${appointmentUuid}/price-snapshot`), enabled: !!appointmentUuid, // نوبتِ بدون فاکتور ۴۰۴ می‌دهد و آن خطا نیست، یعنی «هنوز ثبت نشده». retry: false, }); return { invoice: query.data?.data, loading: query.isLoading, missing: query.isError }; }