added bannig when amount is under 0

This commit is contained in:
2026-07-20 21:28:35 +03:30
parent 2b58db3a91
commit 5ea97e873a
5 changed files with 319 additions and 96 deletions
@@ -102,7 +102,7 @@ export const EDITABLE_SETTING_GROUPS: SettingGroupDef[] = [
id: 'features',
title: 'قابلیت‌های سیستم',
icon: 'vuesax-linear:setting-2',
match: (k) => /^(product_|main_wallet_products|profit_gold)/.test(k)
match: (k) => /^(product_|main_wallet_products|require_zero_main_gold_before_other_buy|profit_gold)/.test(k)
},
{
id: 'misc',
@@ -119,7 +119,7 @@ export const SYSTEM_SETTING_GROUPS: SettingGroupDef[] = [
title: 'عمومی و برند',
icon: 'vuesax-linear:home-2',
match: (k) =>
/^(name_fa|name_en|app_url|admin_url|apk_download_link|permision__enabled|bace_url|server_url|logo_|title_pwa|title_fav|metal_type|main_metal|unit$|open_register|auto_active_customer|store_status|key$|is_store|group_sms|customer_direct_sms|has_page_earn_money|sms_panel)/.test(
/^(name_fa|name_en|app_url|admin_url|apk_download_link|permision__enabled|bace_url|server_url|logo_|title_pwa|title_fav|metal_type|main_metal|unit$|open_register|auto_active_customer|store_status|key$|is_store|group_sms|customer_direct_sms|has_page_earn_money|sms_panel|main_wallet_products|require_zero_main_gold_before_other_buy)/.test(
k
)
},
@@ -231,6 +231,7 @@ const KEY_TYPE_FALLBACK: Record<string, SettingFieldType> = {
text_about: 'longtext',
fee_service_charge_percentage: 'number',
fee_deduct_from_gold: 'switch',
require_zero_main_gold_before_other_buy: 'switch',
fee_single: 'price',
buy_fee: 'price',
sell_fee: 'price',
@@ -550,6 +551,8 @@ const KEY_HELP_FALLBACK: Record<string, string> = {
'درصد کارمزد هر معامله از مبلغ سفارش (اعشاری؛ مثلاً ۰٫۰۰۵ یعنی نیم در هزار).',
fee_deduct_from_gold:
'این کلید دیگر روی محاسبه اثری ندارد. مبنای کارمزد اکنون فیلدی است که مشتری وارد می‌کند: اگر «مبلغ ریالی» را وارد کند (مثلاً دقیقاً ۱۰۰ میلیون ریال) همان مبلغ معامله می‌شود و کارمزد از طلا کسر می‌شود؛ اگر «وزن» را وارد کند (مثلاً دقیقاً ۲ گرم) همان وزن معامله می‌شود و کارمزد از ریال کسر می‌شود. این قانون برای خرید و فروش یکسان است.',
require_zero_main_gold_before_other_buy:
'روشن: اگر مانده طلای کیف اصلی صفر یا زیر صفر باشد (بدهی)، مشتری ابتدا باید آبشده/مانده کیف اصلی را صفر کند و بعد می‌تواند محصول دیگر بخرد. خاموش: بدون این محدودیت. معامله خودِ محصولات کیف اصلی همیشه مجاز است.',
fee_free:
'تعداد اولین سفارش‌های هر کاربر که از کارمزد معاف می‌شوند. صفر یعنی غیرفعال.',
min_withdraw:
@@ -778,6 +781,7 @@ export const KEY_LABEL_FALLBACK: Record<string, string> = {
sell_fee: 'کسر قیمت فروش',
fee_service_charge_percentage: 'درصد کارمزد معامله',
fee_deduct_from_gold: 'اعمال مبلغ دقیق در معامله مشتری',
require_zero_main_gold_before_other_buy: 'الزام صفر بودن کیف اصلی قبل از خرید محصول دیگر',
fee_free: 'معافیت کارمزد سفارش اول',
min_withdraw: 'حداقل مبلغ برداشت',
min_deposit: 'حداقل مبلغ واریز کیف پول',
@@ -860,6 +864,7 @@ export const SETTING_LOCKED_KEYS = new Set([
'sms_panel',
'logo_login', 'logo_register', 'title_pwa', 'title_fav',
'main_product', 'main_wallet_products', 'metal_type', 'main_metal',
'require_zero_main_gold_before_other_buy',
'montify_name',
'montzar_base_url', 'montzar_closed',
'montzar_diff', 'montzar_last_product_log', 'montzar_live_price', 'montzar_mazaneh',
+76 -56
View File
@@ -293,73 +293,88 @@ async function setProductIndexImage(record: Record<string, any>, productId?: num
}
async function edit(record: Product) {
await loadCategorySelectItems()
addUserVisible.value = true
submitError.value = ''
editId = record.id
let productData = cloneDeep(record) as Record<string, any>
addUserVisible.value = true
loading.value = true
try {
const detail = unwrapApiRecord(await getCustomerById(record.id))
if (detail) productData = { ...productData, ...detail }
} catch {
/* use table row data */
}
let productData = cloneDeep(record) as Record<string, any>
methodOption.value = productData.app_price
? '3'
: (productData.reading_method ? '2' : '1')
meltedPriceOption.value = resolveMeltedPriceSource(productData)
if (usesMeltedPriceEditor(productData)) {
methodOption.value = '1'
if (
!isMeltedTradeGroup(productData.group_type)
&& !productData.reading_method
&& Number(productData.direct_price) !== 1
&& Number(productData.price) > 0
) {
meltedPriceOption.value = 'fixed'
const [, detailResult] = await Promise.all([
loadCategorySelectItems(),
getCustomerById(record.id)
.then((res) => unwrapApiRecord(res))
.catch(() => null),
refreshLivePrices(),
])
if (detailResult) {
productData = { ...productData, ...detailResult }
}
methodOption.value = productData.app_price
? '3'
: (productData.reading_method ? '2' : '1')
meltedPriceOption.value = resolveMeltedPriceSource(productData)
if (usesMeltedPriceEditor(productData)) {
methodOption.value = '1'
if (
!isMeltedTradeGroup(productData.group_type)
&& !productData.reading_method
&& Number(productData.direct_price) !== 1
&& Number(productData.price) > 0
) {
meltedPriceOption.value = 'fixed'
}
}
weightOption.value = Number(productData.amount) > 0 ? '1' : '2'
if (weightOption.value === '2' && !isMeltedTradeGroup(productData.group_type)) {
productData.unit = undefined
}
const start = productData.auto_open_at
? dayjs(productData.auto_open_at, 'HH:mm:ss')
: dayjs('00:00:00', 'HH:mm:ss')
const close = productData.auto_close_at
? dayjs(productData.auto_close_at, 'HH:mm:ss')
: dayjs('00:00:00', 'HH:mm:ss')
form.value = normalizeProductOrderLimitForm({
...productData,
show_in_assets: productData.show_in_assets ?? false,
trade_by_quantity: productData.trade_by_quantity ?? false,
app_price: Boolean(productData.app_price),
override_trading_hours: productData.override_trading_hours ?? false,
has_physical_delivery: productData.has_physical_delivery ?? false,
min_physical_delivery_quantity:
productData.min_physical_delivery_quantity ??
(productData as { min_physical_delivery_grams?: number | null }).min_physical_delivery_grams ??
undefined,
cash_fee_buy: parseCashFeeValue(productData.cash_fee_buy),
cash_fee_sell: parseCashFeeValue(productData.cash_fee_sell),
cash_fee_buy_is_percent: normalizeCashFeeFlags(productData.cash_fee_buy_is_percent),
cash_fee_sell_is_percent: normalizeCashFeeFlags(productData.cash_fee_sell_is_percent),
price_offset_percent: productData.price_offset_percent ?? 0,
direct_price: productData.direct_price ?? 0,
auto_open_at: start.isValid() ? start : dayjs('00:00:00', 'HH:mm:ss'),
auto_close_at: close.isValid() ? close : dayjs('00:00:00', 'HH:mm:ss')
})
await setProductIndexImage(productData, record.id)
} catch (err) {
console.error(err)
message.error('خطا در دریافت اطلاعات محصول')
} finally {
loading.value = false
}
weightOption.value = Number(productData.amount) > 0 ? '1' : '2'
if (weightOption.value === '2' && !isMeltedTradeGroup(productData.group_type)) {
productData.unit = undefined
}
const start = productData.auto_open_at
? dayjs(productData.auto_open_at, 'HH:mm:ss')
: dayjs('00:00:00', 'HH:mm:ss')
const close = productData.auto_close_at
? dayjs(productData.auto_close_at, 'HH:mm:ss')
: dayjs('00:00:00', 'HH:mm:ss')
form.value = normalizeProductOrderLimitForm({
...productData,
show_in_assets: productData.show_in_assets ?? false,
trade_by_quantity: productData.trade_by_quantity ?? false,
app_price: Boolean(productData.app_price),
override_trading_hours: productData.override_trading_hours ?? false,
has_physical_delivery: productData.has_physical_delivery ?? false,
min_physical_delivery_quantity:
productData.min_physical_delivery_quantity ??
(productData as { min_physical_delivery_grams?: number | null }).min_physical_delivery_grams ??
undefined,
cash_fee_buy: parseCashFeeValue(productData.cash_fee_buy),
cash_fee_sell: parseCashFeeValue(productData.cash_fee_sell),
cash_fee_buy_is_percent: normalizeCashFeeFlags(productData.cash_fee_buy_is_percent),
cash_fee_sell_is_percent: normalizeCashFeeFlags(productData.cash_fee_sell_is_percent),
price_offset_percent: productData.price_offset_percent ?? 0,
direct_price: productData.direct_price ?? 0,
auto_open_at: start.isValid() ? start : dayjs('00:00:00', 'HH:mm:ss'),
auto_close_at: close.isValid() ? close : dayjs('00:00:00', 'HH:mm:ss')
})
await setProductIndexImage(productData, record.id)
}
function closeProductModal() {
addUserVisible.value = false
editId = undefined
submitError.value = ''
loading.value = false
}
async function add() {
@@ -367,7 +382,12 @@ async function add() {
submitError.value = ''
addUserVisible.value = true
resetData()
await loadCategorySelectItems()
loading.value = true
try {
await Promise.all([loadCategorySelectItems(), refreshLivePrices()])
} finally {
loading.value = false
}
}
function resetData() {