Files
boursecu_user/src/utils/productDealMethod.ts
T

753 lines
22 KiB
TypeScript
Raw Normal View History

2026-06-01 17:19:45 +03:30
import type { SelectItem } from '@/models/SelectItem'
2026-06-22 21:10:25 +03:30
import type { Product } from '@/models/products'
import type { WalletInventoryCard } from '@/models/walletAssets'
2026-06-03 22:04:45 +03:30
import { useSettingsStore } from '@/store/settingsStore'
2026-06-09 21:04:22 +03:30
import {
isLegacyMaftolGroup,
isMeltedTradeGroup,
LEGACY_GROUP_KATOD,
LEGACY_GROUP_MAFTOL,
normalizeProductGroupType,
PRODUCT_CATEGORY_ABSHODE,
2026-06-22 21:10:25 +03:30
usesQuantityTrade,
2026-06-09 21:04:22 +03:30
} from '@/utils/productCategories'
2026-06-22 21:10:25 +03:30
import { formatInventoryCardValue } from '@/utils/productAssets'
2026-07-04 17:56:24 +03:30
import { resolveProductCashFeeBuyRial, resolveProductCashFeeSellRial } from '@/utils/productCashFee'
2026-07-04 12:06:02 +03:30
import { TRADE_GRAM_DISPLAY_DECIMALS } from '@/utils/serviceFee'
2026-07-02 21:23:55 +03:30
import { formatGoldAmount } from '@/utils/usePrice'
2026-06-01 17:19:45 +03:30
2026-06-09 21:04:22 +03:30
/** @deprecated از isMeltedTradeGroup استفاده کنید */
export const BOURSECU_GROUP_ABSHODE = PRODUCT_CATEGORY_ABSHODE
export const BOURSECU_GROUP_KATOD = LEGACY_GROUP_KATOD
export const BOURSECU_GROUP_MAFTOL = LEGACY_GROUP_MAFTOL
2026-06-01 17:19:45 +03:30
2026-06-03 22:04:45 +03:30
export const BOURSECU_WALLET_LABEL_GENERIC = 'موجودی کیف'
2026-06-01 17:19:45 +03:30
export function isBoursecuDealProductGroup(groupType?: string | null) {
const group = normalizeProductGroupType(groupType)
return group === BOURSECU_GROUP_MAFTOL
2026-06-03 19:54:23 +03:30
|| group === BOURSECU_GROUP_KATOD
2026-06-01 17:19:45 +03:30
|| group === BOURSECU_GROUP_ABSHODE
2026-06-09 21:04:22 +03:30
|| group === 'مس'
2026-06-01 17:19:45 +03:30
}
export function isMaftolMesGroup(groupType?: string | null) {
2026-06-09 21:04:22 +03:30
const group = normalizeProductGroupType(groupType)
return group === BOURSECU_GROUP_MAFTOL || group === 'مس'
2026-06-01 17:19:45 +03:30
}
2026-06-03 19:54:23 +03:30
export function isKatodMesGroup(groupType?: string | null) {
return normalizeProductGroupType(groupType) === BOURSECU_GROUP_KATOD
}
2026-06-23 16:02:41 +03:30
export function isShamshMesGroup(groupType?: string | null, title?: string | null) {
const group = normalizeProductGroupType(groupType)
if (group === 'شمش') {
return true
}
return (title ?? '').includes('شمش')
}
2026-06-01 17:19:45 +03:30
export function isGoldOnlyDealGroup(groupType?: string | null) {
2026-06-09 21:04:22 +03:30
return isMeltedTradeGroup(groupType)
2026-06-01 17:19:45 +03:30
}
2026-06-03 22:04:45 +03:30
export interface ProductUnitSource {
unit?: string | null
direct_price?: number | null
group_type?: string | null
amount?: number | null
2026-06-23 16:02:41 +03:30
trade_by_quantity?: boolean | number | null
price_formula_enabled?: boolean | number | null
2026-06-03 22:04:45 +03:30
}
2026-06-09 21:04:22 +03:30
export function isWeightBasedProductUnit(unit?: string | null) {
const value = (unit ?? '').trim()
return value === 'کیلوگرم' || value === 'گرم'
}
2026-06-03 22:04:45 +03:30
const COUNT_BASED_GROUP_TYPES = ['سکه', 'گوی', 'مکعب', 'شمش', 'سکه پارسیان']
2026-06-17 16:03:19 +03:30
/** مطابق ادمین: وزن «دارد» => amount > 0 ؛ «ندارد» => amount = 0 */
2026-06-03 22:04:45 +03:30
export function hasProductUnitWeight(product?: ProductUnitSource | null) {
2026-06-17 16:03:19 +03:30
if (isMeltedTradeGroup(product?.group_type)) {
return false
}
2026-06-03 22:04:45 +03:30
const amount = Number(product?.amount ?? 0)
2026-06-17 16:03:19 +03:30
return amount > 0
}
2026-06-27 18:06:44 +03:30
/** ضریب قیمت — فقط «متغیر» بدون مرجع اتوماتیک: قیمت هر گرم × وزن */
2026-06-17 16:03:19 +03:30
export function productPriceAmountFactor(product?: ProductUnitSource | null) {
// قیمت فرمولی = قیمت واحد هر عدد (وزن داخل فرمول است)
if (product?.price_formula_enabled) {
return 1
}
2026-06-27 18:06:44 +03:30
if (product?.reading_method) {
return 1
}
if (isCountBasedProduct(product)) {
return 1
}
if (Number(product?.direct_price ?? 0) !== 0) {
return 1
}
2026-06-17 16:03:19 +03:30
if (hasProductUnitWeight(product)) {
const amount = Number(product?.amount ?? 0)
return amount > 0 ? amount : 1
}
return 1
2026-06-03 22:04:45 +03:30
}
export function getProductWeightUnit(product?: ProductUnitSource | null) {
2026-06-09 21:04:22 +03:30
const unit = product?.unit?.trim()
if (unit && isWeightBasedProductUnit(unit)) {
return unit
}
const group = normalizeProductGroupType(product?.group_type)
if (group === BOURSECU_GROUP_MAFTOL || group === BOURSECU_GROUP_KATOD || group === BOURSECU_GROUP_ABSHODE || group === 'مس' || isMeltedTradeGroup(group)) {
return getWeightUnit()
2026-06-03 22:04:45 +03:30
}
2026-06-09 21:04:22 +03:30
if (!isCountBasedProduct(product) || isMeltedTradeGroup(product?.group_type)) {
2026-06-03 22:04:45 +03:30
return getWeightUnit()
}
return 'گرم'
}
export function formatProductWeightAmount(amount?: number | null, product?: ProductUnitSource | null) {
const value = Number(amount ?? 0)
const weightUnit = getProductWeightUnit(product)
if (weightUnit === 'گرم' && value > 0 && value < 1) {
return `${value * 1000} سوت`
}
return `${value} ${weightUnit}`
}
2026-06-23 16:02:41 +03:30
/** فقط محصول تعدادی (مثل سکه): «هر عدد X گرم» — معامله مقداری با trade_by_quantity نیست */
export function shouldShowPerUnitWeightHint(product?: ProductUnitSource | null) {
if (!product || !hasProductUnitWeight(product) || usesQuantityTrade(product)) {
return false
}
return isCountBasedProduct(product)
}
2026-06-03 22:04:45 +03:30
export function getProductUnitWeightLabel(product?: ProductUnitSource | null) {
2026-06-23 16:02:41 +03:30
if (!shouldShowPerUnitWeightHint(product)) {
2026-06-03 22:04:45 +03:30
return null
}
return formatProductWeightAmount(product?.amount, product)
}
export function getProductTotalWeightLabel(count?: number | null, product?: ProductUnitSource | null) {
if (!hasProductUnitWeight(product)) {
return null
}
const quantity = Number(count ?? 0)
return formatProductWeightAmount(quantity * Number(product?.amount ?? 0), product)
}
export function shouldShowProductTotalWeight(product?: ProductUnitSource | null) {
if (!product) {
return false
}
if (!isCountBasedProduct(product)) {
return true
}
return hasProductUnitWeight(product)
}
export function formatProductInventoryBalance(product?: (ProductUnitSource & { wallet?: { gold?: number | null } }) | null) {
const count = product?.wallet?.gold ?? 0
const quantityPart = `${count} ${getProductQuantityUnit(product)}`
const unitWeight = getProductUnitWeightLabel(product)
if (!unitWeight) {
return quantityPart
}
return `${quantityPart} · هر عدد ${unitWeight}`
}
2026-06-23 16:02:41 +03:30
/** محصول تعدادی: موجودی wallet.gold = تعداد قلم، نه وزن — معامله مقداری با trade_by_quantity نیست */
2026-06-03 22:04:45 +03:30
export function isCountBasedProduct(product?: ProductUnitSource | null) {
if (!product) {
return false
}
2026-06-23 16:02:41 +03:30
if (usesQuantityTrade(product)) {
return false
}
2026-06-09 21:04:22 +03:30
if (isWeightBasedProductUnit(product.unit)) {
return false
}
2026-06-03 22:04:45 +03:30
if (product.direct_price != null && product.direct_price !== 0) {
return true
}
const group = normalizeProductGroupType(product.group_type)
if (group === BOURSECU_GROUP_MAFTOL || isLegacyMaftolGroup(group) || group === 'مس') {
2026-06-03 22:04:45 +03:30
return true
}
return COUNT_BASED_GROUP_TYPES.includes(group)
}
export function getProductQuantityUnit(product?: ProductUnitSource | null) {
const unit = product?.unit?.trim()
if (unit) {
return unit
}
2026-06-09 21:04:22 +03:30
if (isCountBasedProduct(product)) {
return 'عدد'
}
2026-06-03 22:04:45 +03:30
return getWeightUnit()
}
2026-06-22 21:10:25 +03:30
export const MELTED_DEAL_METHOD_PREFIX = 'gold:'
export interface ProductDealMethodContext {
tradedProduct?: Product | null
productMetalId?: number | null
inventoryCards?: WalletInventoryCard[]
catalog?: Product[]
2026-06-03 22:04:45 +03:30
}
2026-06-22 21:10:25 +03:30
/** سلکت نحوه معامله فقط وقتی محصول مورد معامله وزن دارد */
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
}
2026-07-04 17:56:24 +03:30
const basePrice = (product.price ?? 0) + resolveProductCashFeeBuyRial(product, product.price ?? 0)
2026-06-27 18:06:44 +03:30
return basePrice * productPriceAmountFactor(product)
2026-06-22 21:10:25 +03:30
}
export function resolveProductTradeSellUnitPrice(product?: Product | null) {
if (!product) {
return 0
}
2026-07-04 17:56:24 +03:30
const basePrice = (product.price ?? 0) - resolveProductCashFeeSellRial(product, product.price ?? 0)
2026-06-27 18:06:44 +03:30
return basePrice * productPriceAmountFactor(product)
2026-06-22 21:10:25 +03:30
}
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[] {
2026-06-03 22:04:45 +03:30
const settingsStore = useSettingsStore()
2026-06-01 17:19:45 +03:30
if (isMaftolMesGroup(groupType)) {
2026-06-09 21:04:22 +03:30
if (isBuy) {
return [
{ value: `پرداخت با ${settingsStore.metalTypeLabel}`, key: 'katod' },
{ value: 'نقدی', key: 'cash' },
]
}
2026-06-03 22:04:45 +03:30
return [
{ value: 'نقدی', key: 'cash' },
2026-06-09 21:04:22 +03:30
{ value: `دریافت ${settingsStore.metalTypeLabel}`, key: 'katod' },
2026-06-03 22:04:45 +03:30
]
2026-06-01 17:19:45 +03:30
}
2026-06-03 19:54:23 +03:30
if (isKatodMesGroup(groupType)) {
2026-06-03 22:04:45 +03:30
return [{ value: 'نقدی', key: 'cash' }]
2026-06-03 19:54:23 +03:30
}
2026-06-09 21:04:22 +03:30
if (isMeltedTradeGroup(groupType)) {
2026-06-03 22:04:45 +03:30
return [{ value: settingsStore.meltedGoldLabel, key: 'gold' }]
2026-06-01 17:19:45 +03:30
}
2026-06-22 21:10:25 +03:30
return getDefaultTypeDealOptions(context, isBuy)
2026-06-01 17:19:45 +03:30
}
2026-06-22 21:10:25 +03:30
export function getDefaultProductDealMethod(
groupType?: string | null,
isBuy = true,
context?: ProductDealMethodContext | null,
) {
return getProductDealMethodOptions(groupType, isBuy, context)[0]?.key ?? 'cash'
2026-06-09 21:04:22 +03:30
}
export function getProductDealMethodPlaceholder(isBuy = true) {
return isBuy ? 'نحوه خرید را انتخاب کنید' : 'نحوه دریافت را انتخاب کنید'
}
export function formatMainMetalReceiveText(weight?: number | null) {
return `${useSettingsStore().metalTypeLabel}: ${weight ?? 0}${getWeightUnit()}`
}
export function calcSellReceivedMetalWeight(
count?: number | null,
2026-07-23 12:27:24 +03:30
product?: ProductUnitSource | null,
2026-06-09 21:04:22 +03:30
) {
const quantity = Number(count ?? 0)
const unitAmount = Number(product?.amount ?? 0)
if (!quantity || !unitAmount) {
return 0
}
2026-07-23 12:27:24 +03:30
// کارمزد محصول تعدادی از ریال است — وزن دریافتی فلز کم نمی‌شود
return quantity * unitAmount
2026-06-01 17:19:45 +03:30
}
export function isCashLikeDealMethod(method?: string | null) {
2026-06-03 22:04:45 +03:30
return method === 'cash'
2026-06-01 17:19:45 +03:30
}
2026-06-03 19:54:23 +03:30
2026-06-03 22:04:45 +03:30
export function isMainMetalWalletDealMethod(method?: string | null) {
2026-06-22 21:10:25 +03:30
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
2026-06-03 22:04:45 +03:30
}
/** برچسب کیف فلز اصلی (main wallet gold) — از setting metal_type */
export function getMainMetalWalletLabel() {
return `موجودی کیف ${useSettingsStore().metalTypeLabel}`
}
/** برچسب کیف آبشده — از setting metal_type */
export function getMeltedGoldWalletLabel() {
return `موجودی کیف ${useSettingsStore().meltedGoldLabel}`
}
2026-06-03 19:54:23 +03:30
2026-06-09 21:04:22 +03:30
export function getBoursecuMetalWalletLabel(groupType?: string | null) {
const group = normalizeProductGroupType(groupType)
if (group === BOURSECU_GROUP_MAFTOL) {
return BOURSECU_GROUP_MAFTOL
}
if (group === BOURSECU_GROUP_KATOD) {
return BOURSECU_GROUP_KATOD
}
if (group === BOURSECU_GROUP_ABSHODE) {
return useSettingsStore().meltedGoldLabel
}
2026-06-03 22:04:45 +03:30
2026-06-09 21:04:22 +03:30
return useSettingsStore().metalTypeLabel
}
export function getGoldWalletLabel(groupType?: string | null) {
2026-06-03 19:54:23 +03:30
const group = normalizeProductGroupType(groupType)
2026-06-09 21:04:22 +03:30
if (group === BOURSECU_GROUP_MAFTOL
|| group === BOURSECU_GROUP_KATOD
|| group === BOURSECU_GROUP_ABSHODE) {
return `موجودی کیف ${getBoursecuMetalWalletLabel(groupType)}`
2026-06-03 22:04:45 +03:30
}
2026-06-09 21:04:22 +03:30
if (!group) {
return getMainMetalWalletLabel()
2026-06-03 22:04:45 +03:30
}
2026-06-03 19:54:23 +03:30
return BOURSECU_WALLET_LABEL_GENERIC
}
2026-06-09 21:04:22 +03:30
/** پرداخت نقدی همیشه از کیف پول ریالی — مستقل از نوع محصول */
export function getCashWalletLabel(_groupType?: string | null) {
2026-06-03 22:04:45 +03:30
return 'موجودی کیف پول'
}
export function getMetalAssetLabel() {
return `دارایی ${useSettingsStore().metalTypeLabel}`
}
export function getMeltedGoldAssetLabel() {
return `دارایی ${useSettingsStore().meltedGoldLabel}`
}
export function getMaftolAssetLabel() {
return `دارایی ${BOURSECU_GROUP_MAFTOL}`
2026-06-03 19:54:23 +03:30
}
export function getWeightUnit() {
2026-06-09 21:04:22 +03:30
return useSettingsStore().tradeWeightUnit
2026-06-03 19:54:23 +03:30
}
export function formatBoursecuAssetAmount(amount?: number | null) {
return `${amount ?? 0}${getWeightUnit()}`
}
2026-06-03 22:04:45 +03:30
export function formatMainMetalWalletBalanceText(gold: number) {
return `${getMainMetalWalletLabel()}: ${gold} ${getWeightUnit()}`
}
2026-06-03 19:54:23 +03:30
export function formatGoldWalletBalanceText(gold: number, groupType?: string | null) {
return `${getGoldWalletLabel(groupType)}: ${gold} ${getWeightUnit()}`
}
export function formatCashWalletBalanceText(cashFormatted: string | number, groupType?: string | null) {
return `${getCashWalletLabel(groupType)}: ${cashFormatted} ریال`
}
2026-06-09 21:04:22 +03:30
/** برچسب کیف فلزی متناسب با نحوه پرداخت (مثلاً کاتد مس برای خرید مفتول با کیف کاتد) */
export function getMetalWalletLabelForDealMethod(method?: string | null, groupType?: string | null) {
if (method === 'katod') {
2026-06-09 21:04:22 +03:30
return getMainMetalWalletLabel()
}
return getGoldWalletLabel(groupType)
2026-06-03 19:54:23 +03:30
}
2026-06-09 21:04:22 +03:30
export function getInsufficientGoldWalletMessage(groupType?: string | null, method?: string | null) {
return `${getMetalWalletLabelForDealMethod(method, groupType)} ناکافی است`
}
export function getInsufficientCashWalletMessage(_groupType?: string | null) {
return `${getCashWalletLabel()} ناکافی است`
2026-06-03 19:54:23 +03:30
}
2026-06-03 22:04:45 +03:30
export function getInsufficientMainMetalWalletMessage() {
return `${getMainMetalWalletLabel()} ناکافی است`
}
export function getMeltedGoldTradeLabel() {
return useSettingsStore().meltedGoldLabel
}
export function getMetalTypeTradeLabel() {
return useSettingsStore().metalTypeLabel
}
export function getTradePriceUnitLabel() {
return useSettingsStore().metalTypeLabel
}
2026-06-23 16:02:41 +03:30
2026-06-29 22:17:14 +03:30
export type TransactionTradeProductSource = {
product?: (ProductUnitSource & { title?: string | null }) | null
wallet?: { product?: (ProductUnitSource & { title?: string | null }) | null } | null
title?: string | null
2026-06-30 10:28:05 +03:30
order?: unknown
2026-06-29 22:17:14 +03:30
}
/** محصول معامله‌شده — نه لزوماً همان کیف پول (مثلاً خرید مفتول با کیف کاتد) */
export function resolveTransactionTradeProduct(
item?: TransactionTradeProductSource | null,
): (ProductUnitSource & { title?: string | null }) | null {
if (!item) {
return null
}
const fromTransaction = item.product
if ((fromTransaction?.title ?? '').trim()) {
return fromTransaction ?? null
}
const title = (item.title ?? '').trim()
const match = title.match(/^(?:خرید|فروش)\s+(.+)$/u)
if (match?.[1]?.trim()) {
return {
...(item.wallet?.product ?? {}),
title: match[1].trim(),
}
}
return item.wallet?.product ?? null
}
2026-07-02 21:23:55 +03:30
/** معامله آبشده / کیف طلای اصلی — نه سکه و محصول تعدادی */
export function isMeltedGoldTransaction(
item?: (TransactionTradeProductSource & { type?: number | null; title?: string | null }) | null,
): boolean {
if (!item) {
return false
}
const tradeProduct = resolveTransactionTradeProduct(item)
if (tradeProduct) {
if (usesQuantityTrade(tradeProduct) && !isMeltedTradeGroup(tradeProduct.group_type)) {
return false
}
if (isMeltedTradeGroup(tradeProduct.group_type)) {
return true
}
if (isCountBasedProduct(tradeProduct)) {
return false
}
}
const title = (item.title ?? '').trim()
const meltedLabel = getMeltedGoldTradeLabel()
if (title.includes(PRODUCT_CATEGORY_ABSHODE) || (meltedLabel && title.includes(meltedLabel))) {
return true
}
if (item.type !== 1 && item.type !== 2) {
return false
}
if (isMeltedTradeGroup(item.wallet?.product?.group_type)) {
return true
}
const tradeTitle = (tradeProduct?.title ?? '').trim()
if (tradeTitle === meltedLabel || tradeTitle.includes(PRODUCT_CATEGORY_ABSHODE)) {
return true
}
return !item.wallet?.product && !tradeTitle
}
export function formatTransactionGoldAmount(
item?: (TransactionTradeProductSource & { type?: number | null; title?: string | null }) | null,
amount?: number | null,
): string {
2026-07-04 12:06:02 +03:30
const decimals = isMeltedGoldTransaction(item) ? TRADE_GRAM_DISPLAY_DECIMALS : 3
2026-07-02 21:23:55 +03:30
return formatGoldAmount(amount, decimals)
}
2026-06-29 22:17:14 +03:30
/** برچسب قیمت حین معامله — نام و واحد همان محصول معامله‌شده */
2026-06-23 16:02:41 +03:30
export function getTransactionTradePriceLabel(product?: (ProductUnitSource & { title?: string | null }) | null) {
2026-06-29 22:17:14 +03:30
if (!product) {
return `قیمت هر ${getWeightUnit()} ${getTradePriceUnitLabel()}`
}
const title = (product.title ?? '').trim()
if (usesQuantityTrade(product)) {
2026-06-23 16:02:41 +03:30
const unit = getProductQuantityUnit(product)
return title ? `قیمت هر ${unit} ${title}` : `قیمت هر ${unit}`
}
2026-06-29 22:17:14 +03:30
if (title) {
return `قیمت هر ${getWeightUnit()} ${title}`
}
2026-06-23 16:02:41 +03:30
return `قیمت هر ${getWeightUnit()} ${getTradePriceUnitLabel()}`
}
2026-06-30 10:28:05 +03:30
/** برچسب «موجودی کیف …» برای سطر موجودی فلز در جزئیات معامله */
export function getTransactionMetalWalletBalanceLabel(
item?: TransactionTradeProductSource | null,
): string {
if (!item) {
return getGoldWalletLabel()
}
const tradeProduct = item.order ? resolveTransactionTradeProduct(item) : null
const walletProduct = item.wallet?.product
const tradeTitle = (tradeProduct?.title ?? '').trim()
const walletTitle = (walletProduct?.title ?? '').trim()
if (tradeTitle) {
if (!walletTitle) {
return `موجودی کیف ${tradeTitle}`
}
return `موجودی ${tradeTitle}`
}
if (walletTitle) {
return `موجودی ${walletTitle}`
}
return getGoldWalletLabel(item.wallet?.product?.group_type)
}
/** واحد نمایش موجودی فلز در جزئیات معامله */
export function getTransactionMetalWalletBalanceUnit(
item?: TransactionTradeProductSource | null,
): string {
const tradeProduct = item?.order ? resolveTransactionTradeProduct(item) : null
const walletProduct = item?.wallet?.product
const product = tradeProduct?.title ? tradeProduct : walletProduct
if (product && usesQuantityTrade(product)) {
return getProductQuantityUnit(product)
}
if (product?.title) {
return getWeightUnit()
}
return getWeightUnit()
}
2026-06-23 16:02:41 +03:30
/** وزن کل زیر مقدار مبادله‌شده — فقط محصول تعدادی (نه trade_by_quantity) */
export function shouldShowTransactionTotalWeightLine(product?: ProductUnitSource | null) {
if (!product || usesQuantityTrade(product) || !hasProductUnitWeight(product)) {
return false
}
return isCountBasedProduct(product)
}