import { flushPromises, mount } from '@vue/test-utils' import { beforeEach, describe, expect, it, vi } from 'vitest' import BusinessDocumentFees from './BusinessDocumentFees.vue' import { listBusinessFeeOptions } from '../api/overseasFees' const can = vi.hoisted(() => vi.fn(() => true)) vi.mock('@/core/access/accessPreview', () => ({ useAccessPreviewStore: () => ({ can }) })) vi.mock('../api/overseasFees', () => ({ listBusinessFeeOptions: vi.fn() })) vi.mock('./BusinessOrderFees.vue', () => ({ default: { name: 'BusinessOrderFees', props: ['business', 'relatedBusinesses', 'canCreate', 'readonly', 'direction'], template: '
' } })) const business = { businessType: 'LASTLEG_ORDER', businessId: '9223372036854775001', businessNo: 'TB-01', customerId: 'C1', customerName: '客户', orderId: '9223372036854775001', warehouseId: null } function page(props = {}) { return mount(BusinessDocumentFees, { props: { ...business, ...props }, global: { stubs: { LoadErrorState: { props: ['message'], template: '
{{ message }}
' }, ApiErrorMeta: true, ElSkeleton: true, ElAlert: true, } } }) } beforeEach(() => { vi.resetAllMocks(); can.mockReturnValue(true); vi.mocked(listBusinessFeeOptions).mockResolvedValue([business]) }) describe('单据费用归属', () => { it('passes the payable direction to the review panel', async () => { const wrapper = page({ direction: 'PAYABLE', canCreate: false }); await flushPromises() expect(wrapper.getComponent({ name: 'BusinessOrderFees' }).props()).toMatchObject({ direction: 'PAYABLE', canCreate: false }) }) it('requires exact customer, type, number and long identity', async () => { vi.mocked(listBusinessFeeOptions).mockResolvedValue([{ ...business, businessNo: 'TB-010' }, { ...business, customerId: 'C2' }, business]) const wrapper = page(); await flushPromises() expect(wrapper.getComponent({ name: 'BusinessOrderFees' }).props('business')).toEqual(business) expect(wrapper.getComponent({ name: 'BusinessOrderFees' }).props('canCreate')).toBe(true) expect(wrapper.getComponent({ name: 'BusinessOrderFees' }).props('readonly')).toBe(false) expect(listBusinessFeeOptions).toHaveBeenCalledWith({ businessType: 'LASTLEG_ORDER', customerId: 'C1', keyword: 'TB-01' }) }) it('does not permit a missing or ambiguous match to create charges', async () => { vi.mocked(listBusinessFeeOptions).mockResolvedValue([{ ...business, businessId: 'another' }]) const wrapper = page(); await flushPromises() expect(wrapper.findComponent({ name: 'BusinessOrderFees' }).exists()).toBe(false) expect(wrapper.text()).toContain('未找到唯一关联单据') }) it('resolves source order charges alongside tail charges', async () => { const source = { ...business, businessType: 'RETURN_ORDER', businessId: 'return-id', businessNo: 'TH-01', orderId: null } vi.mocked(listBusinessFeeOptions).mockResolvedValueOnce([business]).mockResolvedValueOnce([source]) const wrapper = page({ relatedDocuments: [source] }); await flushPromises() expect(wrapper.getComponent({ name: 'BusinessOrderFees' }).props('relatedBusinesses')).toEqual([source]) }) it('can resolve a unique relabel id without inventing a customer', async () => { const wrapper = page({ customerId: undefined }); await flushPromises() expect(wrapper.getComponent({ name: 'BusinessOrderFees' }).props('business').customerId).toBe('C1') }) it('keeps the real tail order usable when its source number is only an external reference', async () => { vi.mocked(listBusinessFeeOptions).mockResolvedValueOnce([business]).mockResolvedValueOnce([]) const wrapper = page({ relatedDocuments: [{ businessType: 'RELABEL_ORDER', businessNo: 'external-reference', customerId: 'C1' }] }) await flushPromises() expect(wrapper.getComponent({ name: 'BusinessOrderFees' }).props('business')).toEqual(business) expect(wrapper.getComponent({ name: 'BusinessOrderFees' }).props('relatedBusinesses')).toEqual([]) }) it('does not query fees without read permission', async () => { can.mockReturnValue(false) const wrapper = page(); await flushPromises() expect(listBusinessFeeOptions).not.toHaveBeenCalled() expect(wrapper.findComponent({ name: 'BusinessOrderFees' }).exists()).toBe(false) }) })