优化
This commit is contained in:
@@ -1,13 +1,15 @@
|
||||
import fs from 'node:fs'
|
||||
import path from 'node:path'
|
||||
import crypto from 'node:crypto'
|
||||
|
||||
// Explicit one-time TEST setup. No inventory operations, existing-user changes or role changes.
|
||||
// Explicit TEST identity handoff. Reuses an existing PDA account without changing roles or account state.
|
||||
export async function createF33PdaOperator({ env, credentialFile, reportFile }) {
|
||||
if (String(env.CHONGCHONG_ENV).toUpperCase() !== 'TEST') throw Error('EXPLICIT_TEST_REQUIRED')
|
||||
if (fs.existsSync(credentialFile) || fs.existsSync(reportFile)) throw Error('EXISTING_RESULT_RECONCILE_NO_RECREATE')
|
||||
const warehouseId = '193000000000200003', roleCode = 'OVERSEAS_WAREHOUSE_PDA_OPERATOR'
|
||||
const report = { startedAt: new Date().toISOString(), warehouseId, roleCode, requests: [], success: false,
|
||||
const actors = JSON.parse(env.CHONGCHONG_ACCEPTANCE_PDA_ACTORS || '[]')
|
||||
const actor = actors.find(item => String(item.warehouseId) === warehouseId && item.membershipId && item.username && item.password)
|
||||
if (!actor) throw Error('EXISTING_PDA_ACCOUNT_CONFIGURATION_REQUIRED_NO_CREATE')
|
||||
const report = { reused: true, startedAt: new Date().toISOString(), warehouseId, roleCode, requests: [], success: false,
|
||||
existingAccountsChanged: false, rolePermissionsChanged: false, businessOperationsIssued: 0 }
|
||||
const save = () => { fs.mkdirSync(path.dirname(reportFile), {recursive:true}); fs.writeFileSync(reportFile, JSON.stringify(report,null,2)) }
|
||||
let admin, pda
|
||||
@@ -27,34 +29,30 @@ export async function createF33PdaOperator({ env, credentialFile, reportFile })
|
||||
const role=roles.find(r=>r.roleCode===roleCode&&r.status==='ACTIVE')
|
||||
const operate=permissions.find(p=>p.permissionCode==='lastleg:pda:operate')
|
||||
if(!role||!operate||!(role.permissionIds||[]).some(id=>String(id)===String(operate.id)))throw Error('EXISTING_ROLE_OPERATE_PERMISSION_REQUIRED')
|
||||
let phone
|
||||
for(let i=0;i<10;i++){
|
||||
const candidate='18'+String(crypto.randomInt(0,1000000000)).padStart(9,'0')
|
||||
if(await call('GET',`/platform/v1/iam/tenants/administrator-phone-availability?phone=${candidate}`)){phone=candidate;break}
|
||||
let created
|
||||
for (let page=1;page<=100;page++) {
|
||||
const users=await call('GET',`/platform/v1/iam/users?page=${page}&size=100`)
|
||||
if(!Array.isArray(users?.records)||!Number.isSafeInteger(Number(users.total)))throw Error('EXISTING_ACCOUNT_PAGE_INVALID')
|
||||
created=users.records.find(row=>String(row.membershipId)===String(actor.membershipId)&&row.username===actor.username)
|
||||
if(created||page*100>=Number(users.total))break
|
||||
}
|
||||
if(!phone)throw Error('NO_AVAILABLE_SYNTHETIC_PHONE')
|
||||
const username='pda_f33_20261004_'+crypto.randomBytes(5).toString('hex')
|
||||
const password='Pda1!'+crypto.randomBytes(18).toString('hex')
|
||||
const writeCredentials = membershipId => fs.writeFileSync(credentialFile,
|
||||
`PDA_USERNAME=${username}\nPDA_PASSWORD=${password}\nPDA_MEMBERSHIP_ID=${membershipId}\n`,{mode:0o600})
|
||||
fs.mkdirSync(path.dirname(credentialFile),{recursive:true})
|
||||
fs.writeFileSync(credentialFile,`PDA_USERNAME=${username}\nPDA_PASSWORD=${password}\nPDA_MEMBERSHIP_ID=\n`,{flag:'wx',mode:0o600})
|
||||
const created=await call('POST','/platform/v1/iam/users',{username,password,phone,
|
||||
displayName:'F33海外PDA独立验收-20261004',email:username+'@example.com',tenantId:'0',roleIds:[String(role.id)],
|
||||
overseasWarehouseId:warehouseId,domesticWarehouseId:null,status:'ACTIVE'})
|
||||
if(!created)throw Error('EXISTING_ACCOUNT_NOT_FOUND_NO_CREATE')
|
||||
const username=actor.username,password=actor.password
|
||||
report.subject={membershipId:String(created.membershipId),userId:String(created.userId),authUserId:String(created.authUserId),
|
||||
tenantId:String(created.tenantId),roleIds:(created.roleIds||[]).map(String),overseasWarehouseId:String(created.overseasWarehouseId),
|
||||
domesticWarehouseId:created.domesticWarehouseId??null,status:created.status,protectedAccount:created.protectedAccount}
|
||||
writeCredentials(report.subject.membershipId);save()
|
||||
save()
|
||||
if(report.subject.tenantId!=='0'||report.subject.overseasWarehouseId!==warehouseId||report.subject.status!=='ACTIVE'
|
||||
||report.subject.domesticWarehouseId!==null||report.subject.roleIds.length!==1||report.subject.roleIds[0]!==String(role.id))throw Error('CREATED_SUBJECT_SCOPE_MISMATCH')
|
||||
||report.subject.domesticWarehouseId!==null||report.subject.roleIds.length!==1||report.subject.roleIds[0]!==String(role.id))throw Error('EXISTING_SUBJECT_SCOPE_MISMATCH')
|
||||
fs.mkdirSync(path.dirname(credentialFile),{recursive:true})
|
||||
fs.writeFileSync(credentialFile,`PDA_USERNAME=${username}\nPDA_PASSWORD=${password}\nPDA_MEMBERSHIP_ID=${actor.membershipId}\n`,{flag:'wx',mode:0o600})
|
||||
pda=await call('POST','/auth/login',{loginId:username,password},'')
|
||||
if(pda.passwordChangeRequired||pda.mustChangePassword||pda.firstLogin||!pda.accessToken)throw Error('FIRST_PASSWORD_CHANGE_OR_NORMAL_LOGIN_BLOCKED')
|
||||
if(!(pda.authorities||[]).includes('lastleg:pda:operate')||!(pda.roles||[]).includes(roleCode)||(pda.roles||[]).length!==1)throw Error('NORMAL_LOGIN_ROLE_OR_PERMISSION_MISMATCH')
|
||||
const profile=await call('GET','/pda/v1/last-leg/receiving-containers/warehouse-profile',undefined,pda.accessToken)
|
||||
report.profile={warehouseId:String(profile.warehouseId),warehouseCode:profile.warehouseCode,warehouseName:profile.warehouseName}
|
||||
if(report.profile.warehouseId!==warehouseId||report.profile.warehouseCode!=='US-LAX-01')throw Error('FORMAL_WAREHOUSE_PROFILE_MISMATCH')
|
||||
report.cleanup={method:'PUT',path:`/platform/v1/iam/users/${report.subject.membershipId}/status`,body:{status:'DISABLED'},executeNow:false}
|
||||
report.cleanup={sessionLogoutOnly:true,sharedAccountStateUnchanged:true}
|
||||
report.status='ACTIVE_FOR_COORDINATOR_UI';report.loginVerified=true;report.warehouseProfileVerified=true;report.success=true
|
||||
}catch(error){report.failure=String(error.message).replace(/https?:\/\/\S+/g,'[redacted]')}
|
||||
finally{
|
||||
|
||||
Reference in New Issue
Block a user