fixsome changes

This commit is contained in:
2026-08-16 14:03:11 +03:30
parent 2b27b16296
commit 27f3a6212a
7 changed files with 469 additions and 59 deletions
+72 -2
View File
@@ -63,7 +63,35 @@
</div>
</template>
<a-row :gutter="[16, 16]" class="settings-grid">
<template v-if="group.subsections?.length">
<div
v-for="block in subsectionBlocks(group)"
:key="block.id"
class="settings-subsection"
>
<h3 class="settings-subsection__title">{{ block.title }}</h3>
<a-row :gutter="[16, 16]" class="settings-grid">
<a-col
v-for="row in block.rows"
:key="row.id"
:xs="24"
:sm="12"
:lg="rowColSpan(row)"
>
<SettingCard
:row="row"
:model-value="draftValue(row)"
:readonly="isReadonly(row)"
:saving="isSaving(row.id)"
:saved-flash="isSavedFlash(row.id)"
@update:value="onValueChange(row, $event)"
@blur="onFieldBlur(row)"
/>
</a-col>
</a-row>
</div>
</template>
<a-row v-else :gutter="[16, 16]" class="settings-grid">
<a-col
v-for="row in groupedFiltered[group.id]"
:key="row.id"
@@ -178,7 +206,8 @@ import { applyBannerEnabledFromRows, applyTrackingSystemsEnabledFromRows, applyC
import {
EDITABLE_SETTING_GROUPS,
SYSTEM_SETTING_GROUPS,
getSettingGroupId
getSettingGroupId,
type SettingGroupDef
} from './settingGroups'
import {
SETTING_TYPE_OPTIONS,
@@ -318,6 +347,32 @@ const visibleSettingGroups = computed(() =>
settingGroups.value.filter((g) => (groupedFiltered.value[g.id]?.length ?? 0) > 0)
)
function subsectionBlocks(group: SettingGroupDef) {
const rows = groupedFiltered.value[group.id] ?? []
if (!group.subsections?.length) {
return [{ id: 'all', title: group.title, rows }]
}
const used = new Set<number>()
const blocks = group.subsections
.map((sub) => {
const subRows = rows.filter((row) => {
if (row.id == null || used.has(row.id)) return false
if (!sub.match(row.key || '')) return false
used.add(row.id)
return true
})
return { id: sub.id, title: sub.title, rows: subRows }
})
.filter((b) => b.rows.length > 0)
const leftovers = rows.filter((row) => row.id != null && !used.has(row.id))
if (leftovers.length) {
blocks.push({ id: `${group.id}-other`, title: 'سایر', rows: leftovers })
}
return blocks
}
const defaultOpenGroupId = computed(() => {
const visibleIds = visibleSettingGroups.value.map((g) => g.id)
const preferred = isSystemMode.value
@@ -740,6 +795,21 @@ async function ok() {
margin-bottom: 8px;
}
.settings-subsection {
& + & {
margin-top: 1.25rem;
padding-top: 1rem;
border-top: 1px solid var(--admin-border);
}
&__title {
margin: 0 0 0.75rem;
font-size: 13px;
font-weight: 700;
color: var(--admin-text-primary);
}
}
:deep(.ant-form-item-extra) {
font-size: 12px;
color: rgba(0, 0, 0, 0.45);
@@ -1,8 +1,16 @@
export type SettingSubsectionDef = {
id: string
title: string
match: (key: string) => boolean
}
export type SettingGroupDef = {
id: string
title: string
icon: string
match: (key: string) => boolean
/** زیربخش‌های داخل گروه (مثلاً روش‌های واریز) */
subsections?: SettingSubsectionDef[]
}
/** گروه‌های صفحه تنظیمات عادی (فقط can_edit=1) */
@@ -81,6 +89,44 @@ export const EDITABLE_SETTING_GROUPS: SettingGroupDef[] = [
icon: 'vuesax-linear:shop',
match: (k) => /^external_order/.test(k)
},
{
id: 'deposit_methods',
title: 'روش‌های واریز',
icon: 'vuesax-linear:card-send',
match: (k) =>
k.startsWith('deposit_method_')
|| k === 'deposit_account_holder'
|| k === 'deposit_card_number'
|| k === 'deposit_account_number'
|| k === 'deposit_sheba',
subsections: [
{
id: 'card_to_card',
title: 'کارت به کارت',
match: (k) =>
k === 'deposit_method_card_to_card'
|| k === 'deposit_account_holder'
|| k === 'deposit_card_number'
|| k === 'deposit_account_number'
|| k === 'deposit_sheba',
},
{
id: 'gateway',
title: 'درگاه پرداخت',
match: (k) => k === 'deposit_method_gateway',
},
{
id: 'identified',
title: 'شناسه واریز',
match: (k) => k === 'deposit_method_identified',
},
{
id: 'shetab',
title: 'شبکه شتابی',
match: (k) => k === 'deposit_method_shetab',
},
],
},
{
id: 'support',
title: 'پشتیبانی',
@@ -89,7 +135,7 @@ export const EDITABLE_SETTING_GROUPS: SettingGroupDef[] = [
k === 'support_messengers'
|| k.startsWith('support_messenger_')
|| k === 'deposit_sms_support_number'
|| (k.startsWith('deposit_') && !k.startsWith('external_')),
|| k === 'deposit_support_message_text',
},
{
id: 'bots',
@@ -181,12 +227,21 @@ export const SYSTEM_SETTING_GROUPS: SettingGroupDef[] = [
match: (k) => /^node_/.test(k) || k === 'montify_name' || k === 'external_order_api_enabled'
},
{
id: 'gateway',
title: 'درگاه شارژ آنلاین',
icon: 'vuesax-linear:card-pos',
id: 'deposit_methods',
title: 'روش‌های واریز',
icon: 'vuesax-linear:card-send',
match: (k) =>
k.startsWith('external_payment_')
|| k === 'wallet_payment_provider'
|| k === 'wallet_payment_provider',
subsections: [
{
id: 'gateway',
title: 'درگاه فروشگاه / پرداخت آنلاین',
match: (k) =>
k.startsWith('external_payment_')
|| k === 'wallet_payment_provider',
},
],
},
{
id: 'payping',
@@ -245,3 +300,14 @@ export function getSettingGroupId(key: string, groups: SettingGroupDef[]): strin
}
return 'misc'
}
export function getSettingSubsectionId(
key: string,
group: SettingGroupDef | undefined
): string | null {
if (!group?.subsections?.length) return null
for (const sub of group.subsections) {
if (sub.match(key)) return sub.id
}
return null
}
@@ -368,6 +368,10 @@ const KEY_TYPE_FALLBACK: Record<string, SettingFieldType> = {
deposit_card_number: 'text',
deposit_account_number: 'text',
deposit_sheba: 'text',
deposit_method_card_to_card: 'switch',
deposit_method_gateway: 'switch',
deposit_method_identified: 'switch',
deposit_method_shetab: 'switch',
invite_link_text: 'longtext',
support_messenger: 'select',
deposit_sms_support_number: 'number',
@@ -775,6 +779,14 @@ const KEY_HELP_FALLBACK: Record<string, string> = {
'شماره حساب بانکی واریز — در مودال راهنمای شارژ کنار کارت و شبا نمایش داده می‌شود. در متن‌ها با ٪حساب یا %حساب جایگزین می‌شود.',
deposit_sheba:
'شماره شبا واریز — در متن‌ها با ٪شبا یا %شبا جایگزین می‌شود.',
deposit_method_card_to_card:
'روشن (پیش‌فرض): روش کارت به کارت در صفحه واریز اپ نمایش داده می‌شود. خاموش: این روش از لیست روش‌های واریز حذف می‌شود.',
deposit_method_gateway:
'روشن: روش درگاه پرداخت در صفحه واریز نمایش داده می‌شود. خاموش: مخفی است. اتصال و کدهای درگاه در تنظیمات پیشرفته → روش‌های واریز تنظیم می‌شوند.',
deposit_method_identified:
'روشن: روش شناسه واریز در صفحه واریز نمایش داده می‌شود. خاموش: مخفی است.',
deposit_method_shetab:
'روشن: روش شبکه شتابی در صفحه واریز نمایش داده می‌شود. خاموش: مخفی است.',
deposit_sms_support_number:
'شماره تماس پشتیبانی برای راهنمای واریز و دکمه پیامک داخل مودال شارژ. برای نمایش در منوی شناور، باید «تماس تلفنی» یا «پیامک» را جداگانه در لیست پیام‌رسان‌های پشتیبانی اضافه کنید.',
charge_notif:
@@ -1030,6 +1042,10 @@ export const KEY_LABEL_FALLBACK: Record<string, string> = {
deposit_card_number: 'شماره کارت واریز',
deposit_account_number: 'شماره حساب واریز',
deposit_sheba: 'شبا واریز',
deposit_method_card_to_card: 'فعال‌سازی کارت به کارت',
deposit_method_gateway: 'فعال‌سازی درگاه پرداخت',
deposit_method_identified: 'فعال‌سازی شناسه واریز',
deposit_method_shetab: 'فعال‌سازی شبکه شتابی',
deposit_sms_support_number: 'شماره تماس پشتیبانی',
price_channel_enabled: 'ارسال قیمت به کانال',
price_channel_access: 'دسترسی ارسال قیمت به کانال',
@@ -1119,6 +1135,7 @@ export const SETTING_EDITABLE_KEYS = new Set([
'sms_notif_price_trigger', 'sms_notif_wallet_alert', 'sms_notif_support_admin',
'deposit_sms_support_number', 'deposit_support_message_text',
'deposit_account_holder', 'deposit_card_number', 'deposit_account_number', 'deposit_sheba',
'deposit_method_card_to_card', 'deposit_method_gateway', 'deposit_method_identified', 'deposit_method_shetab',
'endDay',
'fee_free', 'fee_service_charge_percentage',
'gift_for_referral', 'gift_for_referrer',
@@ -1138,6 +1155,7 @@ export const SETTING_EDITABLE_KEYS = new Set([
'support_messengers', 'support_messenger_text',
'has_chat',
'deposit_support_message_text', 'deposit_account_holder', 'deposit_card_number', 'deposit_account_number', 'deposit_sheba',
'deposit_method_card_to_card', 'deposit_method_gateway', 'deposit_method_identified', 'deposit_method_shetab',
'text_about', 'text_rule',
'zaarbox_price_key',
'price_channel_enabled', 'price_channel_messengers', 'price_channel_diff',
@@ -1,8 +1,13 @@
<template>
<div class="flex flex-col gap-2 rounded-lg border border-solid border-amber-200 bg-amber-50 px-3 py-2">
<div class="formula-price-section mb-4 flex flex-col gap-2 rounded-lg border border-solid px-3 py-2">
<div class="flex items-center justify-between gap-2">
<div class="flex items-center gap-1.5">
<DashboardLabelWithHelp label="قیمت فرمولی" :help="formulaHelp" size="sm" />
<DashboardLabelWithHelp
label="قیمت فرمولی"
:help="formulaHelp"
size="sm"
text-class="formula-price-section__label"
/>
</div>
<a-switch
:checked="!!modelValue.price_formula_enabled"
@@ -15,7 +20,7 @@
<template v-if="modelValue.price_formula_enabled">
<a-form-item class="!mb-0" name="price_formula">
<template #label>
<span class="text-sm">فرمول قیمت محصول</span>
<span class="formula-price-section__label text-sm">فرمول قیمت محصول</span>
</template>
<a-input
v-model:value="localFormula"
@@ -29,9 +34,9 @@
/>
</a-form-item>
<div class="flex items-center justify-between gap-2 rounded-md bg-white px-2 py-1 text-sm">
<span class="text-gray-600">قیمت محصول (محاسبه‌شده)</span>
<span class="font-bold text-amber-800">{{ usePrice(computedProductPrice) }}</span>
<div class="formula-price-section__result flex items-center justify-between gap-2 rounded-md px-2 py-1 text-sm">
<span class="formula-price-section__result-label">قیمت محصول (محاسبه‌شده)</span>
<span class="formula-price-section__result-value font-bold">{{ usePrice(computedProductPrice) }}</span>
</div>
</template>
</div>
@@ -126,9 +131,55 @@ function onToggle(checked: boolean) {
</script>
<style scoped>
.formula-price-section {
border-color: #fde68a;
background: #fffbeb;
color: #78350f;
}
.formula-price-section__label {
color: #78350f;
}
.formula-price-section__result {
background: #fff;
}
.formula-price-section__result-label {
color: #4b5563;
}
.formula-price-section__result-value {
color: #92400e;
}
.formula-price-input :deep(input) {
direction: ltr !important;
text-align: left !important;
unicode-bidi: plaintext;
}
</style>
<style>
html.is-dark .formula-price-section {
border-color: rgba(180, 83, 9, 0.55);
background: rgba(120, 53, 15, 0.45);
color: #fde68a;
}
html.is-dark .formula-price-section__label {
color: #fde68a;
}
html.is-dark .formula-price-section__result {
background: rgba(0, 0, 0, 0.28);
}
html.is-dark .formula-price-section__result-label {
color: rgba(253, 230, 138, 0.85);
}
html.is-dark .formula-price-section__result-value {
color: #fbbf24;
}
</style>
@@ -41,18 +41,47 @@
<template #label>
<DashboardLabelWithHelp label="مرجع قیمت" :help="priceReferenceHelp" size="sm" />
</template>
<BasicSelect
class="price-reference-select"
allowClear
:hasTooltip="false"
popup-class-name="price-reference-select-dropdown"
:dropdown-match-select-width="false"
:dropdown-style="{ minWidth: '28rem' }"
:items="pricesList"
valueName="name"
keyName="id"
v-model:value="form.reading_method"
/>
<div class="flex flex-col gap-1.5">
<div class="flex flex-col gap-1.5 sm:flex-row sm:items-center sm:gap-3">
<BasicSelect
class="price-reference-select min-w-0 flex-1"
allowClear
:hasTooltip="false"
popup-class-name="price-reference-select-dropdown"
:dropdown-match-select-width="false"
:dropdown-style="{ minWidth: '28rem' }"
:items="pricesList"
valueName="name"
keyName="id"
v-model:value="form.reading_method"
/>
<span
v-if="selectedReferenceTotal > 0"
class="price-reference-live shrink-0 text-sm font-700"
>
{{ usePrice(selectedReferenceTotal) }}
</span>
<span
v-else-if="isOrphanReference"
class="price-reference-live-empty shrink-0 text-sm"
>
در لیست فعلی نیست
</span>
<span
v-else-if="form.reading_method"
class="price-reference-live-empty shrink-0 text-sm"
>
قیمت مرجع در دسترس نیست
</span>
</div>
<a-alert
v-if="isOrphanReference"
type="warning"
show-icon
class="!mb-0"
message="این مرجع قبلاً روی محصول ذخیره شده، ولی الان در لیست قیمت همکار نیست. یک مرجع معتبر انتخاب کنید یا فیلد را پاک کنید."
/>
</div>
</a-form-item>
<a-form-item name="price_offset_percent" class="!mb-0">
<template #label>
@@ -115,18 +144,47 @@
<template #label>
<DashboardLabelWithHelp label="مرجع قیمت" :help="priceReferenceHelp" size="sm" />
</template>
<BasicSelect
class="price-reference-select"
allowClear
:hasTooltip="false"
popup-class-name="price-reference-select-dropdown"
:dropdown-match-select-width="false"
:dropdown-style="{ minWidth: '28rem' }"
:items="pricesList"
valueName="name"
keyName="id"
v-model:value="form.reading_method"
/>
<div class="flex flex-col gap-1.5">
<div class="flex flex-col gap-1.5 sm:flex-row sm:items-center sm:gap-3">
<BasicSelect
class="price-reference-select min-w-0 flex-1"
allowClear
:hasTooltip="false"
popup-class-name="price-reference-select-dropdown"
:dropdown-match-select-width="false"
:dropdown-style="{ minWidth: '28rem' }"
:items="pricesList"
valueName="name"
keyName="id"
v-model:value="form.reading_method"
/>
<span
v-if="selectedReferenceTotal > 0"
class="price-reference-live shrink-0 text-sm font-700"
>
{{ usePrice(selectedReferenceTotal) }}
</span>
<span
v-else-if="isOrphanReference"
class="price-reference-live-empty shrink-0 text-sm"
>
در لیست فعلی نیست
</span>
<span
v-else-if="form.reading_method"
class="price-reference-live-empty shrink-0 text-sm"
>
قیمت مرجع در دسترس نیست
</span>
</div>
<a-alert
v-if="isOrphanReference"
type="warning"
show-icon
class="!mb-0"
message="این مرجع قبلاً روی محصول ذخیره شده، ولی الان در لیست قیمت همکار نیست. یک مرجع معتبر انتخاب کنید یا فیلد را پاک کنید."
/>
</div>
</a-form-item>
<a-form-item v-if="!form.price_formula_enabled" name="price_offset_percent" class="!mb-0">
<template #label>
@@ -170,19 +228,30 @@
/>
</div>
<div class="rounded-lg border border-solid border-blue-200 bg-blue-50 px-3 py-2">
<div class="live-price-preview rounded-lg border border-solid px-3 py-2">
<div class="flex flex-col gap-2 md:flex-row md:items-center md:justify-between md:gap-3">
<div class="flex flex-wrap items-center gap-x-3 gap-y-1 md:min-w-0 md:flex-1">
<DashboardLabelWithHelp label="قیمت لحظه‌ای" :help="livePriceHelp" size="sm" />
<span v-if="livePricePreview.status === 'ready'" class="text-base font-700 text-blue-700">
<DashboardLabelWithHelp
label="قیمت لحظه‌ای"
:help="livePriceHelp"
size="sm"
text-class="live-price-preview__label"
/>
<span
v-if="livePricePreview.status === 'ready'"
class="live-price-preview__amount text-base font-700"
>
{{ usePrice(livePricePreview.amount) }}
</span>
<span v-else-if="livePricePreview.message" class="text-sm text-gray-500">
<span
v-else-if="livePricePreview.message"
class="live-price-preview__message text-sm"
>
{{ livePricePreview.message }}
</span>
<span
v-if="livePricePreview.status === 'ready'"
class="truncate text-xs text-gray-500"
class="live-price-preview__source truncate text-xs"
>
مبنا: {{ livePricePreview.source }}
<span v-if="!form.price_formula_enabled && Number(form.price_offset_percent) !== 0">
@@ -508,7 +577,7 @@ import type { last } from '@/model/price'
import type { MethodePrices } from '@/model/product'
import { usePrice } from '@core/utils/usePrice'
import { isMeltedTradeGroup, resolveProductTradeTypeLabel, usesMeltedPriceEditor } from '@/utils/productCategories'
import { computeProductEditorPricePreview, findMethodPriceEntry, normalizeReferenceBase } from '@/utils/productEditorPrice'
import { computeProductEditorPricePreview, findMethodPriceEntry, normalizeReferenceBase, referenceProviderTotal, isOrphanReadingMethod } from '@/utils/productEditorPrice'
import { resolveTradeWeightUnit, weightFieldLabelForUnit } from '@/utils/weightUnit'
import type { DashboardHelp } from '@/pages/dashboard/dashboardSectionCopy'
import DashboardLabelWithHelp from '@/pages/dashboard/components/DashboardLabelWithHelp.vue'
@@ -700,8 +769,20 @@ const livePricePreview = computed(() =>
})
)
const selectedReferenceEntry = computed(() =>
findMethodPriceEntry(props.pricesData, props.form.reading_method)
)
const selectedReferenceTotal = computed(() =>
referenceProviderTotal(selectedReferenceEntry.value)
)
const isOrphanReference = computed(() =>
isOrphanReadingMethod(props.form.reading_method, props.pricesData)
)
const formulaReferenceMiddlePrice = computed(() => {
const entry = findMethodPriceEntry(props.pricesData, props.form.reading_method)
const entry = selectedReferenceEntry.value
if (!entry) {
return 0
}
@@ -942,4 +1023,58 @@ defineExpose({
.product-editor-form :deep(.product-cash-fee-field .ant-input-group .ant-input) {
padding-block: 0.5rem;
}
.live-price-preview {
border-color: #bfdbfe;
background: #eff6ff;
}
.live-price-preview__label {
color: #1e3a8a;
}
.live-price-preview__amount {
color: #1d4ed8;
}
.live-price-preview__message,
.live-price-preview__source {
color: #6b7280;
}
.price-reference-live {
color: #1d4ed8;
}
.price-reference-live-empty {
color: #6b7280;
}
</style>
<style>
html.is-dark .live-price-preview {
border-color: rgba(29, 78, 216, 0.55);
background: rgba(23, 37, 84, 0.55);
}
html.is-dark .live-price-preview__label {
color: #bfdbfe;
}
html.is-dark .live-price-preview__amount {
color: #93c5fd;
}
html.is-dark .live-price-preview__message,
html.is-dark .live-price-preview__source {
color: #d1d5db;
}
html.is-dark .price-reference-live {
color: #93c5fd;
}
html.is-dark .price-reference-live-empty {
color: #d1d5db;
}
</style>
+28 -6
View File
@@ -76,7 +76,7 @@ import ProductEditorFormBody from '@/pages/menuPages/products/base/components/Pr
import { validateProductSubmitInput } from '@/pages/menuPages/products/base/productFormValidation'
import tbl from './components/table.vue'
import { usePrice } from '@core/utils/usePrice'
import { referenceProviderTotal } from '@/utils/productEditorPrice'
import { referenceProviderTotal, resolveReadingMethodForSelect, canonicalMethodPriceId, isOrphanReadingMethod } from '@/utils/productEditorPrice'
import {
applyFileToUploadList,
normalizeFileResource,
@@ -151,16 +151,37 @@ const pricesData = ref<MethodePrices[]>([])
const appLastPrice = ref<(last & { price?: number }) | null>(null)
let pricePollTimer: ReturnType<typeof setInterval> | undefined
const pricesList = computed(() =>
pricesData.value.map((x) => ({
id: `${x.key ?? x.id ?? x.name}`,
const pricesList = computed(() => {
const list = pricesData.value.map((x) => ({
id: canonicalMethodPriceId(x),
name: `${x.name} (${usePrice(referenceProviderTotal(x))})`,
})),
)
}))
const raw = String(form.value.reading_method ?? '').trim()
// مقدار یتیم از DB: Select آن را نشان می‌دهد حتی اگر در options نباشد — صریح علامت بزن
if (raw && isOrphanReadingMethod(raw, pricesData.value) && !list.some((item) => item.id === raw)) {
list.unshift({
id: raw,
name: `${raw} — در لیست فعلی همکار نیست`,
})
}
return list
})
function syncReadingMethodToSelectValue() {
if (!form.value.reading_method || !pricesData.value.length) return
if (isOrphanReadingMethod(form.value.reading_method, pricesData.value)) return
const resolved = resolveReadingMethodForSelect(form.value.reading_method, pricesData.value)
if (resolved && resolved !== form.value.reading_method) {
form.value.reading_method = resolved
}
}
async function fetchPrices() {
try {
pricesData.value = await methodePrices()
syncReadingMethodToSelectValue()
} catch (err) {
console.error(err)
}
@@ -364,6 +385,7 @@ async function edit(record: Product) {
auto_open_at: start.isValid() ? start : dayjs('00:00:00', 'HH:mm:ss'),
auto_close_at: close.isValid() ? close : dayjs('00:00:00', 'HH:mm:ss')
})
syncReadingMethodToSelectValue()
await setProductIndexImage(productData, record.id)
} catch (err) {
+57 -9
View File
@@ -12,12 +12,45 @@ export function findMethodPriceEntry(
): MethodePrices | undefined {
if (!readingMethod) return undefined
return prices.find(
(entry) =>
entry.key === readingMethod ||
entry.id === readingMethod ||
entry.name === readingMethod
)
const needle = String(readingMethod).trim()
if (!needle) return undefined
return prices.find((entry) => {
const key = String(entry.key ?? '').trim()
const id = String(entry.id ?? '').trim()
const name = String(entry.name ?? '').trim()
return key === needle || id === needle || name === needle
})
}
/** مقدار value سلکت مرجع — key خالی را با ?? نگه نمی‌دارد */
export function canonicalMethodPriceId(entry: MethodePrices): string {
return String(entry.key || entry.id || entry.name || '').trim()
}
/** reading_method ذخیره‌شده (name/key/id) را به id سلکت هم‌تراز می‌کند */
export function resolveReadingMethodForSelect(
raw: string | null | undefined,
prices: MethodePrices[]
): string | null | undefined {
if (raw == null) return raw
const trimmed = String(raw).trim()
if (!trimmed) return raw
const entry = findMethodPriceEntry(prices, trimmed)
if (!entry) return trimmed
return canonicalMethodPriceId(entry) || trimmed
}
/** مرجع روی محصول هست ولی در فید/لیست فعلی همکار پیدا نمی‌شود */
export function isOrphanReadingMethod(
raw: string | null | undefined,
prices: MethodePrices[]
): boolean {
const trimmed = String(raw ?? '').trim()
if (!trimmed || !prices.length) return false
return !findMethodPriceEntry(prices, trimmed)
}
export function normalizeReferenceBase(entry: MethodePrices): { base: number; profit: number } {
@@ -117,7 +150,12 @@ export function computeProductEditorPricePreview(input: {
}
const entry = findMethodPriceEntry(input.pricesData, input.form.reading_method)
if (!entry) {
return { status: 'empty', message: '' }
return {
status: 'empty',
message: input.pricesData.length
? 'مرجع در لیست قیمت یافت نشد'
: 'لیست قیمت مرجع خالی است — بروزرسانی را بزنید',
}
}
const { base } = normalizeReferenceBase(entry)
if (base <= 0) {
@@ -177,7 +215,12 @@ export function computeProductEditorPricePreview(input: {
}
const entry = findMethodPriceEntry(input.pricesData, input.form.reading_method)
if (!entry) {
return { status: 'empty', message: '' }
return {
status: 'empty',
message: input.pricesData.length
? 'مرجع در لیست قیمت یافت نشد'
: 'لیست قیمت مرجع خالی است — بروزرسانی را بزنید',
}
}
const { base, profit } = normalizeReferenceBase(entry)
const liveAmount = adjustedProductPrice(base, profit, offsetPercent)
@@ -232,7 +275,12 @@ export function computeProductEditorPricePreview(input: {
}
const entry = findMethodPriceEntry(input.pricesData, input.form.reading_method)
if (!entry) {
return { status: 'empty', message: '' }
return {
status: 'empty',
message: input.pricesData.length
? 'مرجع در لیست قیمت یافت نشد'
: 'لیست قیمت مرجع خالی است — بروزرسانی را بزنید',
}
}
const { base, profit } = normalizeReferenceBase(entry)
const liveAmount = adjustedProductPrice(base, profit, offsetPercent)