import { ref } from 'vue' import { useSettingsStore } from '@/store/settingsStore' import { getTradeBuyPrice, getTradeSellPrice, lastPrice } from '@/utils/price' export interface StoreTradingHours { start: string end: string closePriceEnabled: boolean } export interface EffectiveTradingHours { start: string end: string enforced: boolean } const productTradingHours = ref<{ start: string; end: string } | null>(null) const productTradingHoursVersion = ref(0) function normalizeTradingTimeSetting(value: unknown, fallback: string): string { const raw = String(value ?? '').trim() return raw || fallback } function parseTimeToSeconds(time: string): number { const parts = time.trim().split(':').map(Number) const [hours = 0, minutes = 0, seconds = 0] = parts return hours * 3600 + minutes * 60 + seconds } export function formatTradingTimeDisplay(time: string): string { const normalized = normalizeTradingTimeSetting(time, '') if (!normalized) { return '' } const parts = normalized.split(':') if (parts.length >= 3) { return `${parts[0]}:${parts[1]}:${parts[2]}` } if (parts.length >= 2) { return `${parts[0]}:${parts[1]}:00` } return normalized } function hasProductTradingWindow(start?: string | null, end?: string | null): boolean { const open = formatTradingTimeDisplay(normalizeTradingTimeSetting(start, '00:00:00')) const close = formatTradingTimeDisplay(normalizeTradingTimeSetting(end, '00:00:00')) if (!open || !close) { return false } return open !== close } export function setProductTradingHours(start?: string | null, end?: string | null) { if (!hasProductTradingWindow(start, end)) { productTradingHours.value = null productTradingHoursVersion.value += 1 return } productTradingHours.value = { start: normalizeTradingTimeSetting(start, '00:00'), end: normalizeTradingTimeSetting(end, '23:59'), } productTradingHoursVersion.value += 1 } export function syncProductTradingHoursFromProducts( products: Array<{ auto_open_at?: string | null; auto_close_at?: string | null }>, ) { for (const product of products) { if (hasProductTradingWindow(product.auto_open_at, product.auto_close_at)) { setProductTradingHours(product.auto_open_at, product.auto_close_at) return } } setProductTradingHours(null, null) } export function getStoreTradingHours(): StoreTradingHours { const settings = useSettingsStore() const closeRaw = settings.getSettingByKey('close_price') const closePriceEnabled = closeRaw === true || closeRaw === 1 || String(closeRaw ?? 'false').trim().toLowerCase() === 'true' return { start: normalizeTradingTimeSetting(settings.getSettingByKey('startDay'), '00:00'), end: normalizeTradingTimeSetting(settings.getSettingByKey('endDay'), '23:59'), closePriceEnabled, } } export function getEffectiveTradingHours(): EffectiveTradingHours { void productTradingHoursVersion.value const settings = getStoreTradingHours() if (settings.closePriceEnabled) { return { start: settings.start, end: settings.end, enforced: true, } } if (productTradingHours.value?.start && productTradingHours.value?.end) { return { start: productTradingHours.value.start, end: productTradingHours.value.end, enforced: true, } } return { start: settings.start, end: settings.end, enforced: false, } } export function isStoreClosedBySchedule(now = new Date()): boolean { const { start, end, enforced } = getEffectiveTradingHours() if (!enforced) { return false } const currentSeconds = now.getHours() * 3600 + now.getMinutes() * 60 + now.getSeconds() const openSeconds = parseTimeToSeconds(start) const closeSeconds = parseTimeToSeconds(end) return currentSeconds < openSeconds || currentSeconds > closeSeconds } export function isStoreClosed(): boolean { void productTradingHoursVersion.value const { closePriceEnabled } = getStoreTradingHours() if (closePriceEnabled) { if (lastPrice.value?.closed === true) { return true } return isStoreClosedBySchedule() } // وقتی close_price خاموش است، صفر بودن قیمت مرجع به معنی بسته بودن فروشگاه نیست. return isStoreClosedBySchedule() } export function getStoreClosedMessage(): string { const { start, end } = getEffectiveTradingHours() const open = formatTradingTimeDisplay(start) const close = formatTradingTimeDisplay(end) if (!open || !close) { return 'فروشگاه در حال حاضر بسته است.' } return `فروشگاه در حال حاضر بسته است. ساعت کاری از ${open} تا ${close} می‌باشد.` } export type PriceDisplayState = 'open' | 'closed' | 'no_quote' export const NO_QUOTE_MESSAGE = 'مظنه در دسترس نیست' /** * وضعیت نمایش قیمت در صفحه اصلی: * - closed → فروشگاه بسته است (خارج از ساعت کاری close_price یا بازه محصول) * - no_quote → مظنه در دسترس نیست (قیمت زنده نداریم و show_last_price خاموش است) * - open → نمایش عادی قیمت * * اولویت با status ارسالی از سرور است؛ اگر نبود به منطق سمت کلاینت برمی‌گردیم. */ export function getPriceDisplayState(): PriceDisplayState { void productTradingHoursVersion.value const p = lastPrice.value const status = p?.status if (status === 'closed') { return 'closed' } if (status === 'no_quote') { return getTradeBuyPrice(p) > 0 ? 'open' : 'no_quote' } if (status === 'open') { return getTradeBuyPrice(p) > 0 || getTradeSellPrice(p) > 0 ? 'open' : 'no_quote' } // سرور status نفرستاده (سازگاری با نسخه قدیمی) → استنتاج سمت کلاینت if (isStoreClosed()) { return 'closed' } return getTradeBuyPrice(p) > 0 || getTradeSellPrice(p) > 0 ? 'open' : 'no_quote' } export function getPriceDisplayMessage(state: PriceDisplayState = getPriceDisplayState()): string { if (state === 'closed') { return getStoreClosedMessage() } if (state === 'no_quote') { return NO_QUOTE_MESSAGE } return '' }