Files
boursecu_admin/src/utils/config.ts
T
mohmdsdgandCursor c332e9df24 feat(admin): let price alerts pick a product
Show the product on the form and table so each alert is tied to one item.

Co-authored-by: Cursor <cursoragent@cursor.com>
2026-08-18 22:23:22 +03:30

418 lines
15 KiB
TypeScript

import { ref } from 'vue'
import { setCachedMainMetal } from '@/utils/metalLabels'
export type AccountingProvider = 'none' | 'pargar' | 'tahesab' | 'zarin'
export function getConfigApp(key: string) {
const config = window.__APP_CONFIG__ ? window.__APP_CONFIG__.user : {}
if (config) {
return config[key]
}
return null
}
/** true اگر ui_config یا app_ui_config در get_user مقدار داشته باشد */
export function hasAppUiConfig(): boolean {
const cfg = getConfigApp('ui_config') ?? getConfigApp('app_ui_config')
if (cfg == null) return false
if (typeof cfg === 'string') return cfg.trim().length > 0
if (Array.isArray(cfg)) return cfg.length > 0
if (typeof cfg === 'object') return Object.keys(cfg as object).length > 0
return Boolean(cfg)
}
let storeModeFromSettings: boolean | null = null
let settingsBootstrapped = false
/** reactive — برای فیلتر منوی «بنرها» در پیکربندی */
export const bannerEnabledSetting = ref(false)
/** reactive — برای فیلتر منوی «سایت‌های ری‌گیری» در پیکربندی */
export const trackingSystemsEnabledSetting = ref(false)
/** reactive — نمایش UI ته‌حساب در حسابداری و ... */
export const tahesabEnabledSetting = ref(false)
/** reactive — نمایش UI زرین در حسابداری و ... */
export const zarinEnabledSetting = ref(false)
/** reactive — نمایش UI پرگار در حسابداری و ... */
export const pargarEnabledSetting = ref(false)
/** reactive — دکمه پیامک تکی در لیست مشتریان */
export const customerDirectSmsEnabledSetting = ref(false)
/** reactive — منو و UI سفارش شرطی (ادمین + کنترل‌های مشتری) */
export const conditionalOrderEnabledSetting = ref(false)
/** reactive — قلک per-product در اپ مشتری */
export const productFundsEnabledSetting = ref(false)
/** reactive — سود چندسطحی معرف در لیست مشتریان */
export const customerLevelProfitEnabledSetting = ref(false)
/** reactive — منو و UI هشدار قیمت */
export const priceTriggerEnabledSetting = ref(false)
/** reactive — دکمه ارسال پیامک گروهی در صفحه پیامک‌ها */
export const groupSmsEnabledSetting = ref(false)
/** reactive — زیرمنوی قیمت ویژه مشتری */
export const customerSpecialPricingEnabledSetting = ref(false)
/** reactive — منو و زنگوله اعلان داخل اپ */
export const appNotificationEnabledSetting = ref(true)
/** reactive — منبع قیمت فعال (montzar / zaarbox / main_product) */
export const priceProviderSetting = ref('')
/** reactive — منوی افقی / دکمه «چت پشتیبانی» */
export const supportChatMenuEnabledSetting = ref(false)
/** reactive — سوییچ دیپلوی show_to_users_chat (برای مخفی کردن has_chat در تنظیمات عادی) */
export const showToUsersChatSetting = ref(false)
/** reactive — سوییچ دیپلوی price_channel_access (گروه کانال در تنظیمات عادی) */
export const priceChannelAccessSetting = ref(false)
export const accountingProviderSetting = ref<AccountingProvider>('none')
let tahesabEnabledFromSettings: boolean | null = null
let zarinEnabledFromSettings: boolean | null = null
let pargarEnabledFromSettings: boolean | null = null
let customerDirectSmsFromSettings: boolean | null = null
let accountingProviderFromSettings: AccountingProvider | null = null
function isSwitchOn(value: string | undefined | null): boolean {
const v = (value ?? '').trim().toLowerCase()
return v === 'true' || v === '1' || v === 'yes' || v === 'activate'
}
function normalizeAccountingProvider(value: string | undefined | null): AccountingProvider {
const v = (value ?? '').trim().toLowerCase()
if (v === 'pargar' || v === 'tahesab' || v === 'zarin') return v
return 'none'
}
function resolveAccountingProviderFromRows(
list: Array<{ key?: string; value?: string | null }>
): AccountingProvider {
const row = list.find((item) => item.key === 'accounting_provider')
if (row?.value !== undefined && row?.value !== null && String(row.value).trim() !== '') {
return normalizeAccountingProvider(row.value)
}
const pargarLegacy = list.find((item) => item.key === 'send_to_pargar')
if (pargarLegacy && isSwitchOn(pargarLegacy.value)) return 'pargar'
const tahesabLegacy = list.find((item) => item.key === 'send_to_tahesab')
if (tahesabLegacy && isSwitchOn(tahesabLegacy.value)) return 'tahesab'
return 'none'
}
export function applyAccountingProviderFromRows(
list: Array<{ key?: string; value?: string | null }>
): void {
const provider = resolveAccountingProviderFromRows(list)
accountingProviderFromSettings = provider
accountingProviderSetting.value = provider
setTahesabEnabledFromSettings(provider === 'tahesab')
setZarinEnabledFromSettings(provider === 'zarin')
setPargarEnabledFromSettings(provider === 'pargar')
}
export function setStoreModeFromSettings(value: boolean): void {
storeModeFromSettings = value
}
export function setBannerEnabledFromSettings(value: boolean): void {
bannerEnabledSetting.value = value
}
export function setTrackingSystemsEnabledFromSettings(value: boolean): void {
trackingSystemsEnabledSetting.value = value
}
export function setTahesabEnabledFromSettings(value: boolean): void {
tahesabEnabledFromSettings = value
tahesabEnabledSetting.value = value
}
export function setZarinEnabledFromSettings(value: boolean): void {
zarinEnabledFromSettings = value
zarinEnabledSetting.value = value
}
export function setPargarEnabledFromSettings(value: boolean): void {
pargarEnabledFromSettings = value
pargarEnabledSetting.value = value
}
export function setCustomerDirectSmsEnabledFromSettings(value: boolean): void {
customerDirectSmsFromSettings = value
customerDirectSmsEnabledSetting.value = value
}
export function setGroupSmsEnabledFromSettings(value: boolean): void {
groupSmsEnabledSetting.value = value
}
export function setCustomerSpecialPricingEnabledFromSettings(value: boolean): void {
customerSpecialPricingEnabledSetting.value = value
}
export function setConditionalOrderEnabledFromSettings(value: boolean): void {
conditionalOrderEnabledSetting.value = value
}
export function setProductFundsEnabledFromSettings(value: boolean): void {
productFundsEnabledSetting.value = value
}
export function setCustomerLevelProfitEnabledFromSettings(value: boolean): void {
customerLevelProfitEnabledSetting.value = value
}
export function setPriceTriggerEnabledFromSettings(value: boolean): void {
priceTriggerEnabledSetting.value = value
}
export function setAppNotificationEnabledFromSettings(value: boolean): void {
appNotificationEnabledSetting.value = value
}
export function setSupportChatMenuEnabledFromSettings(value: boolean): void {
supportChatMenuEnabledSetting.value = value
}
export function setShowToUsersChatFromSettings(value: boolean): void {
showToUsersChatSetting.value = value
}
export function setPriceChannelAccessFromSettings(value: boolean): void {
priceChannelAccessSetting.value = value
}
let lastShowToUsersChat = ''
let lastHasChat = ''
let lastChatApi = ''
/** منوی چت: show_to_users_chat + has_chat + chat_api */
export function resolveSupportChatMenuEnabled(
getValue: (key: string) => string | undefined | null
): boolean {
const api = String(getValue('chat_api') ?? '').trim()
return (
isSwitchOn(getValue('show_to_users_chat')) &&
isSwitchOn(getValue('has_chat')) &&
Boolean(api) &&
api.toLowerCase() !== 'null'
)
}
export function applySupportChatMenuEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }>
): void {
let touched = false
for (const row of rows) {
const key = String(row.key ?? '')
if (key === 'show_to_users_chat') {
lastShowToUsersChat = String(row.value ?? '')
touched = true
} else if (key === 'has_chat') {
lastHasChat = String(row.value ?? '')
touched = true
} else if (key === 'chat_api') {
lastChatApi = String(row.value ?? '')
touched = true
}
}
if (!touched) return
setShowToUsersChatFromSettings(isSwitchOn(lastShowToUsersChat))
setSupportChatMenuEnabledFromSettings(
resolveSupportChatMenuEnabled((key) => {
if (key === 'show_to_users_chat') return lastShowToUsersChat
if (key === 'has_chat') return lastHasChat
if (key === 'chat_api') return lastChatApi
return undefined
})
)
}
export function setPriceProviderFromSettings(value?: string | null): void {
priceProviderSetting.value = (value ?? '').trim().toLowerCase()
}
/** فقط وقتی کلید در rows باشد آپدیت می‌شود — پاسخ ناقص (editable/system) فلگ قبلی را پاک نکند */
export function applyBannerEnabledFromRows(rows: Array<{ key?: string; value?: string | null }>) {
const row = rows.find((item) => item.key === 'banner_enabled')
if (row) setBannerEnabledFromSettings(isSwitchOn(row.value))
}
export function applyTrackingSystemsEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'tracking_systems_enabled')
if (row) setTrackingSystemsEnabledFromSettings(isSwitchOn(row.value))
}
export function applyCustomerDirectSmsFromRows(rows: Array<{ key?: string; value?: string | null }>) {
const row = rows.find((item) => item.key === 'customer_direct_sms')
if (row) setCustomerDirectSmsEnabledFromSettings(isSwitchOn(row.value))
}
export function applyGroupSmsFromRows(rows: Array<{ key?: string; value?: string | null }>) {
const row = rows.find((item) => item.key === 'group_sms')
if (row) setGroupSmsEnabledFromSettings(isSwitchOn(row.value))
}
export function applyCustomerSpecialPricingFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'customer_special_pricing')
if (row) setCustomerSpecialPricingEnabledFromSettings(isSwitchOn(row.value))
}
export function applyConditionalOrderEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'enable_conditional_order')
if (row) setConditionalOrderEnabledFromSettings(isSwitchOn(row.value))
}
export function applyProductFundsEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'enable_product_funds')
if (row) setProductFundsEnabledFromSettings(isSwitchOn(row.value))
}
export function applyCustomerLevelProfitEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'enable_customer_level_profit')
if (row) setCustomerLevelProfitEnabledFromSettings(isSwitchOn(row.value))
}
export function applyPriceTriggerEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'has_page_price_trigger')
if (row) setPriceTriggerEnabledFromSettings(isSwitchOn(row.value))
}
export function applyAppNotificationEnabledFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'has_page_notification')
if (row) setAppNotificationEnabledFromSettings(isSwitchOn(row.value))
}
export function applyPriceProviderFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'price_provider')
if (row) {
setPriceProviderFromSettings(row.value)
}
}
export function applyPriceChannelAccessFromRows(
rows: Array<{ key?: string; value?: string | null }>
) {
const row = rows.find((item) => item.key === 'price_channel_access')
if (row) setPriceChannelAccessFromSettings(isSwitchOn(row.value))
}
async function bootstrapSettingsFromApi(): Promise<void> {
if (settingsBootstrapped) return
try {
const { getConfiguration } = await import('@/api/configuration')
const { parseMainWalletProductIds } = await import('@/components/mobile/utils/wallet')
const rows = await getConfiguration()
const list = Array.isArray(rows) ? rows : []
const isStoreRow = list.find((item) => item.key === 'is_store')
const mainWalletRow = list.find((item) => item.key === 'main_wallet_products')
const mainMetalRow = list.find((item) => item.key === 'main_metal')
storeModeFromSettings = isStoreRow ? isSwitchOn(isStoreRow.value) : false
applyAccountingProviderFromRows(list)
applyBannerEnabledFromRows(list)
applyTrackingSystemsEnabledFromRows(list)
applyCustomerDirectSmsFromRows(list)
applyGroupSmsFromRows(list)
applyCustomerSpecialPricingFromRows(list)
applyConditionalOrderEnabledFromRows(list)
applyProductFundsEnabledFromRows(list)
applyCustomerLevelProfitEnabledFromRows(list)
applyPriceTriggerEnabledFromRows(list)
applyAppNotificationEnabledFromRows(list)
applySupportChatMenuEnabledFromRows(list)
applyPriceProviderFromRows(list)
applyPriceChannelAccessFromRows(list)
setCachedMainMetal(mainMetalRow?.value)
const { setCachedMainWalletProductIds } = await import('@/components/mobile/utils/wallet')
setCachedMainWalletProductIds(parseMainWalletProductIds(mainWalletRow?.value))
settingsBootstrapped = true
} catch {
// Allow retry on next init* call — do not lock flags to false forever.
}
}
/** is_store و main_wallet_products از API تنظیمات — نه از get_user */
export async function initStoreModeFromSettings(): Promise<boolean> {
if (storeModeFromSettings !== null) return storeModeFromSettings
await bootstrapSettingsFromApi()
return storeModeFromSettings === true
}
export async function initWalletSettingsFromApi(): Promise<void> {
await bootstrapSettingsFromApi()
}
export function isStoreApp(): boolean {
return storeModeFromSettings === true
}
export function isTahesabEnabled(): boolean {
return tahesabEnabledFromSettings === true
}
export function isZarinEnabled(): boolean {
return zarinEnabledFromSettings === true
}
export function isPargarEnabled(): boolean {
return pargarEnabledFromSettings === true
}
export function getAccountingProvider(): AccountingProvider {
return accountingProviderFromSettings ?? 'none'
}
/** بارگذاری accounting_provider و فلگ‌های UI */
export async function initAccountingSettingsFromApi(): Promise<AccountingProvider> {
if (accountingProviderFromSettings !== null) return accountingProviderFromSettings
await bootstrapSettingsFromApi()
return accountingProviderFromSettings ?? 'none'
}
/** @deprecated از initAccountingSettingsFromApi استفاده کنید */
export async function initTahesabSettingFromApi(): Promise<boolean> {
await initAccountingSettingsFromApi()
return tahesabEnabledFromSettings === true
}
/** @deprecated از initAccountingSettingsFromApi استفاده کنید */
export async function initPargarSettingFromApi(): Promise<boolean> {
await initAccountingSettingsFromApi()
return pargarEnabledFromSettings === true
}