fix: bind overseas receiving to shared warehouse
This commit is contained in:
@@ -46,32 +46,40 @@ async function loginMerchantForNegativeProbe(context) {
|
||||
return nonBlank(data?.overseasAccessToken) ? data.overseasAccessToken : null
|
||||
}
|
||||
|
||||
async function createPicker(context, index) {
|
||||
async function resolvePickerAccess(context) {
|
||||
const rolesResponse = await context.request('GET', '/api/platform/v1/iam/roles')
|
||||
const roles = context.apiSuccess(MODULE, `查询海外PDA仓库操作员角色${index}`, rolesResponse, '', OPTIONS)
|
||||
const roles = context.apiSuccess(MODULE, '查询海外PDA仓库操作员角色', rolesResponse, '', OPTIONS)
|
||||
const role = (Array.isArray(roles) ? roles : []).find((item) => item?.roleCode === 'WAREHOUSE_PICKER' && item?.status === 'ACTIVE')
|
||||
const permissionsResponse = await context.request('GET', '/api/platform/v1/iam/permissions')
|
||||
const permissions = context.apiSuccess(MODULE, `查询海外PDA权限资源${index}`, permissionsResponse, '', OPTIONS)
|
||||
const permissions = context.apiSuccess(MODULE, '查询海外PDA权限资源', permissionsResponse, '', OPTIONS)
|
||||
const operate = (Array.isArray(permissions) ? permissions : []).find((item) => item?.permissionCode === 'lastleg:pda:operate')
|
||||
const assigned = Boolean(role && operate && (role.permissionIds || []).map(id).includes(id(operate.id)))
|
||||
context.assert(MODULE, `WAREHOUSE_PICKER精确具备海外PDA权限${index}`, rolesResponse, assigned,
|
||||
context.assert(MODULE, 'WAREHOUSE_PICKER精确具备海外PDA权限', rolesResponse, assigned,
|
||||
`roleId=${id(role?.id) || 'missing'}, permissionId=${id(operate?.id) || 'missing'}`, OPTIONS)
|
||||
if (!assigned) {
|
||||
blockerGap(context, '海外PDA仓库操作员权限', 'WAREHOUSE_PICKER未获得lastleg:pda:operate;必须先执行最新国内统一增量SQL并部署IAM')
|
||||
return null
|
||||
}
|
||||
return { role, operate }
|
||||
}
|
||||
|
||||
async function createPicker(context, index, overseasWarehouseId, access) {
|
||||
const role = access.role
|
||||
const suffix = markerSuffix(context)
|
||||
const username = `pda_overseas_${suffix.toLowerCase()}_${index}`.slice(0, 64)
|
||||
const password = `Pda${suffix.replace(/[^A-Za-z0-9]/g, '')}A${index}9`
|
||||
const phone = await context.findAvailablePhone(MODULE)
|
||||
const payload = { username, displayName: `海外PDA验收操作员${index}-${suffix}`, phone,
|
||||
email: `${username}@example.com`, tenantId: '0', roleIds: [id(role.id)], password, status: 'ACTIVE' }
|
||||
email: `${username}@example.com`, tenantId: '0', roleIds: [id(role.id)],
|
||||
overseasWarehouseId, password, status: 'ACTIVE' }
|
||||
const createdResponse = await context.request('POST', '/api/platform/v1/iam/users', payload)
|
||||
const created = context.apiSuccess(MODULE, `创建海外PDA仓库操作员${index}`, createdResponse, '', OPTIONS)
|
||||
const membershipId = id(created?.membershipId)
|
||||
context.assert(MODULE, `海外PDA操作员${index}冻结平台范围与角色`, createdResponse,
|
||||
longId(membershipId) && id(created?.tenantId) === '0' && (created?.roleIds || []).map(id).includes(id(role.id)),
|
||||
`membershipId=${membershipId || 'missing'}, tenantId=${id(created?.tenantId) || 'missing'}`, OPTIONS)
|
||||
longId(membershipId) && id(created?.tenantId) === '0'
|
||||
&& id(created?.overseasWarehouseId) === id(overseasWarehouseId)
|
||||
&& (created?.roleIds || []).map(id).includes(id(role.id)),
|
||||
`membershipId=${membershipId || 'missing'}, tenantId=${id(created?.tenantId) || 'missing'}, overseasWarehouseId=${id(created?.overseasWarehouseId) || 'missing'}`, OPTIONS)
|
||||
if (!longId(membershipId)) return null
|
||||
const login = await context.request('POST', '/api/auth/login', { username, password }, '')
|
||||
const token = success(login) ? login.body?.data?.overseasAccessToken : null
|
||||
@@ -88,7 +96,7 @@ async function disablePicker(context, picker, index) {
|
||||
}
|
||||
|
||||
async function createPallet(context, inbound, index) {
|
||||
const warehouseId = id(inbound?.destinationWarehouseId)
|
||||
const warehouseId = id(inbound?.overseasWarehouseId)
|
||||
if (!longId(warehouseId)) return null
|
||||
const suffix = markerSuffix(context)
|
||||
const location = await context.requestOverseas('POST', `/api/platform/v1/warehouse-admin/${encodeURIComponent(warehouseId)}/locations`, {
|
||||
@@ -114,7 +122,8 @@ async function uploadPhotos(context, token) {
|
||||
const malicious = await context.requestOverseasMultipart('POST', '/api/pda/v1/last-leg/receiving-containers/current/unload-photos/files', {
|
||||
name: `${context.marker}-forged.png`, type: 'image/png', content: Uint8Array.from(Buffer.from('<script>alert(1)</script>')),
|
||||
}, token)
|
||||
context.addStep(MODULE, '伪造图片内容安全扫描被拒绝', malicious, !success(malicious) && traced(malicious), trace(malicious), OPTIONS)
|
||||
context.addStep(MODULE, '伪造图片内容安全扫描返回A0400', malicious,
|
||||
malicious?.http === 200 && code(malicious) === 'A0400' && traced(malicious), trace(malicious), OPTIONS)
|
||||
const photos = []
|
||||
for (const role of PHOTO_ROLES) {
|
||||
const response = await context.requestOverseasMultipart('POST', '/api/pda/v1/last-leg/receiving-containers/current/unload-photos/files', {
|
||||
@@ -265,7 +274,7 @@ async function runReceiving(context, token, secondaryToken, merchantToken) {
|
||||
const pallet = await createPallet(context, inbound, index)
|
||||
if (!pallet) {
|
||||
blockerGap(context, `${inbound.destinationType}入仓码${inbound.inboundCode}实物托盘`,
|
||||
`无法在目的仓 ${inbound.destinationWarehouseId || 'missing'} 创建可解析真实托盘`, 'warehouse-resource')
|
||||
`无法在实际海外收货仓 ${inbound.overseasWarehouseId || 'missing'} 创建可解析真实托盘;目的仓 ${inbound.destinationWarehouseId || 'missing'} 不得代替物理仓`, 'warehouse-resource')
|
||||
continue
|
||||
}
|
||||
pallets.set(inbound.inboundCode, pallet)
|
||||
@@ -313,11 +322,21 @@ export async function run(context) {
|
||||
context.createdResources.phase4OverseasPda = {
|
||||
marker: context.marker, containerNo: null, customerId: null,
|
||||
palletIds: [], locationIds: [], finalStatus: null, pickerMembershipIds: [],
|
||||
cleanup: 'Pallets and locations used by completed inventory are retained as acceptance evidence',
|
||||
overseasWarehouseId: null, overseasWarehouseName: null,
|
||||
cleanup: 'Shared warehouse, pallets and locations used by completed inventory are retained as acceptance evidence',
|
||||
}
|
||||
const merchantToken = await loginMerchantForNegativeProbe(context)
|
||||
const primary = await createPicker(context, 1)
|
||||
const secondary = primary?.token ? await createPicker(context, 2) : null
|
||||
const pickerAccess = await resolvePickerAccess(context)
|
||||
if (!pickerAccess) return
|
||||
const sharedWarehouse = await createSharedWarehouse(context)
|
||||
if (!sharedWarehouse) {
|
||||
blockerGap(context, '海外PDA共享实际收货仓', '无法通过平台正式API创建customerId=0共享物理仓')
|
||||
return
|
||||
}
|
||||
context.createdResources.phase4OverseasPda.overseasWarehouseId = sharedWarehouse.id
|
||||
context.createdResources.phase4OverseasPda.overseasWarehouseName = sharedWarehouse.name
|
||||
const primary = await createPicker(context, 1, sharedWarehouse.id, pickerAccess)
|
||||
const secondary = primary?.token ? await createPicker(context, 2, sharedWarehouse.id, pickerAccess) : null
|
||||
for (const picker of [primary, secondary]) if (picker?.membershipId) {
|
||||
context.createdResources.phase4OverseasPda.pickerMembershipIds.push(picker.membershipId)
|
||||
}
|
||||
@@ -332,3 +351,22 @@ export async function run(context) {
|
||||
await disablePicker(context, primary, 1)
|
||||
}
|
||||
}
|
||||
|
||||
async function createSharedWarehouse(context) {
|
||||
const suffix = markerSuffix(context)
|
||||
const payload = {
|
||||
customerId: 0, warehouseCode: `PDA-${suffix}`.slice(0, 50),
|
||||
warehouseName: `PDA共享收货仓-${suffix}`.slice(0, 120), warehouseType: 'OVERSEAS',
|
||||
countryCode: 'US', timezone: 'America/Los_Angeles', contactName: 'PDA Acceptance',
|
||||
contactPhone: '+1-213-555-0198', contactEmail: `pda-${suffix.toLowerCase()}@example.com`,
|
||||
status: 'ACTIVE', remark: `${context.marker}-shared-receiving`,
|
||||
address: { addressType: 'WAREHOUSE', countryCode: 'US', stateProvince: 'CA', city: 'Los Angeles',
|
||||
district: 'Commerce', postalCode: '90040', addressLine1: '1 Acceptance Logistics Ave' },
|
||||
capabilities: [{ capabilityCode: 'RECEIVING', capabilityName: '收货', enabled: true }],
|
||||
}
|
||||
const created = await context.requestOverseas('POST', '/api/platform/v1/warehouse-admin', payload)
|
||||
const warehouseId = id(created?.body?.data)
|
||||
context.addStep(MODULE, '创建本轮PDA共享实际收货仓', created,
|
||||
success(created) && longId(warehouseId), `warehouseId=${warehouseId || 'missing'}; ${trace(created)}`, OPTIONS)
|
||||
return longId(warehouseId) ? { id: warehouseId, name: payload.warehouseName } : null
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user