price handling
This commit is contained in:
+12
-3
@@ -151,6 +151,7 @@ let amountP =0
|
||||
let isBuyP=true
|
||||
let NumP=0
|
||||
let groupTypeP: string | undefined
|
||||
let meltedBalanceP = 0
|
||||
const checkNumber = async (_rule: Rule, value: number) => {
|
||||
|
||||
|
||||
@@ -165,12 +166,12 @@ if (isBuyP){
|
||||
if (!availableCash && isCashLikeDealMethod(methodP)){
|
||||
return Promise.reject(getInsufficientCashWalletMessage(groupTypeP))
|
||||
}
|
||||
if (!walletCash?.walletInfo?.gold && isMainMetalWalletDealMethod(methodP)){
|
||||
if (!meltedBalanceP && isMainMetalWalletDealMethod(methodP)){
|
||||
return Promise.reject(getInsufficientGoldWalletMessage(groupTypeP, methodP))
|
||||
}
|
||||
if (priceP * value > availableCash && isCashLikeDealMethod(methodP))
|
||||
return Promise.reject(getInsufficientCashWalletMessage(groupTypeP))
|
||||
if (amountP * value > walletCash?.walletInfo?.gold && isMainMetalWalletDealMethod(methodP))
|
||||
if (amountP * value > meltedBalanceP && isMainMetalWalletDealMethod(methodP))
|
||||
return Promise.reject(getInsufficientGoldWalletMessage(groupTypeP, methodP))
|
||||
else
|
||||
return Promise.resolve();
|
||||
@@ -182,12 +183,20 @@ if (isBuyP){
|
||||
}
|
||||
}
|
||||
|
||||
export const justNumber2 = (price: number, method?: string , amount?:number ,isBuy?:boolean, groupType?: string) => {
|
||||
export const justNumber2 = (
|
||||
price: number,
|
||||
method?: string,
|
||||
amount?: number,
|
||||
isBuy?: boolean,
|
||||
groupType?: string,
|
||||
meltedBalance?: number,
|
||||
) => {
|
||||
priceP = price
|
||||
methodP = method
|
||||
amountP=amount
|
||||
isBuyP=isBuy
|
||||
groupTypeP = groupType
|
||||
meltedBalanceP = meltedBalance ?? 0
|
||||
return {
|
||||
required: true,
|
||||
validator: checkNumber,
|
||||
|
||||
@@ -391,7 +391,7 @@ export function formatMetalAssetsInfoText(metal: WalletMetalTotal): string {
|
||||
}
|
||||
|
||||
function formatRialNumber(value: number): string {
|
||||
return usePriceWithoutType(Math.round(value))
|
||||
return usePriceWithoutType(value)
|
||||
}
|
||||
|
||||
/** متن توضیح مودال دارایی ریالی */
|
||||
|
||||
+208
-22
@@ -1,4 +1,6 @@
|
||||
import type { SelectItem } from '@/models/SelectItem'
|
||||
import type { Product } from '@/models/products'
|
||||
import type { WalletInventoryCard } from '@/models/walletAssets'
|
||||
import { isBoursecuProject } from '@/utils/config'
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
import {
|
||||
@@ -8,7 +10,9 @@ import {
|
||||
LEGACY_GROUP_MAFTOL,
|
||||
normalizeProductGroupType,
|
||||
PRODUCT_CATEGORY_ABSHODE,
|
||||
usesQuantityTrade,
|
||||
} from '@/utils/productCategories'
|
||||
import { formatInventoryCardValue } from '@/utils/productAssets'
|
||||
|
||||
/** @deprecated از isMeltedTradeGroup استفاده کنید */
|
||||
export const BOURSECU_GROUP_ABSHODE = PRODUCT_CATEGORY_ABSHODE
|
||||
@@ -183,29 +187,190 @@ export function getProductQuantityUnit(product?: ProductUnitSource | null) {
|
||||
return getWeightUnit()
|
||||
}
|
||||
|
||||
function getDefaultTypeDealOptions(): SelectItem[] {
|
||||
const settingsStore = useSettingsStore()
|
||||
return [
|
||||
{ value: 'نقدی', key: 'cash' },
|
||||
{ value: settingsStore.metalTypeLabel, key: 'gold' },
|
||||
]
|
||||
export const MELTED_DEAL_METHOD_PREFIX = 'gold:'
|
||||
|
||||
export interface ProductDealMethodContext {
|
||||
tradedProduct?: Product | null
|
||||
productMetalId?: number | null
|
||||
inventoryCards?: WalletInventoryCard[]
|
||||
catalog?: Product[]
|
||||
}
|
||||
|
||||
export function getProductDealMethodOptions(groupType?: string | null, isBuy = true): SelectItem[] {
|
||||
/** سلکت نحوه معامله فقط وقتی محصول مورد معامله وزن دارد */
|
||||
export function shouldShowProductDealMethodSelector(product?: Product | null) {
|
||||
return hasProductUnitWeight(product)
|
||||
}
|
||||
|
||||
export function shouldShowProductDealMethodSelect(
|
||||
product?: Product | null,
|
||||
options?: SelectItem[] | null,
|
||||
) {
|
||||
return shouldShowProductDealMethodSelector(product) && (options?.length ?? 0) > 1
|
||||
}
|
||||
|
||||
export function buildMeltedDealMethodKey(productId: number) {
|
||||
return `${MELTED_DEAL_METHOD_PREFIX}${productId}`
|
||||
}
|
||||
|
||||
export function parseMeltedDealMethodProductId(method?: string | null): number | null {
|
||||
if (!method?.startsWith(MELTED_DEAL_METHOD_PREFIX)) {
|
||||
return null
|
||||
}
|
||||
|
||||
const productId = Number(method.slice(MELTED_DEAL_METHOD_PREFIX.length))
|
||||
return productId > 0 ? productId : null
|
||||
}
|
||||
|
||||
export function isMeltedProductDealMethod(method?: string | null) {
|
||||
return parseMeltedDealMethodProductId(method) != null
|
||||
}
|
||||
|
||||
function isQuantityTradeCatalogProduct(
|
||||
product?: Product | null,
|
||||
metalId?: number | null,
|
||||
excludeProductId?: number | null,
|
||||
) {
|
||||
if (!product || !usesQuantityTrade(product)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (excludeProductId && Number(product.id) === Number(excludeProductId)) {
|
||||
return false
|
||||
}
|
||||
|
||||
return Number(product.metal_id) === Number(metalId ?? 0)
|
||||
}
|
||||
|
||||
function findInventoryCardForProduct(
|
||||
cards: WalletInventoryCard[],
|
||||
productId?: number | null,
|
||||
) {
|
||||
if (!productId) {
|
||||
return undefined
|
||||
}
|
||||
|
||||
return cards.find((card) => Number(card.product_id) === Number(productId))
|
||||
}
|
||||
|
||||
export function getQuantityTradePaymentDealOptions(
|
||||
context?: ProductDealMethodContext | null,
|
||||
isBuy = true,
|
||||
): SelectItem[] {
|
||||
const metalId = Number(context?.productMetalId ?? 0)
|
||||
const catalog = context?.catalog ?? []
|
||||
const cards = context?.inventoryCards ?? []
|
||||
const tradedProductId = context?.tradedProduct?.id ?? null
|
||||
|
||||
if (!metalId || !catalog.length) {
|
||||
return []
|
||||
}
|
||||
|
||||
const matchingProducts = catalog.filter((product) =>
|
||||
isQuantityTradeCatalogProduct(product, metalId, tradedProductId)
|
||||
)
|
||||
|
||||
if (isBuy) {
|
||||
const options: SelectItem[] = []
|
||||
|
||||
for (const product of matchingProducts) {
|
||||
const card = findInventoryCardForProduct(cards, product.id)
|
||||
if (!card || Number(card.quantity ?? 0) <= 0) {
|
||||
continue
|
||||
}
|
||||
|
||||
options.push({
|
||||
key: buildMeltedDealMethodKey(product.id),
|
||||
value: `${product.title} — ${formatInventoryCardValue(card)}`,
|
||||
})
|
||||
}
|
||||
|
||||
return options
|
||||
}
|
||||
|
||||
return matchingProducts.map((product) => {
|
||||
const card = findInventoryCardForProduct(cards, product.id)
|
||||
const inventorySuffix = card ? ` — ${formatInventoryCardValue(card)}` : ''
|
||||
|
||||
return {
|
||||
key: buildMeltedDealMethodKey(product.id),
|
||||
value: `دریافت ${product.title}${inventorySuffix}`,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
/** @deprecated از getQuantityTradePaymentDealOptions استفاده کنید */
|
||||
export function getMeltedPaymentDealOptions(
|
||||
context?: ProductDealMethodContext | null,
|
||||
isBuy = true,
|
||||
) {
|
||||
return getQuantityTradePaymentDealOptions(context, isBuy)
|
||||
}
|
||||
|
||||
export function findMeltedDealMethodCard(
|
||||
method?: string | null,
|
||||
cards: WalletInventoryCard[] = [],
|
||||
) {
|
||||
return findInventoryCardForProduct(cards, parseMeltedDealMethodProductId(method))
|
||||
}
|
||||
|
||||
export function findProductDealMethodProduct(
|
||||
method?: string | null,
|
||||
catalog: Product[] = [],
|
||||
) {
|
||||
const productId = parseMeltedDealMethodProductId(method)
|
||||
if (!productId) {
|
||||
return null
|
||||
}
|
||||
|
||||
return catalog.find((product) => Number(product.id) === productId) ?? null
|
||||
}
|
||||
|
||||
export function resolveProductTradeBuyUnitPrice(product?: Product | null) {
|
||||
if (!product) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const basePrice = (product.price ?? 0) + (product.cash_fee_buy ?? 0)
|
||||
return product.direct_price === 0
|
||||
? basePrice * (product.amount ?? 0)
|
||||
: basePrice
|
||||
}
|
||||
|
||||
export function resolveProductTradeSellUnitPrice(product?: Product | null) {
|
||||
if (!product) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const basePrice = (product.price ?? 0) - (product.cash_fee_sell ?? 0)
|
||||
return product.direct_price === 0
|
||||
? basePrice * (product.amount ?? 0)
|
||||
: basePrice
|
||||
}
|
||||
|
||||
function getDefaultTypeDealOptions(context?: ProductDealMethodContext | null, isBuy = true): SelectItem[] {
|
||||
const cashOption: SelectItem = { value: 'نقدی', key: 'cash' }
|
||||
|
||||
if (!shouldShowProductDealMethodSelector(context?.tradedProduct ?? null)) {
|
||||
return [cashOption]
|
||||
}
|
||||
|
||||
const quantityOptions = getQuantityTradePaymentDealOptions(context, isBuy)
|
||||
if (quantityOptions.length) {
|
||||
return [cashOption, ...quantityOptions]
|
||||
}
|
||||
|
||||
return [cashOption]
|
||||
}
|
||||
|
||||
export function getProductDealMethodOptions(
|
||||
groupType?: string | null,
|
||||
isBuy = true,
|
||||
context?: ProductDealMethodContext | null,
|
||||
): SelectItem[] {
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
if (!isBoursecuProject()) {
|
||||
if (isBuy) {
|
||||
return [
|
||||
{ value: 'نقدی', key: 'cash' },
|
||||
{ value: settingsStore.metalTypeLabel, key: 'gold' },
|
||||
]
|
||||
}
|
||||
|
||||
return [
|
||||
{ value: 'نقدی', key: 'cash' },
|
||||
{ value: `دریافت ${settingsStore.metalTypeLabel}`, key: 'gold' },
|
||||
]
|
||||
return getDefaultTypeDealOptions(context, isBuy)
|
||||
}
|
||||
|
||||
if (isMaftolMesGroup(groupType)) {
|
||||
@@ -230,11 +395,15 @@ export function getProductDealMethodOptions(groupType?: string | null, isBuy = t
|
||||
return [{ value: settingsStore.meltedGoldLabel, key: 'gold' }]
|
||||
}
|
||||
|
||||
return getDefaultTypeDealOptions()
|
||||
return getDefaultTypeDealOptions(context, isBuy)
|
||||
}
|
||||
|
||||
export function getDefaultProductDealMethod(groupType?: string | null, isBuy = true) {
|
||||
return getProductDealMethodOptions(groupType, isBuy)[0]?.key ?? 'cash'
|
||||
export function getDefaultProductDealMethod(
|
||||
groupType?: string | null,
|
||||
isBuy = true,
|
||||
context?: ProductDealMethodContext | null,
|
||||
) {
|
||||
return getProductDealMethodOptions(groupType, isBuy, context)[0]?.key ?? 'cash'
|
||||
}
|
||||
|
||||
export function getProductDealMethodPlaceholder(isBuy = true) {
|
||||
@@ -265,7 +434,24 @@ export function isCashLikeDealMethod(method?: string | null) {
|
||||
}
|
||||
|
||||
export function isMainMetalWalletDealMethod(method?: string | null) {
|
||||
return method === 'gold' || method === 'katod'
|
||||
return method === 'gold' || method === 'katod' || isMeltedProductDealMethod(method)
|
||||
}
|
||||
|
||||
export function getMeltedDealMethodBalance(
|
||||
method?: string | null,
|
||||
cards: WalletInventoryCard[] = [],
|
||||
mainWalletGold?: number | null,
|
||||
) {
|
||||
const card = findMeltedDealMethodCard(method, cards)
|
||||
if (card) {
|
||||
return Number(card.quantity ?? 0)
|
||||
}
|
||||
|
||||
if (method === 'gold' || method === 'katod') {
|
||||
return Number(mainWalletGold ?? 0)
|
||||
}
|
||||
|
||||
return 0
|
||||
}
|
||||
|
||||
/** برچسب کیف فلز اصلی (main wallet gold) — از setting metal_type */
|
||||
|
||||
@@ -7,6 +7,22 @@ function productUsesLastPriceIfZero(product: Product): boolean {
|
||||
return Boolean(product.use_last_price_if_zero)
|
||||
}
|
||||
|
||||
function hasReferenceReadingMethod(product: Product): boolean {
|
||||
return Boolean(product.reading_method)
|
||||
}
|
||||
|
||||
/** قیمت پایه محصولات با reading_method — بدون fallback وقتی تیک «قیمت صفر از مرجع» خاموش است */
|
||||
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) {
|
||||
@@ -74,6 +90,10 @@ export function getProductBaseBuyPrice(product: Product): number {
|
||||
return Number(product.price_profit ?? 0) + Number(product.price ?? 0)
|
||||
}
|
||||
|
||||
if (hasReferenceReadingMethod(product)) {
|
||||
return getReferenceProductBaseBuyPrice(product)
|
||||
}
|
||||
|
||||
return Number(product.price ?? 0)
|
||||
}
|
||||
|
||||
@@ -148,6 +168,14 @@ export function getProductSellPrice(product: Product): number {
|
||||
}
|
||||
|
||||
export function isProductPriceInactive(product: Product): boolean {
|
||||
if (
|
||||
hasReferenceReadingMethod(product)
|
||||
&& !productUsesLastPriceIfZero(product)
|
||||
&& product.reference_provider_active === false
|
||||
) {
|
||||
return true
|
||||
}
|
||||
|
||||
return getProductBaseBuyPrice(product) <= 0
|
||||
}
|
||||
|
||||
|
||||
+12
-3
@@ -6,18 +6,27 @@ function formatGroupedPrice(price: string | number | null | undefined, digit: bo
|
||||
return value
|
||||
}
|
||||
|
||||
/** مبلغ ریالی — بدون اعشار، گرد به بالا */
|
||||
export function ceilRial(price?: number | string | null): number {
|
||||
const num = Number(price ?? 0)
|
||||
if (!Number.isFinite(num)) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return Math.ceil(num)
|
||||
}
|
||||
|
||||
export function formatNumber(value: string | number | null | undefined, grouped = false): string {
|
||||
return formatGroupedPrice(value, grouped)
|
||||
}
|
||||
|
||||
export function usePrice(price: number, digit = true, unit = 'ریال') {
|
||||
price = price ?? 0
|
||||
const formatted = formatGroupedPrice(price, digit)
|
||||
const formatted = formatGroupedPrice(ceilRial(price), digit)
|
||||
return `${formatted} ${unit}`
|
||||
}
|
||||
|
||||
export function usePriceWithoutType(price?: number, digit = true) {
|
||||
return formatGroupedPrice(price ?? '', digit)
|
||||
return formatGroupedPrice(ceilRial(price), digit)
|
||||
}
|
||||
|
||||
export function useTowDecimal(num: string | number): string | number {
|
||||
|
||||
Reference in New Issue
Block a user