Stop applying special pricing twice on live quotes so sell stays below buy.
Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -3,6 +3,13 @@ export type ProductCashFeeSource = {
|
||||
cash_fee_sell?: number | null
|
||||
cash_fee_buy_is_percent?: boolean | null
|
||||
cash_fee_sell_is_percent?: boolean | null
|
||||
special_profit_buy?: number | null
|
||||
special_profit_sell?: number | null
|
||||
}
|
||||
|
||||
export type ProductCashFeeOptions = {
|
||||
/** پیشفرض true. اگر مظنهٔ last از قبل special_pricing دارد باید false باشد. */
|
||||
includeSpecial?: boolean
|
||||
}
|
||||
|
||||
/** 0.5 => 0.5% ، 5 => 5% — همیشه عدد درصد */
|
||||
@@ -42,23 +49,37 @@ export function resolveProductCashFeeRial(
|
||||
return Math.round(Math.abs(base * resolveCashFeePercentRatio(raw)))
|
||||
}
|
||||
|
||||
export function resolveProductCashFeeBuyRial(product: ProductCashFeeSource, basePriceRial: number) {
|
||||
export function resolveProductCashFeeBuyRial(
|
||||
product: ProductCashFeeSource,
|
||||
basePriceRial: number,
|
||||
options?: ProductCashFeeOptions,
|
||||
) {
|
||||
const baseFee = resolveProductCashFeeRial(
|
||||
product.cash_fee_buy,
|
||||
product.cash_fee_buy_is_percent,
|
||||
basePriceRial,
|
||||
)
|
||||
const special = Number((product as any).special_profit_buy ?? 0)
|
||||
if (options?.includeSpecial === false) {
|
||||
return baseFee
|
||||
}
|
||||
const special = Number(product.special_profit_buy ?? 0)
|
||||
return baseFee + (Number.isFinite(special) ? Math.round(special) : 0)
|
||||
}
|
||||
|
||||
export function resolveProductCashFeeSellRial(product: ProductCashFeeSource, basePriceRial: number) {
|
||||
export function resolveProductCashFeeSellRial(
|
||||
product: ProductCashFeeSource,
|
||||
basePriceRial: number,
|
||||
options?: ProductCashFeeOptions,
|
||||
) {
|
||||
const baseFee = resolveProductCashFeeRial(
|
||||
product.cash_fee_sell,
|
||||
product.cash_fee_sell_is_percent,
|
||||
basePriceRial,
|
||||
)
|
||||
const special = Number((product as any).special_profit_sell ?? 0)
|
||||
if (options?.includeSpecial === false) {
|
||||
return baseFee
|
||||
}
|
||||
const special = Number(product.special_profit_sell ?? 0)
|
||||
return baseFee + (Number.isFinite(special) ? Math.round(special) : 0)
|
||||
}
|
||||
|
||||
|
||||
@@ -10,6 +10,7 @@ import {
|
||||
usesQuantityTrade,
|
||||
} from '@/utils/productCategories'
|
||||
import { isProductTradingHoursOpen } from '@/utils/productTradeOpen'
|
||||
import { lastPriceIncludesSpecial } from '@/utils/specialPricing'
|
||||
|
||||
/**
|
||||
* قیمتگیری محصول — همتراز با khaneghi_user:
|
||||
@@ -24,6 +25,42 @@ function hasReferenceReadingMethod(product: Product): boolean {
|
||||
return Boolean(product.reading_method)
|
||||
}
|
||||
|
||||
/** پایه از buy/sell مظنه آمده — special همانجا اعمال شده و نباید دوباره جمع شود */
|
||||
function productUsesLiveBoardQuote(product: Product, side: 'buy' | 'sell'): boolean {
|
||||
if (isColleaguePriceProduct(product)) {
|
||||
const stored = side === 'sell'
|
||||
? Number(product.sellPrice ?? product.price ?? 0)
|
||||
: Number(product.price ?? 0)
|
||||
if (stored > 0) {
|
||||
return false
|
||||
}
|
||||
const live = side === 'buy' ? getTradeBuyPrice(lastPrice.value) : getTradeSellPrice(lastPrice.value)
|
||||
return isMeltedTradeGroup(product.group_type) && live > 0
|
||||
}
|
||||
|
||||
if (isMeltedProductUsingAppPrice(product) || isAppPriceProduct(product)) {
|
||||
const live = side === 'buy' ? getTradeBuyPrice(lastPrice.value) : getTradeSellPrice(lastPrice.value)
|
||||
return live > 0
|
||||
}
|
||||
|
||||
return false
|
||||
}
|
||||
|
||||
function cashFeeOptions(product: Product, side: 'buy' | 'sell') {
|
||||
if (lastPriceIncludesSpecial(lastPrice.value) && productUsesLiveBoardQuote(product, side)) {
|
||||
return { includeSpecial: false as const }
|
||||
}
|
||||
return undefined
|
||||
}
|
||||
|
||||
function buyCashFee(product: Product, base: number) {
|
||||
return resolveProductCashFeeBuyRial(product, base, cashFeeOptions(product, 'buy'))
|
||||
}
|
||||
|
||||
function sellCashFee(product: Product, base: number) {
|
||||
return resolveProductCashFeeSellRial(product, base, cashFeeOptions(product, 'sell'))
|
||||
}
|
||||
|
||||
/** قیمت منبع همکار؛ اگر خالی بود آبشده همان مظنهٔ صفحه اصلی را میگیرد */
|
||||
function getColleagueSourcedUnitPrice(product: Product, live: number, apiPrice = Number(product.price ?? 0)): number {
|
||||
if (apiPrice > 0) {
|
||||
@@ -137,7 +174,7 @@ export function getProductBuyPrice(product?: Product | null): number {
|
||||
return 0
|
||||
}
|
||||
|
||||
const fee = resolveProductCashFeeBuyRial(product, base)
|
||||
const fee = buyCashFee(product, base)
|
||||
const withFee = base + fee
|
||||
|
||||
if (isColleaguePriceProduct(product)) {
|
||||
@@ -216,28 +253,28 @@ export function getProductSellPrice(product?: Product | null): number {
|
||||
}
|
||||
|
||||
if (isColleaguePriceProduct(product)) {
|
||||
return base - resolveProductCashFeeSellRial(product, base)
|
||||
return base - sellCashFee(product, base)
|
||||
}
|
||||
|
||||
if (isAppPriceProduct(product)) {
|
||||
const withFee = base - resolveProductCashFeeSellRial(product, base)
|
||||
const withFee = base - sellCashFee(product, base)
|
||||
return withFee * productPriceAmountFactor(product)
|
||||
}
|
||||
|
||||
if (isMeltedProductUsingAppPrice(product) || isMeltedTradeGroup(product.group_type)) {
|
||||
return base - resolveProductCashFeeSellRial(product, base)
|
||||
return base - sellCashFee(product, base)
|
||||
}
|
||||
|
||||
if (usesQuantityTrade(product) && hasProductUnitWeight(product)) {
|
||||
const withFee = base - resolveProductCashFeeSellRial(product, base)
|
||||
const withFee = base - sellCashFee(product, base)
|
||||
return withFee * productPriceAmountFactor(product)
|
||||
}
|
||||
|
||||
if (usesQuantityTrade(product)) {
|
||||
return base - resolveProductCashFeeSellRial(product, base)
|
||||
return base - sellCashFee(product, base)
|
||||
}
|
||||
|
||||
return base - resolveProductCashFeeSellRial(product, base)
|
||||
return base - sellCashFee(product, base)
|
||||
}
|
||||
|
||||
/** کارت فروشگاه: قیمت نمایشی صفر → «بدون قیمت» */
|
||||
|
||||
@@ -48,6 +48,13 @@ export function getSpecialPricingState() {
|
||||
return state
|
||||
}
|
||||
|
||||
/** مظنهٔ last از قبل اختلاف ویژه دارد (سرور یا applyBoardSpecial) */
|
||||
export function lastPriceIncludesSpecial(
|
||||
payload?: { special_pricing?: unknown } | null,
|
||||
): boolean {
|
||||
return Boolean(payload && typeof payload === 'object' && payload.special_pricing)
|
||||
}
|
||||
|
||||
/** اگر سرور قبلاً special_pricing نزده، اختلاف تابلو را روی last اعمال کن */
|
||||
export function applyBoardSpecialToLastPayload<T extends Record<string, any>>(payload: T): T {
|
||||
if (!payload || typeof payload !== 'object') return payload
|
||||
|
||||
Reference in New Issue
Block a user