优化
This commit is contained in:
@@ -235,12 +235,15 @@ export async function completeReturnRelabel(context, merchantToken, pdaToken, re
|
||||
for (const [index, source] of sources.entries()) {
|
||||
const target = await command(pdaToken, 'POST', '生成本轮带目的仓换标托盘', `${pallets}/relabel-pallet-label`,
|
||||
{ relabelNo, idempotencyKey: key(context, `RETURN-PALLET-${index}`) })
|
||||
const from = await command(pdaToken, 'POST', '回查来源托盘版本', `${pallets}/resolve`, { code: source.palletCode })
|
||||
const to = await command(pdaToken, 'POST', '回查目标托盘版本', `${pallets}/resolve`, { code: target.palletCode })
|
||||
const from = await command(pdaToken, 'POST', '回查来源托盘版本', `${pallets}/pallets/resolve`, { code: source.palletCode })
|
||||
const to = await command(pdaToken, 'POST', '回查目标托盘版本', `${pallets}/pallets/resolve`, { code: target.palletCode })
|
||||
require('组托仅使用本轮任务箱唛', source.cartonMarks?.length > 0
|
||||
&& source.cartonMarks.every(mark => task.items.some(item => item.cartonMark === mark)))
|
||||
const body = { relabelNo, source: { palletCode: from.palletCode, expectedVersion: Number(from.palletVersion) },
|
||||
target: { palletCode: to.palletCode, expectedVersion: Number(to.palletVersion) },
|
||||
actualSource: { positionId: source.positionId, expectedPositionVersion: Number(source.positionVersion),
|
||||
packages: task.items.filter(item => source.cartonMarks.includes(item.cartonMark))
|
||||
.reduce((sum, item) => sum + Number(item.expectedPackages), 0) },
|
||||
cartonMarks: source.cartonMarks, idempotencyKey: key(context, `RETURN-BIND-${index}`), reason: context.marker }
|
||||
const bound = await command(pdaToken, 'POST', '退货换标按实际数量绑定目标托盘', `${pallets}/relabel-disassemble`, body)
|
||||
const replay = await command(pdaToken, 'POST', '退货换标组托原键重放', `${pallets}/relabel-disassemble`, body)
|
||||
|
||||
@@ -17,10 +17,16 @@ test('return relabel lifecycle requires review, quantities, binding, photo and c
|
||||
calls.push({ method, path, body, token })
|
||||
let data = task
|
||||
if (path.endsWith('/status')) data = { application: { relabelNo: 'RL-1', status: 'PENDING_PROCESSING' } }
|
||||
if (path.endsWith('/relabel-sources')) data = [{ palletCode: 'OLD', cartonMarks: ['BOX'] }]
|
||||
if (path.endsWith('/relabel-sources')) data = [{ positionId: '12', positionVersion: 0, palletCode: 'OLD', cartonMarks: ['BOX'] }]
|
||||
if (path.endsWith('/relabel-pallet-label')) data = { palletCode: 'NEW' }
|
||||
if (path.endsWith('/resolve')) data = { palletCode: body.code, palletVersion: 1 }
|
||||
if (path.endsWith('/relabel-disassemble')) data = { status: 'COMPLETED', operationId: '9', replayed: true }
|
||||
if (path.endsWith('/resolve')) {
|
||||
assert.equal(path, '/api/pda/v1/last-leg/pallet-operations/pallets/resolve')
|
||||
data = { palletCode: body.code, palletVersion: 1 }
|
||||
}
|
||||
if (path.endsWith('/relabel-disassemble')) {
|
||||
assert.deepEqual(body.actualSource, { positionId: '12', expectedPositionVersion: 0, packages: 1 })
|
||||
data = { status: 'COMPLETED', operationId: '9', replayed: true }
|
||||
}
|
||||
if (path.endsWith('/RL-1/complete')) data = { applicationStatus: 'CUSTOMER_CONFIRM_PENDING' }
|
||||
if (path.endsWith('/confirm-completion')) data = { application: { relabelNo: 'RL-1', status: 'COMPLETED' } }
|
||||
if (path.endsWith('/return-orders/RT-1')) data = { order: { status: 'COMPLETED', relabelNo: 'RL-1', relabelStatus: 'COMPLETED' } }
|
||||
|
||||
@@ -0,0 +1,47 @@
|
||||
import assert from 'node:assert/strict'
|
||||
import { readFile } from 'node:fs/promises'
|
||||
import path from 'node:path'
|
||||
import test from 'node:test'
|
||||
import { fileURLToPath } from 'node:url'
|
||||
|
||||
const repositoryRoot = path.resolve(fileURLToPath(new URL('..', import.meta.url)))
|
||||
const migrations = {
|
||||
iam: 'deploy/sql/migrations/cn/baiyue_iam/V1__align_schema_baseline.sql',
|
||||
firstleg: 'deploy/sql/migrations/cn/baiyue_firstleg/V1__align_schema_baseline.sql',
|
||||
file: 'deploy/sql/migrations/cn/baiyue_file/V1__align_schema_baseline.sql',
|
||||
lastleg: 'deploy/sql/migrations/overseas/baiyue_lastleg/V2__align_schema_baseline.sql',
|
||||
}
|
||||
|
||||
async function sources() {
|
||||
return Object.fromEntries(await Promise.all(Object.entries(migrations).map(async ([name, relative]) => (
|
||||
[name, await readFile(path.join(repositoryRoot, relative), 'utf8')]
|
||||
))))
|
||||
}
|
||||
|
||||
test('schema alignment migrations contain no destructive statements', async () => {
|
||||
for (const [name, source] of Object.entries(await sources())) {
|
||||
assert.doesNotMatch(source, /^\s*(?:DROP|DELETE|UPDATE|TRUNCATE)\b/im, `${name} 迁移不得删除、清理或回填数据`)
|
||||
assert.doesNotMatch(source, /\bSIGNAL\s+SQLSTATE\b/i, `${name} 迁移不得使用 MySQL 不支持的动态 SIGNAL`)
|
||||
}
|
||||
})
|
||||
|
||||
test('schema alignment migrations cover the verified drift', async () => {
|
||||
const source = await sources()
|
||||
for (const field of ['tenant_code', 'customer_nickname', 'original_file_name']) assert.match(source.iam, new RegExp(`\\b${field}\\b`))
|
||||
assert.match(source.firstleg, /\bpallet_no\b/)
|
||||
for (const table of ['file_pda_release_channel', 'file_pda_release']) assert.match(source.file, new RegExp(`\\b${table}\\b`))
|
||||
for (const field of [
|
||||
'actual_discard_packages', 'pda_status', 'pda_operator_id', 'pda_completed_at',
|
||||
'quantity', 'pallet_code', 'discrepancy_reason', 'manually_completed_at',
|
||||
]) assert.match(source.lastleg, new RegExp(`\\b${field}\\b`))
|
||||
})
|
||||
|
||||
test('constraint tightening is guarded before any alter table', async () => {
|
||||
for (const [name, source] of Object.entries(await sources())) {
|
||||
const firstAlter = source.search(/\bALTER TABLE\b/i)
|
||||
const firstGuard = source.search(/SET @guard\s*=\s*IF/i)
|
||||
if (name === 'file' || name === 'iam' || name === 'firstleg' || name === 'lastleg') {
|
||||
assert.ok(firstGuard >= 0 && firstGuard < firstAlter, `${name} 必须先验证存量数据再执行 DDL`)
|
||||
}
|
||||
}
|
||||
})
|
||||
Reference in New Issue
Block a user