widthdraw and deposit
This commit is contained in:
+10
-5
@@ -10,12 +10,17 @@ export interface ProductFile {
|
||||
|
||||
export function getFileUrl(file?: ProductFile | null): string | null {
|
||||
if (!file) return null
|
||||
if (file.full_src) return file.full_src
|
||||
if (file.url) return file.url
|
||||
if (!file.src) return null
|
||||
if (/^https?:\/\//i.test(file.src)) return file.src
|
||||
|
||||
for (const value of [file.full_src, file.url, file.src]) {
|
||||
if (!value) continue
|
||||
if (/^https?:\/\//i.test(value)) return value
|
||||
}
|
||||
|
||||
const relative = file.src || file.full_src
|
||||
if (!relative) return null
|
||||
|
||||
const base = baseURL.replace(/\/$/, '')
|
||||
const path = file.src.replace(/^\//, '')
|
||||
const path = String(relative).replace(/^\//, '')
|
||||
return `${base}/${path}`
|
||||
}
|
||||
|
||||
|
||||
@@ -164,12 +164,12 @@ if (isBuyP){
|
||||
return Promise.reject(getInsufficientCashWalletMessage(groupTypeP))
|
||||
}
|
||||
if (!walletCash?.walletInfo?.gold && isMainMetalWalletDealMethod(methodP)){
|
||||
return Promise.reject(getInsufficientGoldWalletMessage(groupTypeP))
|
||||
return Promise.reject(getInsufficientGoldWalletMessage(groupTypeP, methodP))
|
||||
}
|
||||
if (priceP * value > walletCash?.walletInfo?.cash && isCashLikeDealMethod(methodP))
|
||||
return Promise.reject(getInsufficientCashWalletMessage(groupTypeP))
|
||||
if (amountP * value > walletCash?.walletInfo?.gold && isMainMetalWalletDealMethod(methodP))
|
||||
return Promise.reject(getInsufficientGoldWalletMessage(groupTypeP))
|
||||
return Promise.reject(getInsufficientGoldWalletMessage(groupTypeP, methodP))
|
||||
else
|
||||
return Promise.resolve();
|
||||
}else {
|
||||
|
||||
@@ -0,0 +1,305 @@
|
||||
import type { Product } from '@/models/products'
|
||||
import type { UserWalletLine } from '@/models/wallet'
|
||||
import type { ProductFile } from '@/utils/file'
|
||||
import { getFileUrl } from '@/utils/file'
|
||||
import { isCountBasedProduct, type ProductUnitSource } from '@/utils/productDealMethod'
|
||||
import { isMeltedTradeGroup, normalizeProductGroupType, LEGACY_GROUP_KATOD } from '@/utils/productCategories'
|
||||
import defaultImg from '@/assets/img/defaultAbshodeh.svg'
|
||||
import goyImg from '@/assets/img/goyImg.svg'
|
||||
import mokaabImg from '@/assets/img/mokaabImg.svg'
|
||||
import sekkeImg from '@/assets/img/sekkeImg.svg'
|
||||
import mesImg from '@/assets/img/mesImg.jpg'
|
||||
import noghrehImg from '@/assets/img/noghrehImg.webp'
|
||||
import parsianImg from '@/assets/img/parsianImg.svg'
|
||||
|
||||
export const METAL_GOLD = 1
|
||||
export const METAL_SILVER = 2
|
||||
export const METAL_COPPER = 3
|
||||
|
||||
const GROUP_DEFAULT_IMAGES: Record<string, string> = {
|
||||
گوی: goyImg,
|
||||
مکعب: mokaabImg,
|
||||
سکه: sekkeImg,
|
||||
مس: mesImg,
|
||||
[LEGACY_GROUP_KATOD]: mesImg,
|
||||
نقره: noghrehImg,
|
||||
'سکه پارسیان': parsianImg,
|
||||
طلا: defaultImg,
|
||||
آبشده: defaultImg,
|
||||
}
|
||||
|
||||
export function getMetalLabel(metalId: number): string {
|
||||
switch (metalId) {
|
||||
case METAL_GOLD:
|
||||
return 'طلا'
|
||||
case METAL_SILVER:
|
||||
return 'نقره'
|
||||
case METAL_COPPER:
|
||||
return 'مس'
|
||||
default:
|
||||
return 'فلز'
|
||||
}
|
||||
}
|
||||
|
||||
export function getTotalMetalLabel(metalId: number): string {
|
||||
return `کل دارایی ${getMetalLabel(metalId)}`
|
||||
}
|
||||
|
||||
export function isSingleMetalCatalog(metalIds: number[]): boolean {
|
||||
return metalIds.length === 1
|
||||
}
|
||||
|
||||
export function getCatalogMetalIds(products?: Product[] | null): number[] {
|
||||
const ids = new Set<number>()
|
||||
for (const product of products ?? []) {
|
||||
const metalId = Number(product.metal_id)
|
||||
if (metalId > 0) {
|
||||
ids.add(metalId)
|
||||
}
|
||||
}
|
||||
return Array.from(ids).sort((a, b) => a - b)
|
||||
}
|
||||
|
||||
export function catalogHasCountBasedProducts(products?: Product[] | null): boolean {
|
||||
return (products ?? []).some((product) => isCountBasedProduct(product))
|
||||
}
|
||||
|
||||
export function catalogHasMeltedProducts(products?: Product[] | null): boolean {
|
||||
return (products ?? []).some((product) => isMeltedTradeGroup(product.group_type))
|
||||
}
|
||||
|
||||
export function enrichInventoryCardsWithCatalog<T extends { product_id?: number; file?: ProductFile | null }>(
|
||||
cards: T[],
|
||||
catalog: Product[]
|
||||
): T[] {
|
||||
return cards.map((card) => {
|
||||
const fromCatalog = catalog.find((product) => product.id === card.product_id)
|
||||
if (!fromCatalog) {
|
||||
return card
|
||||
}
|
||||
|
||||
return {
|
||||
...card,
|
||||
file: card.file ?? fromCatalog.file ?? null,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function enrichInventoryWithCatalog<T extends { id?: number }>(
|
||||
items: T[],
|
||||
catalog: Product[]
|
||||
): T[] {
|
||||
return items.map((item) => {
|
||||
const fromCatalog = catalog.find((product) => product.id === item.id)
|
||||
if (!fromCatalog) {
|
||||
return item
|
||||
}
|
||||
|
||||
const current = item as T & Product
|
||||
return {
|
||||
...fromCatalog,
|
||||
...current,
|
||||
wallet: current.wallet ?? fromCatalog.wallet,
|
||||
file: current.file ?? fromCatalog.file,
|
||||
metal_id: current.metal_id ?? fromCatalog.metal_id,
|
||||
group_type: current.group_type ?? fromCatalog.group_type,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
export function getProductDisplayImage(product?: {
|
||||
group_type?: string | null
|
||||
title?: string | null
|
||||
file?: ProductFile | null
|
||||
img?: string | null
|
||||
} | null): string {
|
||||
const fileUrl = getFileUrl(product?.file)
|
||||
if (fileUrl) {
|
||||
return fileUrl
|
||||
}
|
||||
|
||||
if (product?.img && /^https?:\/\//i.test(product.img)) {
|
||||
return product.img
|
||||
}
|
||||
|
||||
const group = normalizeProductGroupType(product?.group_type)
|
||||
if (group && GROUP_DEFAULT_IMAGES[group]) {
|
||||
return GROUP_DEFAULT_IMAGES[group]
|
||||
}
|
||||
|
||||
return defaultImg
|
||||
}
|
||||
|
||||
type InventoryProduct = ProductUnitSource & {
|
||||
metal_id?: number | null
|
||||
title?: string | null
|
||||
wallet?: { gold?: number | null } | null
|
||||
}
|
||||
|
||||
export function sumCountBasedInventory(products?: InventoryProduct[] | null): number {
|
||||
return (products ?? [])
|
||||
.filter((product) => product.title !== 'آبشده نقدی' && isCountBasedProduct(product))
|
||||
.reduce((sum, product) => sum + Number(product.wallet?.gold ?? 0), 0)
|
||||
}
|
||||
|
||||
export function sumProductWalletByMetal(
|
||||
products: InventoryProduct[] | null | undefined,
|
||||
metalId: number
|
||||
): number {
|
||||
return (products ?? [])
|
||||
.filter((product) => Number(product.metal_id) === metalId)
|
||||
.reduce((sum, product) => sum + Number(product.wallet?.gold ?? 0), 0)
|
||||
}
|
||||
|
||||
export function getMainWalletLine(wallets?: UserWalletLine[] | null): UserWalletLine | undefined {
|
||||
return wallets?.find((line) => line.product_id == null)
|
||||
}
|
||||
|
||||
export function getMainWalletGold(wallets?: UserWalletLine[] | null): number {
|
||||
return Number(getMainWalletLine(wallets)?.gold ?? 0)
|
||||
}
|
||||
|
||||
export function getMainWalletCash(wallets?: UserWalletLine[] | null): number {
|
||||
return Number(getMainWalletLine(wallets)?.cash ?? 0)
|
||||
}
|
||||
|
||||
export function sumWalletsGold(
|
||||
wallets?: UserWalletLine[] | null,
|
||||
metalId?: number | null
|
||||
): number {
|
||||
if (!wallets?.length) {
|
||||
return 0
|
||||
}
|
||||
|
||||
return wallets.reduce((sum, line) => {
|
||||
const weight = Number(line.gold ?? 0)
|
||||
if (metalId == null) {
|
||||
return sum + weight
|
||||
}
|
||||
|
||||
if (line.product_id == null) {
|
||||
return metalId === METAL_GOLD ? sum + weight : sum
|
||||
}
|
||||
|
||||
return Number(line.product?.metal_id) === metalId ? sum + weight : sum
|
||||
}, 0)
|
||||
}
|
||||
|
||||
export function sumProductWalletsGold(
|
||||
wallets?: UserWalletLine[] | null,
|
||||
metalId?: number | null
|
||||
): number {
|
||||
return (wallets ?? [])
|
||||
.filter((line) => line.product_id != null)
|
||||
.reduce((sum, line) => {
|
||||
const weight = Number(line.gold ?? 0)
|
||||
if (metalId == null) {
|
||||
return sum + weight
|
||||
}
|
||||
|
||||
return Number(line.product?.metal_id) === metalId ? sum + weight : sum
|
||||
}, 0)
|
||||
}
|
||||
|
||||
export function sumInventoryMetalWeight(products?: InventoryProduct[] | null): number {
|
||||
return (products ?? [])
|
||||
.filter((product) => product.title !== 'آبشده نقدی')
|
||||
.reduce((sum, product) => sum + Number(product.wallet?.gold ?? 0), 0)
|
||||
}
|
||||
|
||||
export function getTotalMetalWeight(
|
||||
walletInfo?: Record<string, unknown> | null,
|
||||
wallets?: UserWalletLine[] | null,
|
||||
inventoryProducts?: InventoryProduct[] | null
|
||||
): number {
|
||||
const fromInventory = sumInventoryMetalWeight(inventoryProducts)
|
||||
if (fromInventory > 0) {
|
||||
return fromInventory
|
||||
}
|
||||
|
||||
const fromProductWallets = sumProductWalletsGold(wallets)
|
||||
if (fromProductWallets > 0) {
|
||||
return fromProductWallets
|
||||
}
|
||||
|
||||
if (wallets?.length) {
|
||||
return getMainWalletGold(wallets)
|
||||
}
|
||||
|
||||
return Number(walletInfo?.treasure ?? walletInfo?.gold_sum ?? walletInfo?.count_gold ?? 0)
|
||||
}
|
||||
|
||||
/** فقط موجودی نقدی کیف اصلی — فیلد gold (مثل 0.3 کیلوگرم) جزو دارایی ریالی نیست */
|
||||
export function getRialCashAmount(
|
||||
walletInfo?: Record<string, unknown> | null,
|
||||
wallets?: UserWalletLine[] | null
|
||||
): number {
|
||||
const mainCash = getMainWalletCash(wallets)
|
||||
if (mainCash > 0) {
|
||||
return mainCash
|
||||
}
|
||||
|
||||
return Number(walletInfo?.count_cash ?? walletInfo?.cash ?? 0)
|
||||
}
|
||||
|
||||
export function getTotalRialEquivalent(walletInfo?: Record<string, unknown> | null): number {
|
||||
return Number(walletInfo?.count_cash_total ?? 0)
|
||||
}
|
||||
|
||||
export function getMetalAssetAmount(
|
||||
walletInfo: Record<string, unknown> | null | undefined,
|
||||
metalId: number,
|
||||
inventoryProducts?: InventoryProduct[] | null
|
||||
): number {
|
||||
if (inventoryProducts?.length) {
|
||||
const fromProducts = sumProductWalletByMetal(inventoryProducts, metalId)
|
||||
if (fromProducts > 0 || inventoryProducts.some((product) => Number(product.metal_id) === metalId)) {
|
||||
return fromProducts
|
||||
}
|
||||
}
|
||||
|
||||
if (!walletInfo) {
|
||||
return 0
|
||||
}
|
||||
|
||||
switch (metalId) {
|
||||
case METAL_GOLD:
|
||||
return Number(walletInfo.count_gold_wallets ?? walletInfo.count_gold ?? 0)
|
||||
case METAL_SILVER:
|
||||
return Number(walletInfo.count_silver ?? 0)
|
||||
case METAL_COPPER:
|
||||
return Number(walletInfo.count_copper ?? 0)
|
||||
default:
|
||||
return 0
|
||||
}
|
||||
}
|
||||
|
||||
export function getMetalAssetAmountForDisplay(
|
||||
walletInfo: Record<string, unknown> | null | undefined,
|
||||
metalId: number,
|
||||
catalogMetalIds: number[],
|
||||
inventoryProducts?: InventoryProduct[] | null,
|
||||
wallets?: UserWalletLine[] | null
|
||||
): number {
|
||||
if (isSingleMetalCatalog(catalogMetalIds)) {
|
||||
return getTotalMetalWeight(walletInfo, wallets, inventoryProducts)
|
||||
}
|
||||
|
||||
const productWeight = sumProductWalletByMetal(inventoryProducts, metalId)
|
||||
const mainWalletWeight = wallets?.length
|
||||
? getMainWalletGold(wallets)
|
||||
: Number(walletInfo?.count_gold_wallet ?? 0)
|
||||
|
||||
if (catalogHasMeltedProducts(inventoryProducts as Product[] | null | undefined) && metalId === catalogMetalIds[0]) {
|
||||
return productWeight + mainWalletWeight
|
||||
}
|
||||
|
||||
if (wallets?.length) {
|
||||
const walletWeight = sumWalletsGold(wallets, metalId)
|
||||
if (walletWeight > 0) {
|
||||
return walletWeight
|
||||
}
|
||||
}
|
||||
|
||||
return productWeight || getMetalAssetAmount(walletInfo, metalId, inventoryProducts)
|
||||
}
|
||||
@@ -0,0 +1,75 @@
|
||||
/** دستهبندی یکسان محصول در همه اپهای ماژولار */
|
||||
export const PRODUCT_CATEGORY_ABSHODE = 'آبشده'
|
||||
|
||||
export const UNIFIED_PRODUCT_CATEGORIES = [
|
||||
PRODUCT_CATEGORY_ABSHODE,
|
||||
'مکعب',
|
||||
'گوی',
|
||||
'سکه',
|
||||
'سکه پارسیان',
|
||||
'مس',
|
||||
'نقره',
|
||||
] as const
|
||||
|
||||
/** دستههای قدیمی بورس مس — سازگاری با داده موجود */
|
||||
export const LEGACY_GROUP_KATOD = 'کاتد مس'
|
||||
export const LEGACY_GROUP_MAFTOL = 'مفتول مس'
|
||||
export const LEGACY_GROUP_GOLD = 'طلا'
|
||||
|
||||
/** دستههای قدیمی که UI آبشدهای دارند — «طلا» عمداً نیست (گاروسی با DealProduct میماند) */
|
||||
export const LEGACY_MELTED_GROUP_TYPES = [LEGACY_GROUP_KATOD] as const
|
||||
|
||||
export function normalizeProductGroupType(groupType?: string | null) {
|
||||
return (groupType ?? '').trim()
|
||||
}
|
||||
|
||||
/** محصول آبشدهای — UI گرم/کیلوگرم مثل indexGold */
|
||||
export function isMeltedTradeGroup(groupType?: string | null) {
|
||||
const group = normalizeProductGroupType(groupType)
|
||||
return group === PRODUCT_CATEGORY_ABSHODE || LEGACY_MELTED_GROUP_TYPES.includes(group as typeof LEGACY_MELTED_GROUP_TYPES[number])
|
||||
}
|
||||
|
||||
export function isMetalCommodityGroup(groupType?: string | null) {
|
||||
const group = normalizeProductGroupType(groupType)
|
||||
return group === 'مس' || group === 'نقره'
|
||||
}
|
||||
|
||||
export function isLegacyMaftolGroup(groupType?: string | null) {
|
||||
return normalizeProductGroupType(groupType) === LEGACY_GROUP_MAFTOL
|
||||
}
|
||||
|
||||
/** نگاشت دسته قدیمی به دسته یکسان */
|
||||
export function normalizeToUnifiedCategory(groupType?: string | null) {
|
||||
const group = normalizeProductGroupType(groupType)
|
||||
if (group === LEGACY_GROUP_KATOD || group === LEGACY_GROUP_GOLD) {
|
||||
return PRODUCT_CATEGORY_ABSHODE
|
||||
}
|
||||
if (group === LEGACY_GROUP_MAFTOL) {
|
||||
return 'مس'
|
||||
}
|
||||
return group
|
||||
}
|
||||
|
||||
export type MeltedPriceSource = 'app' | 'fixed' | 'reference'
|
||||
|
||||
export function resolveMeltedPriceSource(product?: {
|
||||
reading_method?: string | null
|
||||
direct_price?: number | null
|
||||
} | null): MeltedPriceSource {
|
||||
if (product?.reading_method) {
|
||||
return 'reference'
|
||||
}
|
||||
if (Number(product?.direct_price) === 1) {
|
||||
return 'fixed'
|
||||
}
|
||||
return 'app'
|
||||
}
|
||||
|
||||
export function isMeltedProductUsingAppPrice(product?: {
|
||||
group_type?: string | null
|
||||
reading_method?: string | null
|
||||
direct_price?: number | null
|
||||
} | null) {
|
||||
return isMeltedTradeGroup(product?.group_type)
|
||||
&& resolveMeltedPriceSource(product) === 'app'
|
||||
}
|
||||
+121
-46
@@ -1,18 +1,22 @@
|
||||
import type { SelectItem } from '@/models/SelectItem'
|
||||
import { isBoursecuProject } from '@/utils/config'
|
||||
import { useSettingsStore } from '@/store/settingsStore'
|
||||
import {
|
||||
isLegacyMaftolGroup,
|
||||
isMeltedTradeGroup,
|
||||
LEGACY_GROUP_KATOD,
|
||||
LEGACY_GROUP_MAFTOL,
|
||||
normalizeProductGroupType,
|
||||
PRODUCT_CATEGORY_ABSHODE,
|
||||
} from '@/utils/productCategories'
|
||||
|
||||
/** شناسه group_type محصول در دیتابیس — نه برچسب نمایشی */
|
||||
export const BOURSECU_GROUP_MAFTOL = 'مفتول مس'
|
||||
export const BOURSECU_GROUP_KATOD = 'کاتد مس'
|
||||
export const BOURSECU_GROUP_ABSHODE = 'آبشده'
|
||||
/** @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
|
||||
|
||||
export const BOURSECU_WALLET_LABEL_GENERIC = 'موجودی کیف'
|
||||
|
||||
export function normalizeProductGroupType(groupType?: string | null) {
|
||||
return (groupType ?? '').trim()
|
||||
}
|
||||
|
||||
export function isBoursecuDealProductGroup(groupType?: string | null) {
|
||||
if (!isBoursecuProject()) {
|
||||
return false
|
||||
@@ -22,10 +26,12 @@ export function isBoursecuDealProductGroup(groupType?: string | null) {
|
||||
return group === BOURSECU_GROUP_MAFTOL
|
||||
|| group === BOURSECU_GROUP_KATOD
|
||||
|| group === BOURSECU_GROUP_ABSHODE
|
||||
|| group === 'مس'
|
||||
}
|
||||
|
||||
export function isMaftolMesGroup(groupType?: string | null) {
|
||||
return normalizeProductGroupType(groupType) === BOURSECU_GROUP_MAFTOL
|
||||
const group = normalizeProductGroupType(groupType)
|
||||
return group === BOURSECU_GROUP_MAFTOL || (isBoursecuProject() && group === 'مس')
|
||||
}
|
||||
|
||||
export function isKatodMesGroup(groupType?: string | null) {
|
||||
@@ -33,7 +39,7 @@ export function isKatodMesGroup(groupType?: string | null) {
|
||||
}
|
||||
|
||||
export function isGoldOnlyDealGroup(groupType?: string | null) {
|
||||
return normalizeProductGroupType(groupType) === BOURSECU_GROUP_ABSHODE
|
||||
return isMeltedTradeGroup(groupType)
|
||||
}
|
||||
|
||||
export interface ProductUnitSource {
|
||||
@@ -43,6 +49,11 @@ export interface ProductUnitSource {
|
||||
amount?: number | null
|
||||
}
|
||||
|
||||
export function isWeightBasedProductUnit(unit?: string | null) {
|
||||
const value = (unit ?? '').trim()
|
||||
return value === 'کیلوگرم' || value === 'گرم'
|
||||
}
|
||||
|
||||
const COUNT_BASED_GROUP_TYPES = ['سکه', 'گوی', 'مکعب', 'شمش', 'سکه پارسیان']
|
||||
|
||||
/** مطابق ادمین: وزن «دارد» یعنی amount مقدار واقعی است؛ «ندارد» یعنی amount = 1 */
|
||||
@@ -52,14 +63,19 @@ export function hasProductUnitWeight(product?: ProductUnitSource | null) {
|
||||
}
|
||||
|
||||
export function getProductWeightUnit(product?: ProductUnitSource | null) {
|
||||
const unit = product?.unit?.trim()
|
||||
if (unit && isWeightBasedProductUnit(unit)) {
|
||||
return unit
|
||||
}
|
||||
|
||||
if (isBoursecuProject()) {
|
||||
const group = normalizeProductGroupType(product?.group_type)
|
||||
if (group === BOURSECU_GROUP_MAFTOL || group === BOURSECU_GROUP_KATOD || group === BOURSECU_GROUP_ABSHODE) {
|
||||
if (group === BOURSECU_GROUP_MAFTOL || group === BOURSECU_GROUP_KATOD || group === BOURSECU_GROUP_ABSHODE || group === 'مس' || isMeltedTradeGroup(group)) {
|
||||
return getWeightUnit()
|
||||
}
|
||||
}
|
||||
|
||||
if (!isCountBasedProduct(product) || isGoldOnlyDealGroup(product?.group_type)) {
|
||||
if (!isCountBasedProduct(product) || isMeltedTradeGroup(product?.group_type)) {
|
||||
return getWeightUnit()
|
||||
}
|
||||
|
||||
@@ -124,12 +140,16 @@ export function isCountBasedProduct(product?: ProductUnitSource | null) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (isWeightBasedProductUnit(product.unit)) {
|
||||
return false
|
||||
}
|
||||
|
||||
if (product.direct_price != null && product.direct_price !== 0) {
|
||||
return true
|
||||
}
|
||||
|
||||
const group = normalizeProductGroupType(product.group_type)
|
||||
if (group === BOURSECU_GROUP_MAFTOL || group === BOURSECU_GROUP_KATOD) {
|
||||
if (group === BOURSECU_GROUP_MAFTOL || isLegacyMaftolGroup(group) || (isBoursecuProject() && group === 'مس')) {
|
||||
return true
|
||||
}
|
||||
|
||||
@@ -137,15 +157,15 @@ export function isCountBasedProduct(product?: ProductUnitSource | null) {
|
||||
}
|
||||
|
||||
export function getProductQuantityUnit(product?: ProductUnitSource | null) {
|
||||
if (isCountBasedProduct(product)) {
|
||||
return 'عدد'
|
||||
}
|
||||
|
||||
const unit = product?.unit?.trim()
|
||||
if (unit) {
|
||||
return unit
|
||||
}
|
||||
|
||||
if (isCountBasedProduct(product)) {
|
||||
return 'عدد'
|
||||
}
|
||||
|
||||
return getWeightUnit()
|
||||
}
|
||||
|
||||
@@ -157,17 +177,34 @@ function getDefaultTypeDealOptions(): SelectItem[] {
|
||||
]
|
||||
}
|
||||
|
||||
export function getProductDealMethodOptions(groupType?: string | null): SelectItem[] {
|
||||
export function getProductDealMethodOptions(groupType?: string | null, isBuy = true): SelectItem[] {
|
||||
const settingsStore = useSettingsStore()
|
||||
|
||||
if (!isBoursecuProject()) {
|
||||
return getDefaultTypeDealOptions()
|
||||
if (isBuy) {
|
||||
return [
|
||||
{ value: 'نقدی', key: 'cash' },
|
||||
{ value: settingsStore.metalTypeLabel, key: 'gold' },
|
||||
]
|
||||
}
|
||||
|
||||
return [
|
||||
{ value: 'نقدی', key: 'cash' },
|
||||
{ value: `دریافت ${settingsStore.metalTypeLabel}`, key: 'gold' },
|
||||
]
|
||||
}
|
||||
|
||||
if (isMaftolMesGroup(groupType)) {
|
||||
if (isBuy) {
|
||||
return [
|
||||
{ value: `پرداخت با ${settingsStore.metalTypeLabel}`, key: 'katod' },
|
||||
{ value: 'نقدی', key: 'cash' },
|
||||
]
|
||||
}
|
||||
|
||||
return [
|
||||
{ value: settingsStore.metalTypeLabel, key: 'katod' },
|
||||
{ value: 'نقدی', key: 'cash' },
|
||||
{ value: `دریافت ${settingsStore.metalTypeLabel}`, key: 'katod' },
|
||||
]
|
||||
}
|
||||
|
||||
@@ -175,15 +212,38 @@ export function getProductDealMethodOptions(groupType?: string | null): SelectIt
|
||||
return [{ value: 'نقدی', key: 'cash' }]
|
||||
}
|
||||
|
||||
if (isGoldOnlyDealGroup(groupType)) {
|
||||
if (isMeltedTradeGroup(groupType)) {
|
||||
return [{ value: settingsStore.meltedGoldLabel, key: 'gold' }]
|
||||
}
|
||||
|
||||
return getDefaultTypeDealOptions()
|
||||
}
|
||||
|
||||
export function getDefaultProductDealMethod(groupType?: string | null) {
|
||||
return getProductDealMethodOptions(groupType)[0]?.key ?? 'cash'
|
||||
export function getDefaultProductDealMethod(groupType?: string | null, isBuy = true) {
|
||||
return getProductDealMethodOptions(groupType, isBuy)[0]?.key ?? 'cash'
|
||||
}
|
||||
|
||||
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,
|
||||
product?: ProductUnitSource & { percent_fee_sell?: number | null } | null,
|
||||
) {
|
||||
const quantity = Number(count ?? 0)
|
||||
const unitAmount = Number(product?.amount ?? 0)
|
||||
if (!quantity || !unitAmount) {
|
||||
return 0
|
||||
}
|
||||
|
||||
const grossAmount = quantity * unitAmount
|
||||
const feeRate = Number(product?.percent_fee_sell ?? 0)
|
||||
return grossAmount - feeRate * grossAmount
|
||||
}
|
||||
|
||||
export function isCashLikeDealMethod(method?: string | null) {
|
||||
@@ -204,36 +264,42 @@ export function getMeltedGoldWalletLabel() {
|
||||
return `موجودی کیف ${useSettingsStore().meltedGoldLabel}`
|
||||
}
|
||||
|
||||
export function getGoldWalletLabel(groupType?: string | null) {
|
||||
const settingsStore = useSettingsStore()
|
||||
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
|
||||
}
|
||||
|
||||
return useSettingsStore().metalTypeLabel
|
||||
}
|
||||
|
||||
export function getGoldWalletLabel(groupType?: string | null) {
|
||||
if (!isBoursecuProject()) {
|
||||
return getMainMetalWalletLabel()
|
||||
}
|
||||
|
||||
const group = normalizeProductGroupType(groupType)
|
||||
if (group === BOURSECU_GROUP_MAFTOL) {
|
||||
return `موجودی کیف ${BOURSECU_GROUP_MAFTOL}`
|
||||
if (group === BOURSECU_GROUP_MAFTOL
|
||||
|| group === BOURSECU_GROUP_KATOD
|
||||
|| group === BOURSECU_GROUP_ABSHODE) {
|
||||
return `موجودی کیف ${getBoursecuMetalWalletLabel(groupType)}`
|
||||
}
|
||||
if (group === BOURSECU_GROUP_KATOD || group === BOURSECU_GROUP_ABSHODE || !group) {
|
||||
return group === BOURSECU_GROUP_ABSHODE
|
||||
? getMeltedGoldWalletLabel()
|
||||
: getMainMetalWalletLabel()
|
||||
|
||||
if (!group) {
|
||||
return getMainMetalWalletLabel()
|
||||
}
|
||||
|
||||
return BOURSECU_WALLET_LABEL_GENERIC
|
||||
}
|
||||
|
||||
export function getCashWalletLabel(groupType?: string | null) {
|
||||
if (!isBoursecuProject()) {
|
||||
return 'موجودی کیف پول'
|
||||
}
|
||||
|
||||
const group = normalizeProductGroupType(groupType)
|
||||
if (group === BOURSECU_GROUP_MAFTOL) {
|
||||
return `موجودی کیف ${BOURSECU_GROUP_MAFTOL}`
|
||||
}
|
||||
|
||||
/** پرداخت نقدی همیشه از کیف پول ریالی — مستقل از نوع محصول */
|
||||
export function getCashWalletLabel(_groupType?: string | null) {
|
||||
return 'موجودی کیف پول'
|
||||
}
|
||||
|
||||
@@ -250,7 +316,7 @@ export function getMaftolAssetLabel() {
|
||||
}
|
||||
|
||||
export function getWeightUnit() {
|
||||
return isBoursecuProject() ? 'کیلوگرم' : 'گرم'
|
||||
return useSettingsStore().tradeWeightUnit
|
||||
}
|
||||
|
||||
export function formatBoursecuAssetAmount(amount?: number | null) {
|
||||
@@ -269,12 +335,21 @@ export function formatCashWalletBalanceText(cashFormatted: string | number, grou
|
||||
return `${getCashWalletLabel(groupType)}: ${cashFormatted} ریال`
|
||||
}
|
||||
|
||||
export function getInsufficientGoldWalletMessage(groupType?: string | null) {
|
||||
return `${getGoldWalletLabel(groupType)} ناکافی است`
|
||||
/** برچسب کیف فلزی متناسب با نحوه پرداخت (مثلاً کاتد مس برای خرید مفتول با کیف کاتد) */
|
||||
export function getMetalWalletLabelForDealMethod(method?: string | null, groupType?: string | null) {
|
||||
if (!isBoursecuProject() || method === 'katod') {
|
||||
return getMainMetalWalletLabel()
|
||||
}
|
||||
|
||||
return getGoldWalletLabel(groupType)
|
||||
}
|
||||
|
||||
export function getInsufficientCashWalletMessage(groupType?: string | null) {
|
||||
return `${getCashWalletLabel(groupType)} ناکافی است`
|
||||
export function getInsufficientGoldWalletMessage(groupType?: string | null, method?: string | null) {
|
||||
return `${getMetalWalletLabelForDealMethod(method, groupType)} ناکافی است`
|
||||
}
|
||||
|
||||
export function getInsufficientCashWalletMessage(_groupType?: string | null) {
|
||||
return `${getCashWalletLabel()} ناکافی است`
|
||||
}
|
||||
|
||||
export function getInsufficientMainMetalWalletMessage() {
|
||||
|
||||
@@ -1,13 +1,28 @@
|
||||
import type { Product } from '@/models/products'
|
||||
import { getTradeBuyPrice, getTradeSellPrice, lastPrice } from '@/utils/price'
|
||||
import { isMetalCommodityGroup, isMeltedProductUsingAppPrice, isMeltedTradeGroup } from '@/utils/productCategories'
|
||||
|
||||
function applyPriceOffsetPercent(basePrice: number, offsetPercent?: number | null) {
|
||||
const offset = Number(offsetPercent ?? 0)
|
||||
if (!offset) {
|
||||
return basePrice
|
||||
}
|
||||
|
||||
return Math.round(basePrice * (1 + offset / 100))
|
||||
}
|
||||
|
||||
/** قیمت خرید نمایشی محصول (همان مقداری که در لیست و اکشنشیت نشان داده میشود) */
|
||||
export function getProductBuyPrice(product: Product): number {
|
||||
if (product.group_type === 'آبشده') {
|
||||
return getTradeBuyPrice(lastPrice.value) + (product.cash_fee_buy ?? 0)
|
||||
if (isMeltedProductUsingAppPrice(product)) {
|
||||
const base = applyPriceOffsetPercent(getTradeBuyPrice(lastPrice.value), product.price_offset_percent)
|
||||
return base + (product.cash_fee_buy ?? 0)
|
||||
}
|
||||
|
||||
if (['مس', 'نقره'].includes(product.group_type)) {
|
||||
if (isMeltedTradeGroup(product.group_type)) {
|
||||
return (product.price ?? 0) + (product.cash_fee_buy ?? 0)
|
||||
}
|
||||
|
||||
if (isMetalCommodityGroup(product.group_type)) {
|
||||
const base = (product.price_profit ?? 0) + (product.price ?? 0)
|
||||
return base + (product.cash_fee_buy ?? 0)
|
||||
}
|
||||
@@ -18,14 +33,23 @@ export function getProductBuyPrice(product: Product): number {
|
||||
: basePrice
|
||||
}
|
||||
|
||||
/** قیمت فروش نمایشی آبشده — فقط cash_fee_sell محصول اختلاف ایجاد میکند */
|
||||
/** قیمت فروش نمایشی محصول آبشدهای */
|
||||
export function getProductSellPrice(product: Product): number {
|
||||
if (product.group_type === 'آبشده') {
|
||||
return getTradeSellPrice(lastPrice.value) - (product.cash_fee_sell ?? 0)
|
||||
if (isMeltedProductUsingAppPrice(product)) {
|
||||
const base = applyPriceOffsetPercent(getTradeSellPrice(lastPrice.value), product.price_offset_percent)
|
||||
return base - (product.cash_fee_sell ?? 0)
|
||||
}
|
||||
|
||||
if (isMeltedTradeGroup(product.group_type)) {
|
||||
const base = (product.price_profit ?? product.price ?? 0)
|
||||
return base - (product.cash_fee_sell ?? 0)
|
||||
}
|
||||
|
||||
return getTradeSellPrice(lastPrice.value)
|
||||
}
|
||||
|
||||
export function isProductPriceInactive(product: Product): boolean {
|
||||
return getProductBuyPrice(product) <= 0
|
||||
}
|
||||
|
||||
export { isMeltedTradeGroup, isMeltedProductUsingAppPrice } from '@/utils/productCategories'
|
||||
|
||||
@@ -0,0 +1,33 @@
|
||||
export const TRADE_WEIGHT_UNIT_GRAM = 'گرم'
|
||||
export const TRADE_WEIGHT_UNIT_KILOGRAM = 'کیلوگرم'
|
||||
|
||||
export function isKilogramUnit(unit?: string | null) {
|
||||
const value = (unit ?? '').trim()
|
||||
return value === TRADE_WEIGHT_UNIT_KILOGRAM || value === 'kilogram' || value === 'kg'
|
||||
}
|
||||
|
||||
/** واحد نمایش از ستینگ — خالی یا نامعتبر = گرم */
|
||||
export function resolveTradeWeightUnit(settingValue?: string | number | null) {
|
||||
return isKilogramUnit(settingValue?.toString()) ? TRADE_WEIGHT_UNIT_KILOGRAM : TRADE_WEIGHT_UNIT_GRAM
|
||||
}
|
||||
|
||||
export function weightToGrams(value: number, fromUnit?: string | null) {
|
||||
return isKilogramUnit(fromUnit) ? value * 1000 : value
|
||||
}
|
||||
|
||||
export function gramsToTradeUnit(grams: number, displayUnit?: string | null) {
|
||||
return isKilogramUnit(displayUnit ?? resolveTradeWeightUnit(null)) ? grams / 1000 : grams
|
||||
}
|
||||
|
||||
export function convertWeightToDisplayUnit(
|
||||
value: number,
|
||||
fromUnit?: string | null,
|
||||
displayUnit?: string | null
|
||||
) {
|
||||
return gramsToTradeUnit(weightToGrams(value, fromUnit), displayUnit)
|
||||
}
|
||||
|
||||
export function formatTradeWeight(value: number, displayUnit?: string | null) {
|
||||
const unit = resolveTradeWeightUnit(displayUnit)
|
||||
return `${value} ${unit}`
|
||||
}
|
||||
Reference in New Issue
Block a user