fix pargar bugs
This commit is contained in:
@@ -24,17 +24,40 @@
|
||||
|
||||
<MobileInfoGrid>
|
||||
<MobileDetailRow label="شناسه" :value="row.id" />
|
||||
<MobileDetailRow label="مشتری" :value="row.customer?.name || '-'" />
|
||||
<MobileDetailRow label="مشتری" :value="pargarCustomerLabel(row)" />
|
||||
<MobileDetailRow label="موبایل" :value="row.customer?.mobile || '-'" />
|
||||
<MobileDetailRow label="نوع" :value="row.type || '-'" />
|
||||
<MobileDetailRow label="مقدار" :value="row.amount ?? '-'" />
|
||||
<MobileDetailRow label="شرح" full-width :value="row.desc || '-'" />
|
||||
<MobileDetailRow label="نوع" :value="pargarTypeLabel(row.type)" />
|
||||
<MobileDetailRow label="مقدار" :value="pargarAmountLabel(row)" />
|
||||
<MobileDetailRow label="شرح" full-width :value="pargarDescLabel(row)" />
|
||||
<MobileDetailRow label="وضعیت" :value="pargarStatusLabel(row.sync_status, row.pargar_ref, row.desc)" />
|
||||
<MobileDetailRow v-if="parsedPayload?.accountId" label="کد حساب پرگار" :value="parsedPayload.accountId" />
|
||||
<MobileDetailRow
|
||||
v-if="parsedPayload?.transactions.length"
|
||||
label="تعداد سطر"
|
||||
:value="String(parsedPayload.transactions.length)"
|
||||
/>
|
||||
<MobileDetailRow label="کد پرگار" :value="row.pargar_ref || '-'" />
|
||||
<MobileDetailRow label="زمان" :value="row.created_at ? toJalali(row.created_at) : '-'" />
|
||||
<MobileDetailRow v-if="row.res" label="پاسخ API" full-width :value="row.res" />
|
||||
</MobileInfoGrid>
|
||||
|
||||
<div
|
||||
v-if="parsedPayload?.transactions.length"
|
||||
class="mt-3 space-y-2"
|
||||
>
|
||||
<div class="text-sm font-600 text-gray-700">جزئیات اسناد</div>
|
||||
<div
|
||||
v-for="(tx, idx) in parsedPayload.transactions"
|
||||
:key="idx"
|
||||
class="rounded-lg border border-gray-100 bg-gray-50 p-3 text-xs space-y-1"
|
||||
>
|
||||
<MobileDetailRow label="شرح" full-width :value="tx.desc || tx.docType || '-'" />
|
||||
<MobileDetailRow label="تاریخ" :value="tx.date || '-'" />
|
||||
<MobileDetailRow label="شماره سند" :value="tx.docId || '-'" />
|
||||
<MobileDetailRow label="مبالغ" full-width :value="formatTransactionAmount(tx)" />
|
||||
</div>
|
||||
</div>
|
||||
|
||||
<div
|
||||
v-if="row.sync_log"
|
||||
class="mt-3 rounded-lg bg-red-50 p-3 text-sm text-red-700 whitespace-pre-wrap"
|
||||
@@ -53,6 +76,14 @@ import MobileIconButton from '@/components/mobile/MobileIconButton.vue'
|
||||
import MobileInfoGrid from '@/components/mobile/MobileInfoGrid.vue'
|
||||
import MobileSheetHeader from '@/components/mobile/MobileSheetHeader.vue'
|
||||
import { canRetryPargar, pargarStatusLabel } from '@/pages/menuPages/accounting/utils/pargarStatus'
|
||||
import {
|
||||
formatTransactionAmount,
|
||||
parsePargarPayload,
|
||||
pargarAmountLabel,
|
||||
pargarCustomerLabel,
|
||||
pargarDescLabel,
|
||||
pargarTypeLabel
|
||||
} from '@/pages/menuPages/accounting/utils/pargarDisplay'
|
||||
import { isMobile } from '@core/utils/is'
|
||||
import { toJalali } from '@core/utils/useDataTime'
|
||||
|
||||
@@ -72,7 +103,11 @@ const visibleProxy = computed({
|
||||
set: (value: boolean) => emit('update:visible', value)
|
||||
})
|
||||
|
||||
const sheetTitle = computed(() => props.item?.customer?.name || 'سند پرگار')
|
||||
const sheetTitle = computed(() =>
|
||||
props.item ? pargarCustomerLabel(props.item) : 'سند پرگار'
|
||||
)
|
||||
|
||||
const parsedPayload = computed(() => parsePargarPayload(props.item?.data))
|
||||
|
||||
function canRetry(row: PargarRecord) {
|
||||
return canRetryPargar(row)
|
||||
|
||||
@@ -8,8 +8,8 @@
|
||||
</span>
|
||||
</div>
|
||||
<div class="flex flex-wrap items-center gap-x-3 gap-y-0.5 text-xs text-gray-600">
|
||||
<span>نوع: <span class="font-600 text-gray-900">{{ item.type || '-' }}</span></span>
|
||||
<span>مقدار: <span class="font-600 text-gray-900">{{ item.amount ?? '-' }}</span></span>
|
||||
<span>نوع: <span class="font-600 text-gray-900">{{ pargarTypeLabel(item.type) }}</span></span>
|
||||
<span>مقدار: <span class="font-600 text-gray-900">{{ pargarAmountLabel(item) }}</span></span>
|
||||
</div>
|
||||
<div class="text-xs text-gray-400">{{ createdAtLabel }}</div>
|
||||
</div>
|
||||
@@ -21,6 +21,11 @@ import type { PargarRecord } from '@/api/pargar'
|
||||
import MobileCard from '@/components/mobile/MobileCard.vue'
|
||||
import { toJalali } from '@core/utils/useDataTime'
|
||||
import { pargarStatusLabel } from '@/pages/menuPages/accounting/utils/pargarStatus'
|
||||
import {
|
||||
pargarAmountLabel,
|
||||
pargarCustomerLabel,
|
||||
pargarTypeLabel
|
||||
} from '@/pages/menuPages/accounting/utils/pargarDisplay'
|
||||
|
||||
const props = defineProps<{
|
||||
item: PargarRecord
|
||||
@@ -30,7 +35,7 @@ defineEmits<{
|
||||
(e: 'open', item: PargarRecord): void
|
||||
}>()
|
||||
|
||||
const customerName = computed(() => props.item.customer?.name || '-')
|
||||
const customerName = computed(() => pargarCustomerLabel(props.item))
|
||||
const createdAtLabel = computed(() =>
|
||||
props.item.created_at ? toJalali(props.item.created_at) : '-'
|
||||
)
|
||||
|
||||
@@ -56,6 +56,41 @@
|
||||
<div v-if="selected?.res" class="rounded-lg bg-gray-100 p-3 text-xs font-mono text-gray-700 whitespace-pre-wrap">
|
||||
{{ selected.res }}
|
||||
</div>
|
||||
<div v-if="parsedPayload?.transactions.length" class="space-y-2">
|
||||
<div class="text-sm font-600 text-gray-700">جزئیات اسناد دریافتی از پرگار</div>
|
||||
<div
|
||||
v-for="(tx, idx) in parsedPayload.transactions"
|
||||
:key="idx"
|
||||
class="rounded-lg border border-gray-100 bg-gray-50 p-3 text-xs space-y-1"
|
||||
>
|
||||
<div class="flex justify-between gap-2">
|
||||
<span class="text-gray-500">شرح</span>
|
||||
<span class="text-left">{{ tx.desc || tx.docType || '-' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between gap-2">
|
||||
<span class="text-gray-500">تاریخ</span>
|
||||
<span class="text-left">{{ tx.date || '-' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between gap-2">
|
||||
<span class="text-gray-500">شماره سند</span>
|
||||
<span class="text-left">{{ tx.docId || '-' }}</span>
|
||||
</div>
|
||||
<div class="flex justify-between gap-2">
|
||||
<span class="text-gray-500">مبالغ</span>
|
||||
<span class="text-left">{{ formatTransactionAmount(tx) }}</span>
|
||||
</div>
|
||||
<div v-if="tx.remainGold || tx.remainRial" class="flex justify-between gap-2">
|
||||
<span class="text-gray-500">مانده</span>
|
||||
<span class="text-left">
|
||||
{{ tx.remainGold ? `${tx.remainGold} گرم` : '' }}
|
||||
{{ tx.remainRial ? `${tx.remainRial} ریال` : '' }}
|
||||
</span>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div v-else-if="selected?.data" class="rounded-lg bg-gray-100 p-3 text-xs font-mono text-gray-700 whitespace-pre-wrap overflow-x-auto">
|
||||
{{ selected.data }}
|
||||
</div>
|
||||
<div v-if="selected?.sync_log" class="rounded-lg bg-red-50 p-3 text-red-700 whitespace-pre-wrap">
|
||||
{{ selected.sync_log }}
|
||||
</div>
|
||||
@@ -92,6 +127,14 @@ import BasicModal from '@/components/BasicModal.vue'
|
||||
import PargarRetryModal from '@/components/PargarRetryModal.vue'
|
||||
import PargarMobileCardList from '@/pages/menuPages/accounting/components/PargarMobileCardList.vue'
|
||||
import { canRetryPargar, pargarStatusLabel } from '@/pages/menuPages/accounting/utils/pargarStatus'
|
||||
import {
|
||||
formatTransactionAmount,
|
||||
parsePargarPayload,
|
||||
pargarAmountLabel,
|
||||
pargarCustomerLabel,
|
||||
pargarDescLabel,
|
||||
pargarTypeLabel
|
||||
} from '@/pages/menuPages/accounting/utils/pargarDisplay'
|
||||
import { toJalali } from '@core/utils/useDataTime'
|
||||
|
||||
const [submit, reload] = useBaseTable()
|
||||
@@ -110,10 +153,10 @@ const columns = [
|
||||
sortable: false,
|
||||
customRender: (r: any) => r.index + 1
|
||||
},
|
||||
{ title: 'مشتری', dataIndex: 'customer.name', key: 'customer.name', type: 'Text' },
|
||||
{ title: 'نوع', dataIndex: 'type', key: 'type', type: 'Text' },
|
||||
{ title: 'مقدار', dataIndex: 'amount', key: 'amount', type: 'Number' },
|
||||
{ title: 'شرح', dataIndex: 'desc', key: 'desc', type: 'Text' },
|
||||
{ title: 'مشتری', dataIndex: 'customer.name', key: 'customer.name', type: 'Text', customRender: (r: any) => pargarCustomerLabel(r.record) },
|
||||
{ title: 'نوع', dataIndex: 'type', key: 'type', type: 'Text', customRender: (r: any) => pargarTypeLabel(r.record.type) },
|
||||
{ title: 'مقدار', dataIndex: 'amount', key: 'amount', type: 'Number', customRender: (r: any) => pargarAmountLabel(r.record) },
|
||||
{ title: 'شرح', dataIndex: 'desc', key: 'desc', type: 'Text', customRender: (r: any) => pargarDescLabel(r.record) },
|
||||
{
|
||||
title: 'وضعیت',
|
||||
dataIndex: 'sync_status',
|
||||
@@ -143,23 +186,28 @@ const tblProps = ref({
|
||||
api: (params: TableInput) => getPargarTable(params)
|
||||
})
|
||||
|
||||
/** اطلاعاتی که برای هر سند حسابداری نیاز است (بدون جزئیات پرگارمحور) */
|
||||
/** اطلاعاتی که برای هر سند حسابداری نیاز است */
|
||||
const infoItems = computed(() => {
|
||||
const row = selected.value
|
||||
if (!row) return []
|
||||
const payload = parsePargarPayload(row.data)
|
||||
return [
|
||||
{ label: 'شناسه سند', value: row.id },
|
||||
{ label: 'مشتری', value: row.customer?.name },
|
||||
{ label: 'موبایل', value: row.customer?.mobile },
|
||||
{ label: 'نوع', value: row.type },
|
||||
{ label: 'مقدار', value: row.amount },
|
||||
{ label: 'شرح', value: row.desc },
|
||||
{ label: 'مشتری', value: pargarCustomerLabel(row) },
|
||||
{ label: 'موبایل', value: row.customer?.mobile || '-' },
|
||||
{ label: 'کد حساب پرگار', value: payload?.accountId || row.pargar_ref || '-' },
|
||||
{ label: 'نوع', value: pargarTypeLabel(row.type) },
|
||||
{ label: 'مقدار', value: pargarAmountLabel(row) },
|
||||
{ label: 'شرح', value: pargarDescLabel(row) },
|
||||
{ label: 'تعداد سطر سند', value: payload?.transactions.length ? String(payload.transactions.length) : '-' },
|
||||
{ label: 'زمان ثبت', value: row.created_at ? toJalali(row.created_at) : '-' },
|
||||
{ label: 'وضعیت', value: pargarStatusLabel(row.sync_status, row.pargar_ref, row.desc) },
|
||||
{ label: 'کد پرگار', value: row.pargar_ref || 'ثبت نشده' }
|
||||
]
|
||||
})
|
||||
|
||||
const parsedPayload = computed(() => parsePargarPayload(selected.value?.data))
|
||||
|
||||
function openInfo(record: PargarRecord) {
|
||||
selected.value = record
|
||||
infoVisible.value = true
|
||||
|
||||
@@ -0,0 +1,153 @@
|
||||
import type { PargarRecord } from '@/api/pargar'
|
||||
|
||||
export interface PargarTransactionRow {
|
||||
docId?: string
|
||||
date?: string
|
||||
docType?: string
|
||||
desc?: string
|
||||
by?: string
|
||||
bedGold?: number | string
|
||||
besGold?: number | string
|
||||
bedRial?: number | string
|
||||
besRial?: number | string
|
||||
remainGold?: number | string
|
||||
remainRial?: number | string
|
||||
}
|
||||
|
||||
export interface PargarParsedPayload {
|
||||
accountId?: string
|
||||
accountName?: string
|
||||
transactions: PargarTransactionRow[]
|
||||
}
|
||||
|
||||
const TYPE_LABELS: Record<string, string> = {
|
||||
document: 'سند ورودی از پرگار',
|
||||
order: 'سفارش',
|
||||
mande: 'مانده حساب',
|
||||
customer: 'ثبت مشتری',
|
||||
wallet_cash: 'کیف ریالی',
|
||||
wallet_gold: 'کیف طلا'
|
||||
}
|
||||
|
||||
function parseNum(value: unknown): number {
|
||||
if (value == null || value === '') return 0
|
||||
const n = Number(String(value).replace('/', '.'))
|
||||
return Number.isFinite(n) ? n : 0
|
||||
}
|
||||
|
||||
export function pargarTypeLabel(type?: string | null): string {
|
||||
if (!type) return '-'
|
||||
return TYPE_LABELS[type] ?? type
|
||||
}
|
||||
|
||||
export function parsePargarPayload(data?: string | null): PargarParsedPayload | null {
|
||||
if (!data?.trim()) return null
|
||||
try {
|
||||
const raw = JSON.parse(data) as Record<string, unknown>
|
||||
let transactions: PargarTransactionRow[] = []
|
||||
if (Array.isArray(raw.transactions)) {
|
||||
transactions = raw.transactions as PargarTransactionRow[]
|
||||
} else if (raw.transaction && typeof raw.transaction === 'object') {
|
||||
transactions = [raw.transaction as PargarTransactionRow]
|
||||
}
|
||||
|
||||
return {
|
||||
accountId: raw.accountId != null ? String(raw.accountId) : undefined,
|
||||
accountName: raw.accountName != null ? String(raw.accountName) : undefined,
|
||||
transactions
|
||||
}
|
||||
} catch {
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
export function pargarCustomerLabel(record: PargarRecord): string {
|
||||
if (record.customer?.name?.trim()) return record.customer.name.trim()
|
||||
const payload = parsePargarPayload(record.data)
|
||||
if (payload?.accountName?.trim()) return payload.accountName.trim()
|
||||
if (record.pargar_ref) return `کد پرگار ${record.pargar_ref}`
|
||||
return '-'
|
||||
}
|
||||
|
||||
export function pargarAmountLabel(record: PargarRecord): string {
|
||||
if (record.amount != null && record.amount !== 0) {
|
||||
return formatPargarAmount(record.amount, record)
|
||||
}
|
||||
|
||||
const payload = parsePargarPayload(record.data)
|
||||
if (!payload?.transactions.length) return '-'
|
||||
|
||||
let maxGold = 0
|
||||
let maxRial = 0
|
||||
for (const tx of payload.transactions) {
|
||||
maxGold = Math.max(maxGold, Math.abs(parseNum(tx.bedGold)), Math.abs(parseNum(tx.besGold)))
|
||||
maxRial = Math.max(maxRial, Math.abs(parseNum(tx.bedRial)), Math.abs(parseNum(tx.besRial)))
|
||||
}
|
||||
|
||||
if (maxGold >= 0.01) return `${maxGold} گرم`
|
||||
if (maxRial >= 1) return `${maxRial.toLocaleString('fa-IR')} ریال`
|
||||
return '-'
|
||||
}
|
||||
|
||||
function formatPargarAmount(amount: number, record: PargarRecord): string {
|
||||
const payload = parsePargarPayload(record.data)
|
||||
let summaryUnit: string | undefined
|
||||
if (payload && '_summary' in (JSON.parse(record.data || '{}') as Record<string, unknown>)) {
|
||||
const raw = JSON.parse(record.data || '{}') as { _summary?: { amount_unit?: string } }
|
||||
summaryUnit = raw._summary?.amount_unit
|
||||
}
|
||||
|
||||
if (summaryUnit === 'rial' || record.type === 'wallet_cash') {
|
||||
return `${amount.toLocaleString('fa-IR')} ریال`
|
||||
}
|
||||
if (summaryUnit === 'gold' || record.type === 'wallet_gold' || record.type === 'mande') {
|
||||
return `${amount} گرم`
|
||||
}
|
||||
return String(amount)
|
||||
}
|
||||
|
||||
export function pargarDescLabel(record: PargarRecord): string {
|
||||
const desc = record.desc?.trim()
|
||||
if (desc && desc !== 'دریافت اسناد از پرگار') return desc
|
||||
|
||||
try {
|
||||
const raw = record.data ? JSON.parse(record.data) : null
|
||||
if (raw?.wallet_applied === false && raw?.skip_reason === 'echo_outbound') {
|
||||
return 'سند پرگار — از پنل ارسال شده (بدون اعمال مجدد)'
|
||||
}
|
||||
if (raw?.wallet_applied === true) {
|
||||
return desc || 'اعمالشده روی کیف'
|
||||
}
|
||||
} catch {
|
||||
// ignore
|
||||
}
|
||||
|
||||
const payload = parsePargarPayload(record.data)
|
||||
if (!payload?.transactions.length) return desc || '-'
|
||||
|
||||
const lines = payload.transactions
|
||||
.map((tx) => tx.desc?.trim() || tx.docType?.trim() || '')
|
||||
.filter(Boolean)
|
||||
|
||||
if (lines.length) {
|
||||
const head = lines.slice(0, 2).join(' | ')
|
||||
return lines.length > 2 ? `${head} (+${lines.length - 2} سند دیگر)` : head
|
||||
}
|
||||
|
||||
return desc || '-'
|
||||
}
|
||||
|
||||
export function formatTransactionAmount(tx: PargarTransactionRow): string {
|
||||
const parts: string[] = []
|
||||
const bedGold = parseNum(tx.bedGold)
|
||||
const besGold = parseNum(tx.besGold)
|
||||
const bedRial = parseNum(tx.bedRial)
|
||||
const besRial = parseNum(tx.besRial)
|
||||
|
||||
if (bedGold >= 0.01) parts.push(`بدهکار طلا: ${bedGold}`)
|
||||
if (besGold >= 0.01) parts.push(`بستانکار طلا: ${besGold}`)
|
||||
if (bedRial >= 1) parts.push(`بدهکار ریال: ${bedRial.toLocaleString('fa-IR')}`)
|
||||
if (besRial >= 1) parts.push(`بستانکار ریال: ${besRial.toLocaleString('fa-IR')}`)
|
||||
|
||||
return parts.length ? parts.join(' — ') : '-'
|
||||
}
|
||||
@@ -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|main_wallet_products|require_zero_main_gold_before_other_buy)/.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)/.test(
|
||||
k
|
||||
)
|
||||
},
|
||||
|
||||
@@ -864,7 +864,6 @@ 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',
|
||||
@@ -895,6 +894,7 @@ export const SETTING_EDITABLE_KEYS = new Set([
|
||||
'name_fa',
|
||||
'auto_active_customer', 'balance_report_exclude_customer_id',
|
||||
'buy_fee', 'charge_notif', 'close_price',
|
||||
'require_zero_main_gold_before_other_buy',
|
||||
'sms_notif_order_admin', 'sms_notif_order_customer',
|
||||
'sms_notif_withdraw_admin', 'sms_notif_withdraw_otp', 'sms_notif_login_otp',
|
||||
'sms_notif_gateway_charge_admin', 'sms_notif_register_customer', 'sms_notif_register_admin',
|
||||
|
||||
Reference in New Issue
Block a user