fix some bugs from accounting 2
This commit is contained in:
@@ -239,6 +239,13 @@ function inventoryCards() {
|
||||
return [...(summary.value.inventory_cards ?? []), ...(summary.value.count_products ?? [])]
|
||||
}
|
||||
|
||||
function isCountChargeTarget(target: ChargeTarget) {
|
||||
if (target.kind === 'money') return false
|
||||
if (target.allows_decimal === false) return true
|
||||
if (target.unit === 'عدد') return true
|
||||
return target.trade_by_quantity === false && !isMeltedTradeGroup(target.group_type)
|
||||
}
|
||||
|
||||
function balanceForTarget(target: ChargeTarget) {
|
||||
if (!summary.value) return '—'
|
||||
if (target.kind === 'money') {
|
||||
@@ -246,18 +253,15 @@ function balanceForTarget(target: ChargeTarget) {
|
||||
}
|
||||
|
||||
const card = inventoryCards().find((row) => Number(row.product_id) === Number(target.product_id))
|
||||
if (card) return formatCard(card)
|
||||
|
||||
// تعدادی: همیشه «عدد» — نه گرم (وزن هر قطعه در فیلد unit محصول است)
|
||||
const isCount =
|
||||
target.allows_decimal === false ||
|
||||
target.unit === 'عدد' ||
|
||||
(target.trade_by_quantity === false && !isMeltedTradeGroup(target.group_type))
|
||||
|
||||
if (isCount) {
|
||||
return '۰ عدد'
|
||||
// اولویت با نوع شارژ (تعدادی) — حتی اگر کارت دارایی اشتباه «گرم» برچسب زده باشد
|
||||
if (isCountChargeTarget(target)) {
|
||||
const qty = Number(card?.quantity ?? 0)
|
||||
return `${qty.toLocaleString('fa-IR', { maximumFractionDigits: 0 })} عدد`
|
||||
}
|
||||
|
||||
if (card) return formatCard(card)
|
||||
|
||||
return formatMetalDisplayValue(0, target.metal_id ?? 1)
|
||||
}
|
||||
|
||||
|
||||
@@ -37,11 +37,12 @@
|
||||
v-model:value="modelValue.amountAbs"
|
||||
:addon-before="resolvedUnit"
|
||||
:type="resolvedInputType"
|
||||
:step="integerOnly ? 1 : undefined"
|
||||
:step="requiresInteger ? 1 : undefined"
|
||||
:place-holder="amountPlaceholder"
|
||||
@onchange="onAmountChange"
|
||||
/>
|
||||
<div v-if="isMoney && Number(modelValue.amountAbs) > 10" class="wallet-charge-form__hint">
|
||||
معادل {{ usePrice(Number(modelValue.amountAbs) / 10, true, 'تومان') }}
|
||||
<div v-if="isMoney && Number(normalizedAmount) > 10" class="wallet-charge-form__hint">
|
||||
معادل {{ usePrice(Number(normalizedAmount) / 10, true, 'تومان') }}
|
||||
</div>
|
||||
</a-form-item>
|
||||
|
||||
@@ -84,7 +85,8 @@ const resolvedUnit = computed(
|
||||
() => props.unitLabel ?? (props.variant === 'money' ? 'ریال' : 'گرم'),
|
||||
)
|
||||
const isMoney = computed(() => props.isMoney ?? props.variant === 'money')
|
||||
const integerOnly = computed(() => props.integerOnly === true)
|
||||
/** نقدی و تعدادی — بدون اعشار */
|
||||
const requiresInteger = computed(() => isMoney.value || props.integerOnly === true)
|
||||
const resolvedInputType = computed(() => (isMoney.value ? 'price' : 'number'))
|
||||
const isDischarge = computed(() => props.modelValue.direction === 'discharge')
|
||||
|
||||
@@ -114,7 +116,7 @@ const noteLabel = computed(() => (isDischarge.value ? 'علت دشارژ' : 'ع
|
||||
|
||||
const amountPlaceholder = computed(() => {
|
||||
if (isMoney.value) return 'مثلاً ۱۰۰٬۰۰۰'
|
||||
if (integerOnly.value) return 'مثلاً ۱'
|
||||
if (requiresInteger.value) return 'مثلاً ۱'
|
||||
return 'مثلاً ۰.۵'
|
||||
})
|
||||
|
||||
@@ -122,16 +124,64 @@ const notePlaceholder = computed(() =>
|
||||
isDischarge.value ? 'دلیل کسر موجودی' : 'دلیل افزایش موجودی',
|
||||
)
|
||||
|
||||
/** ارقام فارسی/عربی → لاتین؛ جداکننده هزار حذف؛ ممیز یکسان */
|
||||
function normalizeAmountRaw(raw: string | number | undefined | null): string {
|
||||
return String(raw ?? '')
|
||||
.trim()
|
||||
.replace(/[۰-۹]/g, (d) => String('۰۱۲۳۴۵۶۷۸۹'.indexOf(d)))
|
||||
.replace(/[٠-٩]/g, (d) => String('٠١٢٣٤٥٦٧٨٩'.indexOf(d)))
|
||||
.replace(/[٬,\s]/g, '')
|
||||
.replace(/٫/g, '.')
|
||||
}
|
||||
|
||||
function hasDecimalSeparator(raw: string): boolean {
|
||||
// بعد از حذف جداکننده هزار، نقطه = اعشار
|
||||
return raw.includes('.')
|
||||
}
|
||||
|
||||
function parseAmount(raw: string | number | undefined | null): number {
|
||||
const normalized = normalizeAmountRaw(raw)
|
||||
if (!normalized) return 0
|
||||
const num = Number(normalized)
|
||||
return Number.isFinite(num) ? Math.abs(num) : NaN
|
||||
}
|
||||
|
||||
const normalizedAmount = computed(() => parseAmount(props.modelValue.amountAbs))
|
||||
|
||||
function onAmountChange(raw: string | number) {
|
||||
if (!requiresInteger.value) return
|
||||
const text = normalizeAmountRaw(raw)
|
||||
if (!hasDecimalSeparator(text)) return
|
||||
// قطع اعشار — فقط بخش صحیح بماند
|
||||
const whole = text.split('.')[0] ?? ''
|
||||
props.modelValue.amountAbs = whole === '' ? undefined : whole
|
||||
}
|
||||
|
||||
const amountRules = computed(() => [
|
||||
...inputRules('مقدار'),
|
||||
{
|
||||
validator: (_rule: unknown, value: string | number | undefined) => {
|
||||
const num = Math.abs(Number(value) || 0)
|
||||
if (!num) {
|
||||
const raw = normalizeAmountRaw(value)
|
||||
if (!raw) {
|
||||
return Promise.reject('مقدار باید بیشتر از صفر باشد')
|
||||
}
|
||||
if (integerOnly.value && Math.abs(num - Math.round(num)) > 0.000001) {
|
||||
return Promise.reject('برای محصول تعدادی فقط عدد صحیح مجاز است')
|
||||
if (requiresInteger.value && hasDecimalSeparator(raw)) {
|
||||
return Promise.reject(
|
||||
isMoney.value
|
||||
? 'برای مبلغ ریالی فقط عدد صحیح مجاز است'
|
||||
: 'برای محصول تعدادی فقط عدد صحیح مجاز است',
|
||||
)
|
||||
}
|
||||
const num = parseAmount(raw)
|
||||
if (!Number.isFinite(num) || !num) {
|
||||
return Promise.reject('مقدار باید بیشتر از صفر باشد')
|
||||
}
|
||||
if (requiresInteger.value && Math.abs(num - Math.round(num)) > 0.000001) {
|
||||
return Promise.reject(
|
||||
isMoney.value
|
||||
? 'برای مبلغ ریالی فقط عدد صحیح مجاز است'
|
||||
: 'برای محصول تعدادی فقط عدد صحیح مجاز است',
|
||||
)
|
||||
}
|
||||
return Promise.resolve()
|
||||
},
|
||||
|
||||
@@ -113,10 +113,11 @@ const targetOptions = computed(() =>
|
||||
})),
|
||||
)
|
||||
|
||||
/** تعدادی: فقط عدد صحیح — از allows_decimal سرور یا واحد «عدد» */
|
||||
/** تعدادی یا نقدی: فقط عدد صحیح */
|
||||
const isIntegerOnlyTarget = computed(() => {
|
||||
const target = props.selectedTarget
|
||||
if (!target || target.kind === 'money') return false
|
||||
if (!target) return false
|
||||
if (target.kind === 'money') return true
|
||||
if (typeof target.allows_decimal === 'boolean') return !target.allows_decimal
|
||||
if (target.unit === 'عدد') return true
|
||||
// fallback قبل از آپدیت سرور: تعدادی ≠ آبشده/کاتد
|
||||
|
||||
Reference in New Issue
Block a user