add price into product
This commit is contained in:
@@ -12,7 +12,9 @@
|
|||||||
:mode="props.mode"
|
:mode="props.mode"
|
||||||
:style="props.style"
|
:style="props.style"
|
||||||
:multiple="props.multiple"
|
:multiple="props.multiple"
|
||||||
:dropdown-style="dropdownStyle"
|
:dropdown-style="mergedDropdownStyle"
|
||||||
|
:popup-class-name="props.popupClassName"
|
||||||
|
:dropdown-match-select-width="props.dropdownMatchSelectWidth"
|
||||||
@change="handleChange"
|
@change="handleChange"
|
||||||
:placeholder="props.placeholder"
|
:placeholder="props.placeholder"
|
||||||
:allowClear="props.allowClear"
|
:allowClear="props.allowClear"
|
||||||
@@ -60,13 +62,22 @@ interface Prop {
|
|||||||
allowClear?: boolean
|
allowClear?: boolean
|
||||||
hasTooltip?: boolean
|
hasTooltip?: boolean
|
||||||
noData?: string
|
noData?: string
|
||||||
|
popupClassName?: string
|
||||||
|
dropdownMatchSelectWidth?: boolean
|
||||||
|
dropdownStyle?: Record<string, string | number>
|
||||||
}
|
}
|
||||||
|
|
||||||
const props = withDefaults(defineProps<Prop>(), {
|
const props = withDefaults(defineProps<Prop>(), {
|
||||||
allowClear: true,
|
allowClear: true,
|
||||||
hasTooltip: true
|
hasTooltip: true,
|
||||||
|
dropdownMatchSelectWidth: true
|
||||||
})
|
})
|
||||||
|
|
||||||
|
const mergedDropdownStyle = computed(() => ({
|
||||||
|
...dropdownStyle,
|
||||||
|
...(props.dropdownStyle ?? {})
|
||||||
|
}))
|
||||||
|
|
||||||
// console.log('props.items ====>', props.items)
|
// console.log('props.items ====>', props.items)
|
||||||
//define emits
|
//define emits
|
||||||
const emit = defineEmits(['update:value', 'change'])
|
const emit = defineEmits(['update:value', 'change'])
|
||||||
|
|||||||
@@ -43,7 +43,8 @@ export interface Product{
|
|||||||
}
|
}
|
||||||
|
|
||||||
export interface MethodePrices {
|
export interface MethodePrices {
|
||||||
id: string
|
key?: string
|
||||||
|
id?: string
|
||||||
name: string
|
name: string
|
||||||
price: number
|
price: number
|
||||||
profit: number
|
profit: number
|
||||||
|
|||||||
@@ -18,10 +18,21 @@
|
|||||||
<span>قیمت ثابت :</span>
|
<span>قیمت ثابت :</span>
|
||||||
<BasicInput class="md:w-[20rem]" addon-before="ریال" type="price" v-model:value="form.price" />
|
<BasicInput class="md:w-[20rem]" addon-before="ریال" type="price" v-model:value="form.price" />
|
||||||
</div>
|
</div>
|
||||||
<div v-if="meltedPriceOption === 'reference'" class="flex flex-col gap-2">
|
<div v-if="meltedPriceOption === 'reference'" class="flex flex-col gap-2 md:min-w-[28rem]">
|
||||||
<div class="md:flex justify-between items-center">
|
<div class="flex flex-col gap-1">
|
||||||
<div class="ml-4">مرجع قیمت :</div>
|
<div>مرجع قیمت :</div>
|
||||||
<BasicSelect class="w-11rem method_style" allowClear :items="pricesList" valueName="name" keyName="id" v-model:value="form.reading_method" />
|
<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>
|
</div>
|
||||||
<div class="md:flex justify-between items-center">
|
<div class="md:flex justify-between items-center">
|
||||||
<div class="ml-4">تعدیل نسبت به قیمت مرجع (٪) :</div>
|
<div class="ml-4">تعدیل نسبت به قیمت مرجع (٪) :</div>
|
||||||
@@ -74,10 +85,21 @@
|
|||||||
<template #icon><Icon icon="vuesax-linear:minus" size="20" /></template>
|
<template #icon><Icon icon="vuesax-linear:minus" size="20" /></template>
|
||||||
</AButton>
|
</AButton>
|
||||||
</div>
|
</div>
|
||||||
<div v-if="methodOption === '2'" class="flex flex-col gap-2">
|
<div v-if="methodOption === '2'" class="flex flex-col gap-2 md:min-w-[28rem]">
|
||||||
<div class="md:flex justify-between items-center">
|
<div class="flex flex-col gap-1">
|
||||||
<div class="ml-4">قیمت :</div>
|
<div>قیمت :</div>
|
||||||
<BasicSelect class="w-11rem method_style" allowClear :items="pricesList" valueName="name" keyName="id" v-model:value="form.reading_method" />
|
<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>
|
</div>
|
||||||
<div class="md:flex justify-between items-center">
|
<div class="md:flex justify-between items-center">
|
||||||
<div class="ml-4">تعدیل نسبت به قیمت مرجع (٪) :</div>
|
<div class="ml-4">تعدیل نسبت به قیمت مرجع (٪) :</div>
|
||||||
@@ -95,6 +117,30 @@
|
|||||||
</div>
|
</div>
|
||||||
</div>
|
</div>
|
||||||
|
|
||||||
|
<div class="mt-2 rounded-lg border border-solid border-blue-200 bg-blue-50 p-3">
|
||||||
|
<div class="flex flex-wrap items-center justify-between gap-2">
|
||||||
|
<div class="text-sm font-600 text-gray-700">قیمت لحظهای</div>
|
||||||
|
<AButton size="small" :loading="pricesLoading || appPriceLoading" @click="$emit('refreshPrices')">
|
||||||
|
بروزرسانی
|
||||||
|
</AButton>
|
||||||
|
</div>
|
||||||
|
<div v-if="livePricePreview.status === 'ready'" class="mt-2 text-lg font-700 text-blue-700">
|
||||||
|
{{ usePrice(livePricePreview.amount) }}
|
||||||
|
</div>
|
||||||
|
<div v-else-if="livePricePreview.status === 'loading'" class="mt-2 text-sm text-gray-500">
|
||||||
|
{{ livePricePreview.message }}
|
||||||
|
</div>
|
||||||
|
<div v-else class="mt-2 text-sm text-gray-500">
|
||||||
|
{{ livePricePreview.message }}
|
||||||
|
</div>
|
||||||
|
<div v-if="livePricePreview.status === 'ready'" class="mt-1 text-xs text-gray-500">
|
||||||
|
مبنا: {{ livePricePreview.source }}
|
||||||
|
<span v-if="Number(form.price_offset_percent) !== 0">
|
||||||
|
— تعدیل {{ form.price_offset_percent }}٪
|
||||||
|
</span>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
|
||||||
<div
|
<div
|
||||||
v-if="!isMeltedCategory"
|
v-if="!isMeltedCategory"
|
||||||
class="md:flex justify-between p-2 border-1 border-solid rounded-lg border-gray-200 mt-2"
|
class="md:flex justify-between p-2 border-1 border-solid rounded-lg border-gray-200 mt-2"
|
||||||
@@ -183,7 +229,11 @@ import Icon from '@core/components/BaseIcon/src/Icon.vue'
|
|||||||
import BaseCollapse from '@/components/BaseCollapse.vue'
|
import BaseCollapse from '@/components/BaseCollapse.vue'
|
||||||
import IndexImageUploader from '@/components/ProductUploader/IndexImageUploader.vue'
|
import IndexImageUploader from '@/components/ProductUploader/IndexImageUploader.vue'
|
||||||
import { getConfiguration } from '@/api/configuration'
|
import { getConfiguration } from '@/api/configuration'
|
||||||
|
import type { last } from '@/model/price'
|
||||||
|
import type { MethodePrices } from '@/model/product'
|
||||||
|
import { usePrice } from '@core/utils/usePrice'
|
||||||
import { isMeltedTradeGroup } from '@/utils/productCategories'
|
import { isMeltedTradeGroup } from '@/utils/productCategories'
|
||||||
|
import { computeProductEditorPricePreview } from '@/utils/productEditorPrice'
|
||||||
import { resolveTradeWeightUnit, weightFieldLabelForUnit } from '@/utils/weightUnit'
|
import { resolveTradeWeightUnit, weightFieldLabelForUnit } from '@/utils/weightUnit'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import { computed, onMounted, ref, watch } from 'vue'
|
import { computed, onMounted, ref, watch } from 'vue'
|
||||||
@@ -196,6 +246,10 @@ const props = defineProps<{
|
|||||||
meltedPriceOption: string
|
meltedPriceOption: string
|
||||||
activeKey: string[]
|
activeKey: string[]
|
||||||
pricesList: Array<{ id: string; name: string }>
|
pricesList: Array<{ id: string; name: string }>
|
||||||
|
pricesData: MethodePrices[]
|
||||||
|
pricesLoading: boolean
|
||||||
|
appLastPrice: (last & { price?: number }) | null
|
||||||
|
appPriceLoading: boolean
|
||||||
categoryItems: any[]
|
categoryItems: any[]
|
||||||
metalItems: any[]
|
metalItems: any[]
|
||||||
priceItems: any[]
|
priceItems: any[]
|
||||||
@@ -208,6 +262,18 @@ const props = defineProps<{
|
|||||||
const tradeWeightUnit = ref('گرم')
|
const tradeWeightUnit = ref('گرم')
|
||||||
const isMeltedCategory = computed(() => isMeltedTradeGroup(props.form.group_type))
|
const isMeltedCategory = computed(() => isMeltedTradeGroup(props.form.group_type))
|
||||||
|
|
||||||
|
const livePricePreview = computed(() =>
|
||||||
|
computeProductEditorPricePreview({
|
||||||
|
form: props.form,
|
||||||
|
methodOption: props.methodOption,
|
||||||
|
meltedPriceOption: props.meltedPriceOption as 'app' | 'fixed' | 'reference',
|
||||||
|
pricesData: props.pricesData,
|
||||||
|
appLastPrice: props.appLastPrice,
|
||||||
|
pricesLoading: props.pricesLoading,
|
||||||
|
appPriceLoading: props.appPriceLoading
|
||||||
|
})
|
||||||
|
)
|
||||||
|
|
||||||
watch(
|
watch(
|
||||||
() => props.meltedPriceOption,
|
() => props.meltedPriceOption,
|
||||||
(option) => {
|
(option) => {
|
||||||
@@ -263,5 +329,34 @@ defineEmits<{
|
|||||||
(e: 'update:productIndexImage', value: any[]): void
|
(e: 'update:productIndexImage', value: any[]): void
|
||||||
(e: 'uploadedIndexFile', id: number, response?: Record<string, any>): void
|
(e: 'uploadedIndexFile', id: number, response?: Record<string, any>): void
|
||||||
(e: 'deleteIndexFile'): void
|
(e: 'deleteIndexFile'): void
|
||||||
|
(e: 'refreshPrices'): void
|
||||||
}>()
|
}>()
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
|
<style scoped>
|
||||||
|
.price-reference-select {
|
||||||
|
width: 100%;
|
||||||
|
min-width: 22rem;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-reference-select :deep(.ant-select-selector) {
|
||||||
|
height: auto !important;
|
||||||
|
min-height: 32px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.price-reference-select :deep(.ant-select-selection-item) {
|
||||||
|
white-space: normal;
|
||||||
|
line-height: 1.4;
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: unset;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|
||||||
|
<style>
|
||||||
|
.price-reference-select-dropdown .ant-select-item-option-content {
|
||||||
|
white-space: normal;
|
||||||
|
overflow: visible;
|
||||||
|
text-overflow: unset;
|
||||||
|
line-height: 1.4;
|
||||||
|
}
|
||||||
|
</style>
|
||||||
|
|||||||
@@ -23,6 +23,10 @@
|
|||||||
:weightOption="weightOption"
|
:weightOption="weightOption"
|
||||||
:activeKey="activeKey_"
|
:activeKey="activeKey_"
|
||||||
:pricesList="pricesList"
|
:pricesList="pricesList"
|
||||||
|
:pricesData="pricesData"
|
||||||
|
:pricesLoading="pricesLoading"
|
||||||
|
:appLastPrice="appLastPrice"
|
||||||
|
:appPriceLoading="appPriceLoading"
|
||||||
:categoryItems="categorySelectItems"
|
:categoryItems="categorySelectItems"
|
||||||
:metalItems="metalItems"
|
:metalItems="metalItems"
|
||||||
:priceItems="priceItems"
|
:priceItems="priceItems"
|
||||||
@@ -40,6 +44,7 @@
|
|||||||
@minusPrice="minusPrice"
|
@minusPrice="minusPrice"
|
||||||
@uploadedIndexFile="uploadedIndexFile"
|
@uploadedIndexFile="uploadedIndexFile"
|
||||||
@deleteIndexFile="deleteIndexFile"
|
@deleteIndexFile="deleteIndexFile"
|
||||||
|
@refreshPrices="refreshLivePrices"
|
||||||
/>
|
/>
|
||||||
</BasicActionSheet>
|
</BasicActionSheet>
|
||||||
</div>
|
</div>
|
||||||
@@ -52,10 +57,11 @@ import locale from 'ant-design-vue/es/date-picker/locale/fa_IR'
|
|||||||
import { cloneDeep } from 'lodash'
|
import { cloneDeep } from 'lodash'
|
||||||
import dayjs from 'dayjs'
|
import dayjs from 'dayjs'
|
||||||
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
import customParseFormat from 'dayjs/plugin/customParseFormat'
|
||||||
import { computed, nextTick, onMounted, ref } from 'vue'
|
import { computed, nextTick, onMounted, onUnmounted, ref, watch } from 'vue'
|
||||||
import { createProduct, getCustomerById, updateCustomer } from '@/api/product'
|
import { createProduct, getCustomerById, updateCustomer } from '@/api/product'
|
||||||
import { fetchProductImageUrl } from '@/api/file'
|
import { fetchProductImageUrl } from '@/api/file'
|
||||||
import { methodePrices } from '@/api/price'
|
import { getLastPrice, methodePrices } from '@/api/price'
|
||||||
|
import type { last } from '@/model/price'
|
||||||
import BasicActionSheet from '@/components/BasicActionSheet.vue'
|
import BasicActionSheet from '@/components/BasicActionSheet.vue'
|
||||||
import type { Item } from '@/model/Item'
|
import type { Item } from '@/model/Item'
|
||||||
import type { MethodePrices, Product } from '@/model/product'
|
import type { MethodePrices, Product } from '@/model/product'
|
||||||
@@ -123,23 +129,74 @@ const priceItems: Array<Item> = [
|
|||||||
]
|
]
|
||||||
|
|
||||||
const pricesData = ref<MethodePrices[]>([])
|
const pricesData = ref<MethodePrices[]>([])
|
||||||
|
const pricesLoading = ref(false)
|
||||||
|
const appLastPrice = ref<(last & { price?: number }) | null>(null)
|
||||||
|
const appPriceLoading = ref(false)
|
||||||
|
let pricePollTimer: ReturnType<typeof setInterval> | undefined
|
||||||
|
|
||||||
const pricesList = computed(() =>
|
const pricesList = computed(() =>
|
||||||
pricesData.value.map((x) => ({
|
pricesData.value.map((x) => ({
|
||||||
id: `${x.name}`,
|
id: `${x.key ?? x.id ?? x.name}`,
|
||||||
name: `${x.name}(${usePrice(x.price)})`
|
name: `${x.name} (${usePrice(x.price)})`
|
||||||
}))
|
}))
|
||||||
)
|
)
|
||||||
|
|
||||||
async function fetchPrices() {
|
async function fetchPrices() {
|
||||||
|
pricesLoading.value = true
|
||||||
try {
|
try {
|
||||||
pricesData.value = await methodePrices()
|
pricesData.value = await methodePrices()
|
||||||
} catch (err) {
|
} catch (err) {
|
||||||
console.error(err)
|
console.error(err)
|
||||||
|
} finally {
|
||||||
|
pricesLoading.value = false
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
async function fetchAppPrice() {
|
||||||
|
appPriceLoading.value = true
|
||||||
|
try {
|
||||||
|
appLastPrice.value = await getLastPrice()
|
||||||
|
} catch (err) {
|
||||||
|
console.error(err)
|
||||||
|
appLastPrice.value = null
|
||||||
|
} finally {
|
||||||
|
appPriceLoading.value = false
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
async function refreshLivePrices() {
|
||||||
|
await Promise.all([fetchPrices(), fetchAppPrice()])
|
||||||
|
}
|
||||||
|
|
||||||
|
function startPricePolling() {
|
||||||
|
stopPricePolling()
|
||||||
|
void refreshLivePrices()
|
||||||
|
pricePollTimer = setInterval(() => {
|
||||||
|
void refreshLivePrices()
|
||||||
|
}, 10000)
|
||||||
|
}
|
||||||
|
|
||||||
|
function stopPricePolling() {
|
||||||
|
if (pricePollTimer) {
|
||||||
|
clearInterval(pricePollTimer)
|
||||||
|
pricePollTimer = undefined
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
watch(addUserVisible, (visible) => {
|
||||||
|
if (visible) {
|
||||||
|
startPricePolling()
|
||||||
|
} else {
|
||||||
|
stopPricePolling()
|
||||||
|
}
|
||||||
|
})
|
||||||
|
|
||||||
onMounted(() => {
|
onMounted(() => {
|
||||||
fetchPrices()
|
void refreshLivePrices()
|
||||||
|
})
|
||||||
|
|
||||||
|
onUnmounted(() => {
|
||||||
|
stopPricePolling()
|
||||||
})
|
})
|
||||||
|
|
||||||
function uploadedIndexFile(id: number, response?: Record<string, any>) {
|
function uploadedIndexFile(id: number, response?: Record<string, any>) {
|
||||||
@@ -372,8 +429,3 @@ const minusPrice = () => {
|
|||||||
}
|
}
|
||||||
</script>
|
</script>
|
||||||
|
|
||||||
<style scoped>
|
|
||||||
.method_style .ant-select-selector {
|
|
||||||
width: 15rem !important;
|
|
||||||
}
|
|
||||||
</style>
|
|
||||||
|
|||||||
@@ -0,0 +1,141 @@
|
|||||||
|
import type { last } from '@/model/price'
|
||||||
|
import type { MethodePrices } from '@/model/product'
|
||||||
|
import type { MeltedPriceSource } from '@/utils/productCategories'
|
||||||
|
import { isMeltedTradeGroup } from '@/utils/productCategories'
|
||||||
|
|
||||||
|
const GOLD_DOT_REFERENCE_NAME = 'گلد دات ای از آبشده - رسمی - نقد فردا'
|
||||||
|
|
||||||
|
export function findMethodPriceEntry(
|
||||||
|
prices: MethodePrices[],
|
||||||
|
readingMethod?: string | null
|
||||||
|
): MethodePrices | undefined {
|
||||||
|
if (!readingMethod) return undefined
|
||||||
|
|
||||||
|
return prices.find(
|
||||||
|
(entry) =>
|
||||||
|
entry.key === readingMethod ||
|
||||||
|
entry.id === readingMethod ||
|
||||||
|
entry.name === readingMethod
|
||||||
|
)
|
||||||
|
}
|
||||||
|
|
||||||
|
export function normalizeReferenceBase(entry: MethodePrices): { base: number; profit: number } {
|
||||||
|
let base = Number(entry.price) || 0
|
||||||
|
const profit = Number(entry.profit) || 0
|
||||||
|
|
||||||
|
if (entry.name === GOLD_DOT_REFERENCE_NAME) {
|
||||||
|
base = base / 4.3318
|
||||||
|
}
|
||||||
|
|
||||||
|
return { base, profit }
|
||||||
|
}
|
||||||
|
|
||||||
|
export function adjustedProductPrice(
|
||||||
|
basePrice: number,
|
||||||
|
baseProfit: number,
|
||||||
|
offsetPercent: number
|
||||||
|
): number {
|
||||||
|
const reference = basePrice + baseProfit
|
||||||
|
return Math.round(reference * (1 + (Number(offsetPercent) || 0) / 100))
|
||||||
|
}
|
||||||
|
|
||||||
|
export function resolveAppBasePrice(lastPrice?: Partial<last> & { price?: number } | null): number {
|
||||||
|
if (!lastPrice) return 0
|
||||||
|
|
||||||
|
const rawPrice = Number(lastPrice.price)
|
||||||
|
if (rawPrice > 0) return rawPrice
|
||||||
|
|
||||||
|
const buy = Number(lastPrice.buy) || 0
|
||||||
|
const sell = Number(lastPrice.sell) || 0
|
||||||
|
if (buy > 0 && sell > 0) return Math.round((buy + sell) / 2)
|
||||||
|
|
||||||
|
return Number(lastPrice.price_last) || 0
|
||||||
|
}
|
||||||
|
|
||||||
|
export type ProductEditorPricePreview =
|
||||||
|
| { status: 'ready'; amount: number; source: string }
|
||||||
|
| { status: 'empty'; message: string }
|
||||||
|
| { status: 'loading'; message: string }
|
||||||
|
|
||||||
|
export function computeProductEditorPricePreview(input: {
|
||||||
|
form: {
|
||||||
|
group_type?: string
|
||||||
|
price?: number | null
|
||||||
|
reading_method?: string | null
|
||||||
|
price_offset_percent?: number | null
|
||||||
|
}
|
||||||
|
methodOption: string
|
||||||
|
meltedPriceOption: MeltedPriceSource
|
||||||
|
pricesData: MethodePrices[]
|
||||||
|
appLastPrice?: (Partial<last> & { price?: number }) | null
|
||||||
|
pricesLoading?: boolean
|
||||||
|
appPriceLoading?: boolean
|
||||||
|
}): ProductEditorPricePreview {
|
||||||
|
const offsetPercent = Number(input.form.price_offset_percent ?? 0)
|
||||||
|
const melted = isMeltedTradeGroup(input.form.group_type)
|
||||||
|
|
||||||
|
if (melted) {
|
||||||
|
if (input.meltedPriceOption === 'fixed') {
|
||||||
|
const amount = Number(input.form.price) || 0
|
||||||
|
return amount > 0
|
||||||
|
? { status: 'ready', amount, source: 'قیمت ثابت' }
|
||||||
|
: { status: 'empty', message: 'قیمت ثابت را وارد کنید' }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.meltedPriceOption === 'app') {
|
||||||
|
if (input.appPriceLoading) {
|
||||||
|
return { status: 'loading', message: 'در حال دریافت قیمت اپ...' }
|
||||||
|
}
|
||||||
|
const base = resolveAppBasePrice(input.appLastPrice)
|
||||||
|
if (base <= 0) {
|
||||||
|
return { status: 'empty', message: 'قیمت اپ در دسترس نیست' }
|
||||||
|
}
|
||||||
|
return {
|
||||||
|
status: 'ready',
|
||||||
|
amount: adjustedProductPrice(base, 0, offsetPercent),
|
||||||
|
source: 'قیمت صفحه اصلی اپ'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input.form.reading_method) {
|
||||||
|
return { status: 'empty', message: 'مرجع قیمت را انتخاب کنید' }
|
||||||
|
}
|
||||||
|
if (input.pricesLoading) {
|
||||||
|
return { status: 'loading', message: 'در حال دریافت قیمت مرجع...' }
|
||||||
|
}
|
||||||
|
const entry = findMethodPriceEntry(input.pricesData, input.form.reading_method)
|
||||||
|
if (!entry) {
|
||||||
|
return { status: 'empty', message: 'مرجع قیمت یافت نشد' }
|
||||||
|
}
|
||||||
|
const { base, profit } = normalizeReferenceBase(entry)
|
||||||
|
return {
|
||||||
|
status: 'ready',
|
||||||
|
amount: adjustedProductPrice(base, profit, offsetPercent),
|
||||||
|
source: entry.name
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (input.methodOption === '1') {
|
||||||
|
const amount = Number(input.form.price) || 0
|
||||||
|
return amount > 0
|
||||||
|
? { status: 'ready', amount, source: 'قیمت دستی' }
|
||||||
|
: { status: 'empty', message: 'قیمت وسط را وارد کنید' }
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!input.form.reading_method) {
|
||||||
|
return { status: 'empty', message: 'مرجع قیمت را انتخاب کنید' }
|
||||||
|
}
|
||||||
|
if (input.pricesLoading) {
|
||||||
|
return { status: 'loading', message: 'در حال دریافت قیمت مرجع...' }
|
||||||
|
}
|
||||||
|
const entry = findMethodPriceEntry(input.pricesData, input.form.reading_method)
|
||||||
|
if (!entry) {
|
||||||
|
return { status: 'empty', message: 'مرجع قیمت یافت نشد' }
|
||||||
|
}
|
||||||
|
const { base, profit } = normalizeReferenceBase(entry)
|
||||||
|
return {
|
||||||
|
status: 'ready',
|
||||||
|
amount: adjustedProductPrice(base, profit, offsetPercent),
|
||||||
|
source: entry.name
|
||||||
|
}
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user