diff --git a/components.d.ts b/components.d.ts index a530ff2..d0d152a 100644 --- a/components.d.ts +++ b/components.d.ts @@ -92,6 +92,7 @@ declare module '@vue/runtime-core' { PargarRetryModal: typeof import('./src/components/PargarRetryModal.vue')['default'] RouterLink: typeof import('vue-router')['RouterLink'] RouterView: typeof import('vue-router')['RouterView'] + ShayeganChargeAlertHost: typeof import('./src/components/ShayeganChargeAlertHost.vue')['default'] ShayeganCustomerRegisterModal: typeof import('./src/components/ShayeganCustomerRegisterModal.vue')['default'] SmsCreditWidget: typeof import('./src/components/SmsCreditWidget.vue')['default'] SmsNegativeBalanceHost: typeof import('./src/components/SmsNegativeBalanceHost.vue')['default'] diff --git a/src/App.vue b/src/App.vue index 8595286..9c24056 100644 --- a/src/App.vue +++ b/src/App.vue @@ -4,6 +4,7 @@ + @@ -15,6 +16,7 @@ import { initDarkmode } from '@core/stores/darkmode' import CustomerImportProgress from '@/components/CustomerImportProgress.vue' import TahesabDocSyncProgress from '@/components/TahesabDocSyncProgress.vue' import GroupSmsSendProgress from '@/components/GroupSmsSendProgress.vue' +import ShayeganChargeAlertHost from '@/components/ShayeganChargeAlertHost.vue' import { useUserStore } from '@/store/userStore' import { useTahesabDocSyncStore } from '@/store/tahesabDocSyncStore' import { bootstrapAdminChat, useAdminChatService } from '@/utils/adminChat' diff --git a/src/api/shayegan.ts b/src/api/shayegan.ts index 71e369a..da29d4a 100644 --- a/src/api/shayegan.ts +++ b/src/api/shayegan.ts @@ -4,6 +4,14 @@ import type { TableInput, TableOutput } from '@core/type/baseTable' export interface ShayeganRecord { id?: number | null customer_id?: number | null + customer?: { + id?: number + name?: string + fname?: string + lname?: string + mobile?: string + moshtari_code?: string + } | null order_id?: number | null withdraw_id?: number | null amount?: number | null @@ -42,3 +50,59 @@ export const registerCustomerInShayegan = async (customerId: number) => await useAxios.post<{ ok: boolean; message: string; moshtari_code?: string }>( `/admin/customer/${customerId}/shayegan/register` ) + +export interface ShayeganInboundChargeRecord { + id: number + customer_id?: number | null + customer_tafsil?: string | null + shayegan_number?: string | null + amount: number + description?: string | null + source?: string + status: 'pending' | 'approved' | 'rejected' + approved_at?: string | null + rejected_at?: string | null + reject_reason?: string | null + customer?: { + id: number + name?: string + fname?: string + lname?: string + mobile?: string + n_code?: string + moshtari_code?: string + } | null + approver?: { + id: number + name?: string + } | null + created_at?: string | null +} + +export const getPendingShayeganCharges = async () => + await useAxios.get<{ ok: boolean; charges: ShayeganInboundChargeRecord[] }>( + '/admin/shayegan/charges/pending' + ) + +export const getShayeganChargesTable = async (params: TableInput & { status?: string }) => + await useAxios.post>( + '/admin/shayegan/charges/table', + params + ) + +export const approveShayeganCharge = async (id: number | string) => + await useAxios.post<{ ok: boolean; message: string; charge?: ShayeganInboundChargeRecord }>( + `/admin/shayegan/charges/${id}/approve` + ) + +export const rejectShayeganCharge = async (id: number | string, reason?: string) => + await useAxios.post<{ ok: boolean; message: string; charge?: ShayeganInboundChargeRecord }>( + `/admin/shayegan/charges/${id}/reject`, + { reason } + ) + +export const syncShayeganCharges = async () => + await useAxios.post<{ ok: boolean; message: string; new_count?: number }>( + '/admin/shayegan/charges/sync' + ) + diff --git a/src/components/ShayeganChargeAlertHost.vue b/src/components/ShayeganChargeAlertHost.vue new file mode 100644 index 0000000..f4e6c33 --- /dev/null +++ b/src/components/ShayeganChargeAlertHost.vue @@ -0,0 +1,243 @@ + + + + + + + + + + + + واریزی جدید از سیستم حسابداری شایگان + + + سند شایگان: {{ charge.shayegan_number || '-' }} · تفصیلی: {{ charge.customer_tafsil || charge.customer?.moshtari_code || '-' }} + + + + + ✕ + + + + + حساب شخص {{ charge.customer?.name || 'نامشخص' }} از طریق پنل حسابداری مقدار {{ formatPrice(charge.amount) }} ریال شارژ شد + + + + + {{ formatTime(charge.created_at) }} + + + + تأیید و شارژ کیف پول + + + رد + + + لیست کامل + + + + + + + + + + + + diff --git a/src/pages/menuPages/accounting/components/ShayeganChargesTab.vue b/src/pages/menuPages/accounting/components/ShayeganChargesTab.vue new file mode 100644 index 0000000..99ac230 --- /dev/null +++ b/src/pages/menuPages/accounting/components/ShayeganChargesTab.vue @@ -0,0 +1,346 @@ + + + + + + + همه وضعیتها + در انتظار تایید + تایید شده + رد شده + + + + استعلام از شایگان + + + + بروزرسانی + + + + + + + + + + + {{ customerLabel(record) }} + {{ record.customer.mobile }} + + تفصیلی: {{ record.customer_tafsil || record.customer?.moshtari_code }} + + + + + + {{ statusLabel(record.status) }} + + + + + + تأیید و شارژ کیف پول در بورس مس + + تأیید واریزی + + + + رد درخواست + + رد + + + + + + واریز شد + + توسط {{ record.approver.name }} + + + + رد شده + + {{ record.reject_reason }} + + + + + + + + + + + + diff --git a/src/pages/menuPages/accounting/components/shayeganTable.vue b/src/pages/menuPages/accounting/components/shayeganTable.vue index e1e298f..81ea9e9 100644 --- a/src/pages/menuPages/accounting/components/shayeganTable.vue +++ b/src/pages/menuPages/accounting/components/shayeganTable.vue @@ -73,6 +73,13 @@ const healthMessage = ref('') const columns = [ { title: 'شناسه', dataIndex: 'id', key: 'id', width: 80, type: 'Number', filterable: false, sortable: false }, + { + title: 'مشتری', + dataIndex: 'customer.name', + key: 'customer.name', + type: 'Text', + customRender: (r: any) => customerLabel(r.record) + }, { title: 'نوع', dataIndex: 'type', @@ -160,6 +167,15 @@ const tblProps = { } } +function customerLabel(record?: any) { + if (record?.customer?.name?.trim()) return record.customer.name.trim() + if (record?.customer?.fname || record?.customer?.lname) { + const fullName = `${record?.customer?.fname || ''} ${record?.customer?.lname || ''}`.trim() + if (fullName) return fullName + } + return '-' +} + function typeLabel(type?: string | null) { if (!type) return '-' return TYPE_LABELS[type] ?? type diff --git a/src/pages/menuPages/accounting/index.vue b/src/pages/menuPages/accounting/index.vue index d3a6a79..18b2546 100644 --- a/src/pages/menuPages/accounting/index.vue +++ b/src/pages/menuPages/accounting/index.vue @@ -18,6 +18,7 @@ + @@ -30,6 +31,7 @@ + (false) const submitError = ref('') -const activeTab = ref<'reports' | 'tahesab' | 'customer-sync' | 'tahesab-wallet-sync' | 'zarin' | 'zarin-customer-sync' | 'zarin-wallet-sync' | 'pargar' | 'pargar-customer-sync' | 'pargar-wallet-sync' | 'shayegan'>('reports') +const activeTab = ref<'reports' | 'tahesab' | 'customer-sync' | 'tahesab-wallet-sync' | 'zarin' | 'zarin-customer-sync' | 'zarin-wallet-sync' | 'pargar' | 'pargar-customer-sync' | 'pargar-wallet-sync' | 'shayegan' | 'shayegan-charges'>((route.query.tab as any) || 'reports') const tahesabEnabled = tahesabEnabledSetting const zarinEnabled = zarinEnabledSetting const pargarEnabled = pargarEnabledSetting const shayeganEnabled = shayeganEnabledSetting +watch( + () => route.query.tab, + (tab) => { + if (tab && typeof tab === 'string') { + activeTab.value = tab as any + } + } +) + //define store const store = useStaticApiListsStore()