added percent in product fee

This commit is contained in:
2026-07-04 17:55:05 +03:30
parent f7cc5180b1
commit 10b84d6cfe
7 changed files with 91 additions and 15 deletions
+2
View File
@@ -11,8 +11,10 @@ export interface Product{
amount: number, amount: number,
percent_fee_buy: number, percent_fee_buy: number,
cash_fee_buy: number, cash_fee_buy: number,
cash_fee_buy_is_percent?: boolean,
percent_fee_sell: number, percent_fee_sell: number,
cash_fee_sell: number, cash_fee_sell: number,
cash_fee_sell_is_percent?: boolean,
order_limit_enabled?: boolean, order_limit_enabled?: boolean,
min_order_cash?: number | null, min_order_cash?: number | null,
max_order_cash?: number | null, max_order_cash?: number | null,
@@ -464,6 +464,7 @@ export const SETTING_LOCKED_KEYS = new Set([
'group_sms', 'group_sms',
'has_page_earn_money', 'has_page_earn_money',
'is_store', 'is_store',
'sms_panel',
'logo_login', 'logo_register', 'title_pwa', 'title_fav', 'logo_login', 'logo_register', 'title_pwa', 'title_fav',
'main_product', 'main_wallet_products', 'metal_type', 'main_metal', 'main_product', 'main_wallet_products', 'metal_type', 'main_metal',
'montify_name', 'montify_name',
@@ -24,8 +24,8 @@
<BasicInfoItem title="واحد" :value="product.unit || '—'" /> <BasicInfoItem title="واحد" :value="product.unit || '—'" />
<BasicInfoItem title="وزن" :value="product.amount ?? '—'" /> <BasicInfoItem title="وزن" :value="product.amount ?? '—'" />
<BasicInfoItem title="قیمت" :value="usePrice(product.price || 0)" /> <BasicInfoItem title="قیمت" :value="usePrice(product.price || 0)" />
<BasicInfoItem title="هزینه نقدی خرید" :value="usePrice(product.cash_fee_buy || 0)" /> <BasicInfoItem title="هزینه خرید" :value="formatCashFee(product.cash_fee_buy, product.cash_fee_buy_is_percent)" />
<BasicInfoItem title="هزینه نقدی فروش" :value="usePrice(product.cash_fee_sell || 0)" /> <BasicInfoItem title="هزینه فروش" :value="formatCashFee(product.cash_fee_sell, product.cash_fee_sell_is_percent)" />
<BasicInfoItem title="معامله مقداری" :value="product.trade_by_quantity ? 'بله' : 'خیر'" /> <BasicInfoItem title="معامله مقداری" :value="product.trade_by_quantity ? 'بله' : 'خیر'" />
<BasicInfoItem title="تاریخ ثبت" :value="product.created_at ? toJalali(product.created_at) : '—'" /> <BasicInfoItem title="تاریخ ثبت" :value="product.created_at ? toJalali(product.created_at) : '—'" />
</div> </div>
@@ -87,4 +87,17 @@ const visibleProxy = computed({
get: () => props.visible, get: () => props.visible,
set: (value: boolean) => emit('update:visible', value), set: (value: boolean) => emit('update:visible', value),
}) })
function formatCashFee(value?: number | null, isPercent?: boolean | null) {
const raw = Number(value ?? 0)
if (!raw) {
return '۰'
}
if (isPercent) {
return `${raw}%`
}
return usePrice(raw)
}
</script> </script>
@@ -248,15 +248,41 @@
<div class="grid gap-4 md:grid-cols-2"> <div class="grid gap-4 md:grid-cols-2">
<a-form-item name="cash_fee_buy" :rules="requiredPriceRules('هزینه نقدی موقع خرید')"> <a-form-item name="cash_fee_buy" :rules="requiredPriceRules('هزینه نقدی موقع خرید')">
<template #label> <template #label>
<DashboardLabelWithHelp label="هزینه نقدی خرید" :help="cashFeeBuyHelp" size="sm" /> <DashboardLabelWithHelp label="هزینه خرید" :help="cashFeeBuyHelp" size="sm" />
</template> </template>
<BasicInput v-model:value="form.cash_fee_buy" addon-before="ریال" type="price" /> <div class="flex flex-col gap-2 sm:flex-row sm:items-center">
<a-select
v-model:value="form.cash_fee_buy_is_percent"
class="w-full sm:w-36"
:options="cashFeeModeOptions"
/>
<BasicInput
v-model:value="form.cash_fee_buy"
:addon-before="form.cash_fee_buy_is_percent ? '%' : 'ریال'"
:type="form.cash_fee_buy_is_percent ? 'number' : 'price'"
class="flex-1"
:placeholder="form.cash_fee_buy_is_percent ? 'مثلاً 5' : undefined"
/>
</div>
</a-form-item> </a-form-item>
<a-form-item name="cash_fee_sell" :rules="requiredPriceRules('هزینه نقدی موقع فروش')"> <a-form-item name="cash_fee_sell" :rules="requiredPriceRules('هزینه نقدی موقع فروش')">
<template #label> <template #label>
<DashboardLabelWithHelp label="هزینه نقدی فروش" :help="cashFeeSellHelp" size="sm" /> <DashboardLabelWithHelp label="هزینه فروش" :help="cashFeeSellHelp" size="sm" />
</template> </template>
<BasicInput v-model:value="form.cash_fee_sell" addon-before="ریال" type="price" /> <div class="flex flex-col gap-2 sm:flex-row sm:items-center">
<a-select
v-model:value="form.cash_fee_sell_is_percent"
class="w-full sm:w-36"
:options="cashFeeModeOptions"
/>
<BasicInput
v-model:value="form.cash_fee_sell"
:addon-before="form.cash_fee_sell_is_percent ? '%' : 'ریال'"
:type="form.cash_fee_sell_is_percent ? 'number' : 'price'"
class="flex-1"
:placeholder="form.cash_fee_sell_is_percent ? 'مثلاً 10' : undefined"
/>
</div>
</a-form-item> </a-form-item>
<a-form-item name="show_in_assets"> <a-form-item name="show_in_assets">
<template #label> <template #label>
@@ -428,13 +454,20 @@ const inventoryHelp: DashboardHelp = {
} }
const cashFeeBuyHelp: DashboardHelp = { const cashFeeBuyHelp: DashboardHelp = {
description: 'کارمزد ریالی اضافه‌شده به قیمت خرید برای مشتری.', description: 'مبلغ اضافه روی قیمت پایه برای خرید — نقدی (ریال ثابت) یا درصدی از مظنه.',
formula: 'نقدی: +۱۰۰٬۰۰۰ ریال | درصدی: ۵٪ از قیمت پایه',
} }
const cashFeeSellHelp: DashboardHelp = { const cashFeeSellHelp: DashboardHelp = {
description: 'کارمزد ریالی کسرشده از قیمت فروش برای مشتری.', description: 'مبلغ کسر از قیمت پایه برای فروش — نقدی (ریال ثابت) یا درصدی از مظنه.',
formula: 'نقدی: −۲۰۰٬۰۰۰ ریال | درصدی: ۱۰٪ از قیمت پایه',
} }
const cashFeeModeOptions = [
{ value: false, label: 'نقدی' },
{ value: true, label: 'درصدی' },
]
const showInAssetsHelp: DashboardHelp = { const showInAssetsHelp: DashboardHelp = {
description: 'روشن: این محصول در صفحه دارایی‌های مشتری نمایش داده می‌شود.', description: 'روشن: این محصول در صفحه دارایی‌های مشتری نمایش داده می‌شود.',
} }
@@ -116,6 +116,12 @@ function updatedAtLabel(row: Product) {
} }
function cashFeeLabel(row: Product) { function cashFeeLabel(row: Product) {
return usePrice((row.cash_fee_buy || 0) + (row.cash_fee_sell || 0)) const buy = row.cash_fee_buy_is_percent
? `${row.cash_fee_buy || 0}%`
: usePrice(row.cash_fee_buy || 0)
const sell = row.cash_fee_sell_is_percent
? `${row.cash_fee_sell || 0}%`
: usePrice(row.cash_fee_sell || 0)
return `خرید: ${buy} | فروش: ${sell}`
} }
</script> </script>
@@ -7,6 +7,19 @@ function formatMoney(value: number | null | undefined) {
return usePrice(value ?? 0, true, '').trim() return usePrice(value ?? 0, true, '').trim()
} }
function formatProductCashFee(value: number | null | undefined, isPercent?: boolean | null) {
const raw = Number(value ?? 0)
if (!raw) {
return '۰'
}
if (isPercent) {
return `${raw}%`
}
return formatMoney(raw)
}
const inventoryColumn: BaseTableColumn = { const inventoryColumn: BaseTableColumn = {
title: 'موجودی', title: 'موجودی',
dataIndex: 'inventory', dataIndex: 'inventory',
@@ -82,18 +95,18 @@ export function getProductColumns(): BaseTableColumn[] {
) )
}, },
{ {
title: 'هزینه نقدی موقع خرید', title: 'هزینه خرید',
dataIndex: 'cash_fee_buy', dataIndex: 'cash_fee_buy',
key: 'cash_fee_buy', key: 'cash_fee_buy',
type: 'Number', type: 'Number',
customRender: ({ record }) => formatMoney(record.cash_fee_buy) customRender: ({ record }) => formatProductCashFee(record.cash_fee_buy, record.cash_fee_buy_is_percent)
}, },
{ {
title: 'هزینه نقدی موقع فروش', title: 'هزینه فروش',
dataIndex: 'cash_fee_sell', dataIndex: 'cash_fee_sell',
key: 'cash_fee_sell', key: 'cash_fee_sell',
type: 'Number', type: 'Number',
customRender: ({ record }) => formatMoney(record.cash_fee_sell) customRender: ({ record }) => formatProductCashFee(record.cash_fee_sell, record.cash_fee_sell_is_percent)
}, },
...(isStoreApp() ? [inventoryColumn] : []), ...(isStoreApp() ? [inventoryColumn] : []),
{ {
+10 -2
View File
@@ -338,6 +338,8 @@ async function edit(record: Product) {
show_in_assets: productData.show_in_assets ?? false, show_in_assets: productData.show_in_assets ?? false,
trade_by_quantity: productData.trade_by_quantity ?? false, trade_by_quantity: productData.trade_by_quantity ?? false,
override_trading_hours: productData.override_trading_hours ?? false, override_trading_hours: productData.override_trading_hours ?? false,
cash_fee_buy_is_percent: productData.cash_fee_buy_is_percent ?? false,
cash_fee_sell_is_percent: productData.cash_fee_sell_is_percent ?? false,
price_offset_percent: productData.price_offset_percent ?? 0, price_offset_percent: productData.price_offset_percent ?? 0,
direct_price: productData.direct_price ?? 0, direct_price: productData.direct_price ?? 0,
auto_open_at: start.isValid() ? start : dayjs('00:00:00', 'HH:mm:ss'), auto_open_at: start.isValid() ? start : dayjs('00:00:00', 'HH:mm:ss'),
@@ -373,8 +375,10 @@ function resetData() {
amount: undefined, amount: undefined,
percent_fee_buy: 0, percent_fee_buy: 0,
cash_fee_buy: undefined, cash_fee_buy: undefined,
cash_fee_buy_is_percent: false,
percent_fee_sell: 0, percent_fee_sell: 0,
cash_fee_sell: undefined, cash_fee_sell: undefined,
cash_fee_sell_is_percent: false,
price_offset_percent: 0, price_offset_percent: 0,
metal_id: 1, metal_id: 1,
direct_price: 0, direct_price: 0,
@@ -451,6 +455,12 @@ async function saveProduct() {
loading.value = false loading.value = false
return return
} }
payload.cash_fee_buy = payload.cash_fee_buy ?? 0
payload.cash_fee_sell = payload.cash_fee_sell ?? 0
payload.cash_fee_buy_is_percent = Boolean(payload.cash_fee_buy_is_percent)
payload.cash_fee_sell_is_percent = Boolean(payload.cash_fee_sell_is_percent)
if (usesMeltedPriceEditor(payload)) { if (usesMeltedPriceEditor(payload)) {
if (isMeltedTradeGroup(payload.group_type)) { if (isMeltedTradeGroup(payload.group_type)) {
payload.amount = 1 payload.amount = 1
@@ -459,8 +469,6 @@ async function saveProduct() {
} }
} }
payload.direct_price = meltedPriceOption.value === 'fixed' ? 1 : 0 payload.direct_price = meltedPriceOption.value === 'fixed' ? 1 : 0
payload.cash_fee_buy = payload.cash_fee_buy ?? 0
payload.cash_fee_sell = payload.cash_fee_sell ?? 0
if (meltedPriceOption.value === 'app') { if (meltedPriceOption.value === 'app') {
payload.reading_method = null payload.reading_method = null