Files
goauto/web/tests/e2e/purchase-order-writeback.spec.ts
T

146 lines
9.8 KiB
TypeScript
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
import { expect, test } from '@playwright/test'
async function setup(page: any, state = 'not_started', failManualOnce = false) {
await page.setViewportSize({ width: 1920, height: 1080 })
await page.context().addCookies([{ name: 'Admin-Token', value: 'test-only', domain: 'localhost', path: '/' }])
const requests: { path: string, body: any }[] = []
const items = [
{ id: 11, taskType: 'syb_order', executionMode: 'live', status: 'order_created', pddOrderNo: 'EXAMPLE-11', orderSubmittedAt: '2026-09-19T12:00:00Z', pddOrderAmountCent: null as number | null, paymentReviewStatus: 'unpaid', orderWriteback: { status: state, canSubmit: ['not_started', 'failed', 'unknown'].includes(state), reason: state === 'conflict' ? 'SYB 已有不同单号,未覆盖' : '' } },
{ id: 12, taskType: 'syb_order', executionMode: 'live', status: 'failed', retryable: true, orderWriteback: { status: 'not_applicable', canSubmit: false, reason: '' } },
{ id: 13, taskType: 'stock', executionMode: 'live', status: 'order_created', orderWriteback: { status: 'not_applicable', canSubmit: false, reason: '' } }
]
await page.route('**/api/**', async route => {
const path = new URL(route.request().url()).pathname
if (path.endsWith('/getinfo')) return route.fulfill({ json: { code: 200, data: { roles: ['admin'], name: '测试采购员', avatar: '', introduction: '', permissions: [] } } })
if (path.endsWith('/menurole')) return route.fulfill({ json: { code: 200, data: [{ path: '/collection-purchase', component: 'Layout', menuName: 'GoAutoCollectionPurchase', title: '采集采购', visible: '0', children: [{ path: '/purchase-tasks/index', component: '/goauto/purchase-tasks/index', menuName: 'GoAutoPurchaseTasks', title: '采购管理', visible: '0' }] }] } })
if (route.request().method() === 'POST') {
const body = route.request().postDataJSON()
requests.push({ path, body })
if (path.endsWith('/resolve-unknown')) {
if (failManualOnce) { failManualOnce = false; return route.fulfill({ status: 500, json: { code: 500, message: 'synthetic failure' } }) }
items[0].pddOrderAmountCent = body.pddOrderAmountCent
return route.fulfill({ json: { code: 200, data: items[0] } })
}
if (path.endsWith('/syb-order-writeback')) {
items[0].orderWriteback = { status: 'pending', canSubmit: false, reason: '' }
return route.fulfill({ json: { code: 200, data: { items: body.purchaseTaskIds.map((taskId: number) => ({ taskId, result: 'pending', reason: '已受理' })) } } })
}
if (path.endsWith('/batch-retry')) return route.fulfill({ json: { code: 200, data: { items: [], createdCount: 1, failedCount: 0 } } })
throw new Error('unexpected write: ' + path)
}
if (path.endsWith('/purchase-tasks/11')) return route.fulfill({ json: { code: 200, data: { task: items[0], attempts: [] } } })
if (path.endsWith('/purchase-tasks')) return route.fulfill({ json: { code: 200, data: { items, total: items.length } } })
return route.fulfill({ json: { code: 200, data: [] } })
})
await page.goto('/#/purchase-tasks/index')
await expect(page.getByText('CG-11', { exact: true })).toBeVisible()
return requests
}
test('混选任务分别回填与重试,不把已下单任务交给采购重试', async ({ page }) => {
const requests = await setup(page)
await page.locator('.el-table__header-wrapper .el-checkbox').click()
await expect(page.getByRole('button', { name: '重试(1)', exact: true })).toBeEnabled()
await expect(page.getByRole('button', { name: '批量回填 SYB(1)', exact: true })).toBeEnabled()
await page.getByRole('button', { name: '重试(1)', exact: true }).click()
const retry = page.getByRole('dialog', { name: '确认重试失败任务' })
await expect(retry.getByText('CG-12', { exact: true })).toBeVisible()
await expect(retry.getByText('CG-11', { exact: true })).toHaveCount(0)
await retry.getByRole('button', { name: '确认重试', exact: true }).click()
await expect.poll(() => requests.length).toBe(1)
expect(requests[0].body.taskIds).toEqual([12])
await page.getByRole('dialog', { name: '批量重试结果' }).getByRole('button', { name: '留在当前页' }).click()
await page.locator('.el-table__header-wrapper .el-checkbox').first().click()
await page.getByRole('button', { name: '批量回填 SYB(1)', exact: true }).click()
const result = page.getByRole('dialog', { name: 'SYB 单号回填提交结果' })
await expect(result.getByText('待回填', { exact: true })).toBeVisible()
expect(requests[1].body.purchaseTaskIds).toEqual([11])
expect(requests[1].body.requestId).toMatch(/^[0-9a-f-]{36}$/)
await result.getByRole('button', { name: '关闭', exact: true }).click()
await expect(result).toBeHidden()
await expect(page.getByRole('button', { name: '批量回填 SYB(0)', exact: true })).toBeDisabled()
})
test('未支付订单可从详情补偿回填,旧物流流程保持独立', async ({ page }) => {
const requests = await setup(page, 'failed')
await page.getByRole('button', { name: '详情', exact: true }).first().click()
const drawer = page.getByRole('dialog', { name: '采购任务详情' })
await expect(drawer.getByText('SYB 物流回填', { exact: true })).toBeVisible()
await drawer.getByRole('button', { name: '重试回填 SYB 单号', exact: true }).click()
await expect(page.getByRole('dialog', { name: 'SYB 单号回填提交结果' })).toBeVisible()
expect(requests).toHaveLength(1)
expect(requests[0].path).toContain('/syb-order-writeback')
expect(requests[0].body.purchaseTaskIds).toEqual([11])
})
test('冲突显示原因且没有覆盖按钮', async ({ page }) => {
await setup(page, 'conflict')
await page.getByRole('button', { name: '详情', exact: true }).first().click()
const drawer = page.getByRole('dialog', { name: '采购任务详情' })
await expect(drawer.getByText('单号冲突', { exact: true })).toBeVisible()
await expect(drawer.getByText('SYB 已有不同单号,未覆盖', { exact: true })).toBeVisible()
await expect(drawer.getByRole('button', { name: /回填 SYB 单号/ })).toHaveCount(0)
})
test('状态下拉框筛选已回填SYB,清空后恢复普通列表', async ({ page }) => {
const requests = await setup(page, 'succeeded')
const statuses: string[] = []
await page.route('**/api/admin/v1/purchase-tasks?**', async route => {
const query = new URL(route.request().url()).searchParams
statuses.push(query.get('status') || '')
expect(query.get('page')).toBe('1')
return route.fulfill({ json: { code: 200, data: { items: [{ id: 11, taskType: 'syb_order', executionMode: 'live', status: 'order_created', orderWriteback: { status: 'succeeded', canSubmit: false } }], total: 1 } } })
})
const field = page.locator('.search-form .el-form-item').filter({ has: page.locator('label').filter({ hasText: /^状态$/ }) })
await field.locator('.el-select').click()
await page.getByRole('option', { name: '已回填 SYB', exact: true }).click()
await page.getByRole('button', { name: '查询', exact: true }).click()
await expect.poll(() => statuses.at(-1)).toBe('syb_writeback_succeeded')
await expect(page.getByText('订单已创建', { exact: true }).first()).toBeVisible()
await field.locator('.el-select').hover()
await field.locator('.el-select__clear').click()
await page.getByRole('button', { name: '查询', exact: true }).click()
await expect.poll(() => statuses.at(-1)).toBe('')
expect(requests).toHaveLength(0)
})
for (const amount of ['0', '13.01']) {
test(`已创建订单补金额 ${amount},不重新采购或修改支付状态`, async ({ page }) => {
const requests = await setup(page)
await page.getByRole('button', { name: '详情', exact: true }).first().click()
const drawer = page.getByRole('dialog', { name: '采购任务详情' })
await drawer.getByRole('button', { name: '补全订单信息', exact: true }).click()
const dialog = page.getByRole('dialog', { name: '补全订单信息', exact: true })
await expect(dialog.getByRole('button', { name: '保存', exact: true })).toBeDisabled()
await expect(dialog.getByRole('textbox').first()).toHaveAttribute('readonly', '')
await dialog.getByPlaceholder('例如 13.00').fill('-1')
await expect(dialog.getByText('请输入不小于0、最多两位小数的金额')).toBeVisible()
await expect(dialog.getByRole('button', { name: '保存', exact: true })).toBeDisabled()
await dialog.getByPlaceholder('例如 13.00').fill(amount)
await dialog.getByRole('button', { name: '保存', exact: true }).click()
await expect(dialog).toBeHidden()
expect(requests).toHaveLength(1)
expect(requests[0].body.pddOrderAmountCent).toBe(Math.round(Number(amount) * 100))
expect(requests[0].body.pddOrderNo).toBe('EXAMPLE-11')
expect(requests[0].body.orderSubmittedAt).toBe('2026-09-19T12:00:00Z')
expect(requests[0].path).toContain('/resolve-unknown')
await expect(drawer.getByText('信息完整', { exact: true })).toBeVisible()
await expect(drawer.getByRole('button', { name: '补全订单信息', exact: true })).toHaveCount(0)
})
}
test('补录失败保留输入,原样重试复用requestId', async ({ page }) => {
const requests = await setup(page, 'not_started', true)
await page.getByRole('button', { name: '详情', exact: true }).first().click()
await page.getByRole('button', { name: '补全订单信息', exact: true }).click()
const dialog = page.getByRole('dialog', { name: '补全订单信息', exact: true })
await dialog.getByPlaceholder('例如 13.00').fill('15.50')
await dialog.getByRole('button', { name: '保存', exact: true }).click()
await expect(dialog.getByText(/保存未确认/)).toBeVisible()
await expect(dialog.getByPlaceholder('例如 13.00')).toHaveValue('15.50')
await dialog.getByRole('button', { name: '保存', exact: true }).click()
await expect(dialog).toBeHidden()
expect(requests).toHaveLength(2)
expect(requests[1].body).toEqual(requests[0].body)
})