Merge branch 'release/test' of http://8.163.30.128:10082/html/admin-web into dev
This commit is contained in:
@@ -114,6 +114,21 @@ describe('FinanceCustomerArapView G2 operations', () => {
|
||||
expect(editFinanceFeeSource).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('treats inbound and container fee types as Firstleg sources when sourceSystem is missing', async () => {
|
||||
const legacyFirstleg = { ...feeSummary, sourceSystem: '', sourceType: 'CONTAINER_FEE', reviewStatus: 'APPROVED' as const }
|
||||
vi.mocked(listFinanceFeeSources).mockResolvedValue({ records: [legacyFirstleg], total: 1, pages: 1 })
|
||||
const wrapper = await mountView(['platform:finance:customer-arap:list', 'platform:finance:fee-source:edit'])
|
||||
await loadRows(wrapper)
|
||||
|
||||
const buttonLabels = wrapper.findAll('button').map((button) => button.text())
|
||||
expect(buttonLabels).not.toContain('编辑')
|
||||
expect(buttonLabels).not.toContain('调整')
|
||||
const vm = wrapper.vm as unknown as { openMutation(row: Record<string, unknown>, mode: 'ADJUST'): Promise<void> }
|
||||
await vm.openMutation(legacyFirstleg as unknown as Record<string, unknown>, 'ADJUST')
|
||||
expect(getFinanceFeeSource).not.toHaveBeenCalled()
|
||||
expect(adjustFinanceFeeSource).not.toHaveBeenCalled()
|
||||
})
|
||||
|
||||
it('loads all customers by default and keeps explicit customer filtering', async () => {
|
||||
const wrapper = await mountView(['platform:finance:customer-arap:list', 'platform:customer:list'])
|
||||
expect(listFinanceFeeSources).toHaveBeenCalledWith(expect.objectContaining({ page: 1, size: 20, customerId: undefined, direction: undefined }))
|
||||
@@ -209,8 +224,9 @@ describe('FinanceCustomerArapView G2 operations', () => {
|
||||
expect(page).toContain('<el-button v-if="canViewSource" size="small" plain type="primary" @click="openDetail(row)"><Eye :size="15" />详情</el-button>')
|
||||
expect(page).toContain("@click=\"openMutation(row, 'SUBMIT')\"")
|
||||
expect(page).toContain("@click=\"openMutation(row, 'ADJUST')\"")
|
||||
expect(page).toContain("row.sourceSystem !== 'FIRSTLEG'")
|
||||
expect(page).toContain("detail.sourceSystem !== 'FIRSTLEG'")
|
||||
expect(page).toContain('!isFirstlegSource(row)')
|
||||
expect(page).toContain('!isFirstlegSource(detail)')
|
||||
expect(page).toContain("['INBOUND_FEE', 'CONTAINER_FEE'].includes(type)")
|
||||
expect(page).not.toMatch(/<template #actions[\s\S]*?<el-button[^>]*\blink\b/)
|
||||
expect(page).toContain('white-space: nowrap')
|
||||
})
|
||||
|
||||
@@ -85,6 +85,11 @@ const canReviewSource = computed(() => access.can('platform:finance:fee-source:r
|
||||
const canEditSource = computed(() => access.can('platform:finance:fee-source:edit'))
|
||||
const canCreateStatement = computed(() => access.can('platform:finance:reconciliation:create'))
|
||||
const canExport = computed(() => access.can('platform:finance:customer-arap:export') && access.can('platform:download:list'))
|
||||
function isFirstlegSource(source: { sourceSystem?: unknown; sourceType?: unknown }) {
|
||||
const system = String(source.sourceSystem || '').trim().toUpperCase()
|
||||
const type = String(source.sourceType || '').trim().toUpperCase()
|
||||
return system === 'FIRSTLEG' || ['INBOUND_FEE', 'CONTAINER_FEE'].includes(type)
|
||||
}
|
||||
const stateError = computed(() => customersError.value || loadError.value)
|
||||
const activeCustomers = computed(() => customers.value.filter((item) => item.status === 'ACTIVE'))
|
||||
const queryFields = computed<QueryField[]>(() => [
|
||||
@@ -221,6 +226,10 @@ async function submitReview() {
|
||||
}
|
||||
async function openMutation(row: Record<string, unknown>, mode: 'EDIT' | 'ADJUST' | 'SUBMIT' | 'VOID') {
|
||||
const target = row as unknown as ArapRow; selected.value = target
|
||||
if ((mode === 'EDIT' || mode === 'ADJUST') && isFirstlegSource(target)) {
|
||||
ElMessage.info('请到订单入库费用或柜次费用明细中调整,审核通过后会自动同步到财务')
|
||||
return
|
||||
}
|
||||
const loaded = await loadDetail(target)
|
||||
if (!loaded) { detailOpen.value = true; return }
|
||||
mutationMode.value = mode; Object.assign(mutationForm, { amount: loaded.amount, reason: '' }); mutationError.value = null; mutationOpen.value = true
|
||||
@@ -328,7 +337,7 @@ watch(() => [route.name, String(route.params.feeSourceId || '')], ([name, feeSou
|
||||
<section v-if="!customersError && !loadError" class="surface-panel table-panel">
|
||||
<DataTable v-model:page="page" v-model:page-size="pageSize" :data="rows" :columns="columns" :loading="loading" :total="total" preference-key="finance-customer-arap-table" aria-label="客户应收应付列表" row-key="id" empty-text="暂无客户应收应付数据" @selection-change="onSelectionChange" @update:page="load()" @update:page-size="page = 1; load()">
|
||||
<template #toolbar-actions><div class="generation-actions"><el-button v-if="canExport" :loading="exportBusy" :disabled="loading || exportBusy" @click="exportFeeSources"><Download :size="16" />导出Excel</el-button><el-button v-if="canCreateStatement" type="primary" :disabled="!selectedRows.length" @click="continueSelectedGeneration"><FilePlus2 :size="16" />生成所选对账单</el-button></div></template>
|
||||
<template #actions="{ row }"><div class="row-actions"><template v-if="row.feeSourceId"><el-button v-if="canViewSource" size="small" plain type="primary" @click="openDetail(row)"><Eye :size="15" />详情</el-button><el-button v-if="canEditSource && row.sourceSystem !== 'FIRSTLEG' && ['DRAFT','REJECTED'].includes(row.reviewStatus) && row.status === 'AVAILABLE'" size="small" plain @click="openMutation(row, 'EDIT')"><Pencil :size="15" />编辑</el-button><el-button v-if="canEditSource && ['DRAFT','REJECTED'].includes(row.reviewStatus) && row.status === 'AVAILABLE'" size="small" plain type="primary" @click="openMutation(row, 'SUBMIT')"><Send :size="15" />提交审核</el-button><el-button v-if="canReviewSource && row.reviewStatus === 'PENDING' && row.status === 'AVAILABLE'" size="small" plain type="success" @click="openReview(row)"><FileCheck2 :size="15" />审核</el-button><el-button v-if="canEditSource && row.sourceSystem !== 'FIRSTLEG' && row.reviewStatus === 'APPROVED' && row.status === 'AVAILABLE' && !row.statementGenerated" size="small" plain @click="openMutation(row, 'ADJUST')"><Pencil :size="15" />调整</el-button><el-button v-if="canEditSource && row.status === 'AVAILABLE' && !row.statementGenerated" size="small" plain type="danger" @click="openMutation(row, 'VOID')"><Ban :size="15" />作废</el-button></template><span v-else class="muted-action">手工成本</span></div></template>
|
||||
<template #actions="{ row }"><div class="row-actions"><template v-if="row.feeSourceId"><el-button v-if="canViewSource" size="small" plain type="primary" @click="openDetail(row)"><Eye :size="15" />详情</el-button><el-button v-if="canEditSource && !isFirstlegSource(row) && ['DRAFT','REJECTED'].includes(row.reviewStatus) && row.status === 'AVAILABLE'" size="small" plain @click="openMutation(row, 'EDIT')"><Pencil :size="15" />编辑</el-button><el-button v-if="canEditSource && ['DRAFT','REJECTED'].includes(row.reviewStatus) && row.status === 'AVAILABLE'" size="small" plain type="primary" @click="openMutation(row, 'SUBMIT')"><Send :size="15" />提交审核</el-button><el-button v-if="canReviewSource && row.reviewStatus === 'PENDING' && row.status === 'AVAILABLE'" size="small" plain type="success" @click="openReview(row)"><FileCheck2 :size="15" />审核</el-button><el-button v-if="canEditSource && !isFirstlegSource(row) && row.reviewStatus === 'APPROVED' && row.status === 'AVAILABLE' && !row.statementGenerated" size="small" plain @click="openMutation(row, 'ADJUST')"><Pencil :size="15" />调整</el-button><el-button v-if="canEditSource && row.status === 'AVAILABLE' && !row.statementGenerated" size="small" plain type="danger" @click="openMutation(row, 'VOID')"><Ban :size="15" />作废</el-button></template><span v-else class="muted-action">手工成本</span></div></template>
|
||||
<template #customerName="{ row }">{{ customerName(row.customerId, row.customerName) }}</template><template #direction="{ row }"><el-tag :type="row.direction === 'RECEIVABLE' ? 'success' : row.direction === 'PAYABLE' ? 'warning' : 'info'">{{ financeDirectionLabel(row.direction) }}</el-tag></template>
|
||||
<template #businessReference="{ row }">{{ businessReference(row as unknown as ArapRow) }}</template><template #sourceType="{ row }">{{ sourceTypeDisplay(row.sourceType) }}</template><template #supplierName="{ row }">{{ supplierDisplay(row as unknown as ArapRow) }}</template><template #sourceStatus="{ row }">{{ sourceStatusDisplay(row.status) }}</template>
|
||||
<template #status="{ row }"><el-tag :type="row.reviewStatus === 'APPROVED' ? 'success' : row.reviewStatus === 'REJECTED' ? 'danger' : 'warning'">{{ statusLabel(row.reviewStatus) }}</el-tag></template>
|
||||
@@ -339,7 +348,7 @@ watch(() => [route.name, String(route.params.feeSourceId || '')], ([name, feeSou
|
||||
<AdminPage v-else as="div" class="finance-arap-detail" spacing="normal">
|
||||
<section class="surface-panel finance-arap-detail__surface">
|
||||
<DetailPageLayout class="finance-arap-detail__layout" aria-label="费用来源详情">
|
||||
<template #header><div class="detail-heading"><el-button @click="closeDetail"><ArrowLeft :size="16" />返回客户应收应付</el-button><div class="detail-title"><h2>费用来源详情</h2><p>{{ selected?.documentNo || '费用来源' }} · {{ selected ? customerName(selected.customerId, selected.customerName) : '客户名称暂不可用' }}</p></div><div class="detail-actions"><el-button v-if="canEditSource && detail && detail.sourceSystem !== 'FIRSTLEG' && ['DRAFT','REJECTED'].includes(detail.reviewStatus)" @click="openMutation(selected as unknown as Record<string, unknown>, 'EDIT')"><Pencil :size="16" />编辑</el-button><el-button v-if="canEditSource && detail && ['DRAFT','REJECTED'].includes(detail.reviewStatus)" @click="openMutation(selected as unknown as Record<string, unknown>, 'SUBMIT')"><Send :size="16" />提交审核</el-button><el-button v-if="canReviewSource && detail?.reviewStatus === 'PENDING' && selected" @click="openReview(selected as unknown as Record<string, unknown>)"><FileCheck2 :size="16" />审核</el-button></div></div></template>
|
||||
<template #header><div class="detail-heading"><el-button @click="closeDetail"><ArrowLeft :size="16" />返回客户应收应付</el-button><div class="detail-title"><h2>费用来源详情</h2><p>{{ selected?.documentNo || '费用来源' }} · {{ selected ? customerName(selected.customerId, selected.customerName) : '客户名称暂不可用' }}</p></div><div class="detail-actions"><el-button v-if="canEditSource && detail && !isFirstlegSource(detail) && ['DRAFT','REJECTED'].includes(detail.reviewStatus)" @click="openMutation(selected as unknown as Record<string, unknown>, 'EDIT')"><Pencil :size="16" />编辑</el-button><el-button v-if="canEditSource && detail && ['DRAFT','REJECTED'].includes(detail.reviewStatus)" @click="openMutation(selected as unknown as Record<string, unknown>, 'SUBMIT')"><Send :size="16" />提交审核</el-button><el-button v-if="canReviewSource && detail?.reviewStatus === 'PENDING' && selected" @click="openReview(selected as unknown as Record<string, unknown>)"><FileCheck2 :size="16" />审核</el-button></div></div></template>
|
||||
<template v-if="detail" #summary><section class="arap-metrics" aria-label="费用来源概览"><div class="arap-metric is-amount"><span>费用金额</span><strong>{{ money(detail.amount) }}</strong><small>CNY</small></div><div class="arap-metric"><span>收付方向</span><strong>{{ financeDirectionLabel(detail.direction) }}</strong></div><div class="arap-metric"><span>来源状态</span><strong>{{ sourceStatusDisplay(detail.sourceStatus) }}</strong></div><div class="arap-metric"><span>审核状态</span><strong>{{ statusLabel(detail.reviewStatus) }}</strong></div></section></template>
|
||||
<LoadErrorState v-if="detailError" title="费用来源详情加载失败" :message="detailError.message" :loading="detailLoading" @retry="selected && loadDetail(selected)"><template #details><ApiErrorMeta :details="detailError" /></template></LoadErrorState>
|
||||
<template v-else-if="detail"><div class="arap-detail-grid"><FormSection class="arap-information" title="单据信息" :bordered="false"><el-descriptions :column="2" class="arap-detail"><el-descriptions-item label="客户">{{ customerName(detail.customerId, detail.customerName || selected?.customerName) }}</el-descriptions-item><el-descriptions-item label="费用项目">{{ displayFeeName(detail.feeItemName) }}</el-descriptions-item><el-descriptions-item label="来源类型">{{ sourceTypeDisplay(detail.sourceType) }}</el-descriptions-item><el-descriptions-item label="关联业务">{{ detail.inboundCode || detail.containerNo || detail.sourceBusinessId || '业务关联待补充' }}</el-descriptions-item><el-descriptions-item v-if="detail.direction === 'PAYABLE'" label="供应商">{{ detail.supplierName || '供应商待补充' }}</el-descriptions-item><el-descriptions-item label="业务日期">{{ formatBusinessDate(detail.businessDate) }}</el-descriptions-item></el-descriptions></FormSection><FormSection class="arap-settlement" title="审核与结算" :bordered="false"><el-descriptions :column="1" class="arap-detail"><el-descriptions-item label="费用状态">{{ sourceStatusDisplay(detail.sourceStatus) }}</el-descriptions-item><el-descriptions-item label="已生成对账单">{{ detail.statementGenerated ? '是' : '否' }}</el-descriptions-item><el-descriptions-item label="审核原因">{{ detail.reviewReason || '未填写' }}</el-descriptions-item></el-descriptions></FormSection></div><FormSection class="operation-log" title="操作记录" :bordered="false"><el-timeline v-if="detail.operationLogs?.length"><el-timeline-item v-for="(log, index) in detail.operationLogs" :key="`${log.occurredAt}-${index}`" :timestamp="formatDateTime(log.occurredAt)">{{ financeOperationActionLabel(log.action) }} · {{ displayOperator(log.operatorName) }}<small>{{ log.remark || financeOperationResultLabel(log.result) }}</small></el-timeline-item></el-timeline><el-empty v-else description="暂无操作记录" /></FormSection></template>
|
||||
|
||||
Reference in New Issue
Block a user