Colleague quotes are per piece, and the settings service charge is a percent of that price times count. Co-authored-by: Cursor <cursoragent@cursor.com>
336 lines
8.5 KiB
TypeScript
336 lines
8.5 KiB
TypeScript
import type { Product } from '@/models/products'
|
|
import { getTradeBuyPrice, getTradeSellPrice, lastPrice } from '@/utils/price'
|
|
import { resolveProductCashFeeBuyRial, resolveProductCashFeeSellRial } from '@/utils/productCashFee'
|
|
import {
|
|
isAppPriceProduct,
|
|
isColleaguePriceProduct,
|
|
isMeltedProductUsingAppPrice,
|
|
isMeltedTradeGroup,
|
|
isMetalCommodityGroup,
|
|
usesQuantityTrade,
|
|
} from '@/utils/productCategories'
|
|
import { isProductTradingHoursOpen } from '@/utils/productTradeOpen'
|
|
|
|
/**
|
|
* قیمتگیری محصول — همتراز با khaneghi_user:
|
|
* آبشده / قیمتاپ از مظنه زنده؛ قیمت ثابت و مرجع از سرور.
|
|
*/
|
|
|
|
function productUsesLastPriceIfZero(product: Product): boolean {
|
|
return Boolean(product.use_last_price_if_zero)
|
|
}
|
|
|
|
function hasReferenceReadingMethod(product: Product): boolean {
|
|
return Boolean(product.reading_method)
|
|
}
|
|
|
|
function hasProductUnitWeight(product?: Product | null) {
|
|
if (!product || isMeltedTradeGroup(product.group_type)) {
|
|
return false
|
|
}
|
|
return Number(product.amount ?? 0) > 0
|
|
}
|
|
|
|
function productPriceAmountFactor(product?: Product | null) {
|
|
if (!product || product.reading_method || isColleaguePriceProduct(product)) {
|
|
return 1
|
|
}
|
|
if (isAppPriceProduct(product)) {
|
|
const amount = Number(product.amount ?? 0)
|
|
return amount > 0 ? amount : 1
|
|
}
|
|
if (hasProductUnitWeight(product) && Number(product.direct_price ?? 0) === 0) {
|
|
const amount = Number(product.amount ?? 0)
|
|
return amount > 0 ? amount : 1
|
|
}
|
|
return 1
|
|
}
|
|
|
|
function getReferenceProductBaseBuyPrice(product: Product): number {
|
|
const storedUnit = Number(product.price ?? 0)
|
|
const useLast = productUsesLastPriceIfZero(product)
|
|
|
|
if (!useLast) {
|
|
return storedUnit > 0 ? storedUnit : 0
|
|
}
|
|
|
|
return storedUnit
|
|
}
|
|
|
|
export function resolvePriceOffsetRatio(offsetPercent?: number | null) {
|
|
const offset = Number(offsetPercent ?? 0)
|
|
if (!offset) {
|
|
return 0
|
|
}
|
|
|
|
if (Math.abs(offset) > 0 && Math.abs(offset) < 1) {
|
|
return offset
|
|
}
|
|
|
|
return offset / 100
|
|
}
|
|
|
|
export function applyPriceOffsetPercent(basePrice: number, offsetPercent?: number | null) {
|
|
const ratio = resolvePriceOffsetRatio(offsetPercent)
|
|
if (!ratio) {
|
|
return basePrice
|
|
}
|
|
|
|
return Math.round(basePrice * (1 + ratio))
|
|
}
|
|
|
|
/** قیمت پایه بدون کارمزد */
|
|
export function getProductBaseBuyPrice(product?: Product | null): number {
|
|
if (!product) {
|
|
return 0
|
|
}
|
|
|
|
if (isMeltedProductUsingAppPrice(product) || isAppPriceProduct(product)) {
|
|
const apiPrice = Number(product.price ?? 0)
|
|
const useLast = productUsesLastPriceIfZero(product)
|
|
|
|
if (!useLast) {
|
|
const liveBuy = getTradeBuyPrice(lastPrice.value)
|
|
if (liveBuy > 0) {
|
|
return applyPriceOffsetPercent(liveBuy, product.price_offset_percent)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
if (apiPrice > 0) {
|
|
return apiPrice
|
|
}
|
|
|
|
const liveBuy = getTradeBuyPrice(lastPrice.value)
|
|
if (liveBuy > 0) {
|
|
return applyPriceOffsetPercent(liveBuy, product.price_offset_percent)
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
if (isMeltedTradeGroup(product.group_type)) {
|
|
return Number(product.price ?? 0)
|
|
}
|
|
|
|
if (isMetalCommodityGroup(product.group_type)) {
|
|
return Number(product.price_profit ?? 0) + Number(product.price ?? 0)
|
|
}
|
|
|
|
if (hasReferenceReadingMethod(product)) {
|
|
return getReferenceProductBaseBuyPrice(product)
|
|
}
|
|
|
|
return Number(product.price ?? 0)
|
|
}
|
|
|
|
/** قیمت خرید نمایشی */
|
|
export function getProductBuyPrice(product?: Product | null): number {
|
|
if (!product) {
|
|
return 0
|
|
}
|
|
|
|
const base = getProductBaseBuyPrice(product)
|
|
if (base <= 0) {
|
|
return 0
|
|
}
|
|
|
|
const fee = resolveProductCashFeeBuyRial(product, base)
|
|
const withFee = base + fee
|
|
|
|
if (isColleaguePriceProduct(product)) {
|
|
return withFee
|
|
}
|
|
|
|
if (isAppPriceProduct(product)) {
|
|
return withFee * productPriceAmountFactor(product)
|
|
}
|
|
|
|
if (
|
|
isMeltedProductUsingAppPrice(product)
|
|
|| isMeltedTradeGroup(product.group_type)
|
|
|| isMetalCommodityGroup(product.group_type)
|
|
) {
|
|
return withFee
|
|
}
|
|
|
|
if (usesQuantityTrade(product) && hasProductUnitWeight(product)) {
|
|
return withFee * productPriceAmountFactor(product)
|
|
}
|
|
|
|
if (usesQuantityTrade(product)) {
|
|
return withFee
|
|
}
|
|
|
|
return withFee * productPriceAmountFactor(product)
|
|
}
|
|
|
|
/** قیمت پایه فروش */
|
|
export function getProductBaseSellPrice(product?: Product | null): number {
|
|
if (!product) {
|
|
return 0
|
|
}
|
|
|
|
if (isMeltedProductUsingAppPrice(product) || isAppPriceProduct(product)) {
|
|
const apiPrice = Number(product.price ?? 0)
|
|
const useLast = productUsesLastPriceIfZero(product)
|
|
|
|
if (!useLast) {
|
|
const liveSell = getTradeSellPrice(lastPrice.value)
|
|
if (liveSell > 0) {
|
|
return applyPriceOffsetPercent(liveSell, product.price_offset_percent)
|
|
}
|
|
return 0
|
|
}
|
|
|
|
if (apiPrice > 0) {
|
|
return apiPrice
|
|
}
|
|
|
|
const liveSell = getTradeSellPrice(lastPrice.value)
|
|
if (liveSell > 0) {
|
|
return applyPriceOffsetPercent(liveSell, product.price_offset_percent)
|
|
}
|
|
|
|
return 0
|
|
}
|
|
|
|
if (isMeltedTradeGroup(product.group_type)) {
|
|
return Number(product.sellPrice ?? product.price ?? 0)
|
|
}
|
|
|
|
if (isColleaguePriceProduct(product)) {
|
|
return Number(product.sellPrice ?? product.price ?? 0)
|
|
}
|
|
|
|
const serverSell = Number(product.sellPrice ?? 0)
|
|
if (serverSell > 0) {
|
|
return serverSell
|
|
}
|
|
|
|
return getProductBaseBuyPrice(product)
|
|
}
|
|
|
|
/** قیمت فروش نمایشی */
|
|
export function getProductSellPrice(product?: Product | null): number {
|
|
if (!product) {
|
|
return 0
|
|
}
|
|
|
|
const base = getProductBaseSellPrice(product)
|
|
if (base <= 0) {
|
|
return 0
|
|
}
|
|
|
|
if (isColleaguePriceProduct(product)) {
|
|
return base - resolveProductCashFeeSellRial(product, base)
|
|
}
|
|
|
|
if (isAppPriceProduct(product)) {
|
|
const withFee = base - resolveProductCashFeeSellRial(product, base)
|
|
return withFee * productPriceAmountFactor(product)
|
|
}
|
|
|
|
if (isMeltedProductUsingAppPrice(product) || isMeltedTradeGroup(product.group_type)) {
|
|
return base - resolveProductCashFeeSellRial(product, base)
|
|
}
|
|
|
|
if (usesQuantityTrade(product) && hasProductUnitWeight(product)) {
|
|
const withFee = base - resolveProductCashFeeSellRial(product, base)
|
|
return withFee * productPriceAmountFactor(product)
|
|
}
|
|
|
|
if (usesQuantityTrade(product)) {
|
|
return base - resolveProductCashFeeSellRial(product, base)
|
|
}
|
|
|
|
return base - resolveProductCashFeeSellRial(product, base)
|
|
}
|
|
|
|
/** کارت فروشگاه: قیمت نمایشی صفر → «بدون قیمت» */
|
|
export function isProductWithoutDisplayPrice(product?: Product | null): boolean {
|
|
return getProductBuyPrice(product) <= 0
|
|
}
|
|
|
|
export function isProductPriceInactive(product?: Product | null): boolean {
|
|
if (!product) {
|
|
return true
|
|
}
|
|
|
|
if (!isProductTradingHoursOpen(product)) {
|
|
return true
|
|
}
|
|
|
|
if (
|
|
hasReferenceReadingMethod(product)
|
|
&& !productUsesLastPriceIfZero(product)
|
|
&& product.reference_provider_active === false
|
|
) {
|
|
return true
|
|
}
|
|
|
|
return getProductBaseBuyPrice(product) <= 0
|
|
}
|
|
|
|
function tvBuyUnitPrice(product: Product): number {
|
|
return Number(product.tv_price ?? 0)
|
|
}
|
|
|
|
function tvSellUnitPrice(product: Product): number {
|
|
const sell = Number(product.tv_sell_price ?? 0)
|
|
if (sell > 0) {
|
|
return sell
|
|
}
|
|
return tvBuyUnitPrice(product)
|
|
}
|
|
|
|
export function getTvProductBuyPrice(product?: Product | null): number {
|
|
if (!product) {
|
|
return 0
|
|
}
|
|
const unit = tvBuyUnitPrice(product)
|
|
if (unit > 0) {
|
|
return unit
|
|
}
|
|
return getProductBuyPrice(product)
|
|
}
|
|
|
|
export function getTvProductSellPrice(product?: Product | null): number {
|
|
if (!product) {
|
|
return 0
|
|
}
|
|
const unit = tvSellUnitPrice(product)
|
|
if (unit > 0) {
|
|
return unit
|
|
}
|
|
return getProductSellPrice(product)
|
|
}
|
|
|
|
export function isTvProductPriceInactive(product?: Product | null): boolean {
|
|
if (!product) {
|
|
return true
|
|
}
|
|
if (tvBuyUnitPrice(product) > 0 || tvSellUnitPrice(product) > 0) {
|
|
return false
|
|
}
|
|
return isProductPriceInactive(product)
|
|
}
|
|
|
|
/**
|
|
* نمایش محصول در فروشگاه — اولویت با `show` سرور.
|
|
* آبشدهٔ قیمتاپ با مظنه زنده حتی اگر show هنوز false باشد.
|
|
*/
|
|
export function isProductVisible(product?: Product | null): boolean {
|
|
if (!product || product.active === false) {
|
|
return false
|
|
}
|
|
|
|
if (product.show) {
|
|
return true
|
|
}
|
|
|
|
return isMeltedProductUsingAppPrice(product) && getProductBaseBuyPrice(product) > 0
|
|
}
|
|
|
|
export { isMeltedTradeGroup, isMeltedProductUsingAppPrice } from '@/utils/productCategories'
|