chore: 保存盘点开发前改动
This commit is contained in:
92
scripts/verify-history-query-and-barcode-print.js
Normal file
92
scripts/verify-history-query-and-barcode-print.js
Normal file
@@ -0,0 +1,92 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const root = path.resolve(__dirname, '..')
|
||||
|
||||
function read(file) {
|
||||
return fs.readFileSync(path.join(root, file), 'utf8')
|
||||
}
|
||||
|
||||
function assertMatch(name, content, pattern) {
|
||||
if (!pattern.test(content)) {
|
||||
throw new Error(name)
|
||||
}
|
||||
}
|
||||
|
||||
const barcodeData = read('ruoyi-ui/src/views/bas/barcodeData/index.vue')
|
||||
assertMatch(
|
||||
'条码打印必须规范化历史条码类型值',
|
||||
barcodeData,
|
||||
/normalizeBarcodeType\s*\([\s\S]*['"]1['"]\s*:\s*['"]CODE128['"]/
|
||||
)
|
||||
assertMatch(
|
||||
'条码打印必须通过安全数值方法处理宽度和高度',
|
||||
barcodeData,
|
||||
/getBarcodeOptionNumber\s*\(/
|
||||
)
|
||||
assertMatch(
|
||||
'条码打印宽度必须使用安全数值方法',
|
||||
barcodeData,
|
||||
/const lineWidth\s*=\s*this\.getBarcodeOptionNumber/
|
||||
)
|
||||
assertMatch(
|
||||
'条码打印失败时必须显示明确错误信息',
|
||||
barcodeData,
|
||||
/生成条码打印内容失败/
|
||||
)
|
||||
|
||||
const inStockinHistory = read('ruoyi-ui/src/views/search/inStockinHistory/index.vue')
|
||||
assertMatch(
|
||||
'入库历史单据查询必须支持点击主单行加载明细',
|
||||
inStockinHistory,
|
||||
/@row-click="handleRowClick"[\s\S]*highlight-current-row/
|
||||
)
|
||||
assertMatch(
|
||||
'入库历史单据查询必须调用入库子单明细接口',
|
||||
inStockinHistory,
|
||||
/import\s+\{\s*listStockin\s*,\s*listStockinDetail\s*\}/
|
||||
)
|
||||
assertMatch(
|
||||
'入库历史单据明细必须传递父单状态以查询完成明细表',
|
||||
inStockinHistory,
|
||||
/this\.detailQueryParams\.status\s*=\s*row\.status/
|
||||
)
|
||||
assertMatch(
|
||||
'入库历史单据明细必须有独立分页查询参数',
|
||||
inStockinHistory,
|
||||
/detailQueryParams:\s*\{[\s\S]*stockinId:\s*null/
|
||||
)
|
||||
assertMatch(
|
||||
'入库历史单据明细必须调用 listStockinDetail',
|
||||
inStockinHistory,
|
||||
/listStockinDetail\(this\.detailQueryParams\)/
|
||||
)
|
||||
|
||||
const inJobFlow = read('ruoyi-ui/src/views/search/inJobFlow/index.vue')
|
||||
assertMatch(
|
||||
'入库流水查询必须支持点击主作业行加载明细',
|
||||
inJobFlow,
|
||||
/@row-click="handleRowClick"[\s\S]*highlight-current-row/
|
||||
)
|
||||
assertMatch(
|
||||
'入库流水查询必须调用子作业明细接口',
|
||||
inJobFlow,
|
||||
/import\s+\{\s*listJobdetail\s*\}/
|
||||
)
|
||||
assertMatch(
|
||||
'入库流水查询明细必须传递父任务状态以查询完成明细表',
|
||||
inJobFlow,
|
||||
/this\.detailQueryParams\.status\s*=\s*row\.status/
|
||||
)
|
||||
assertMatch(
|
||||
'入库流水查询明细必须有独立分页查询参数',
|
||||
inJobFlow,
|
||||
/detailQueryParams:\s*\{[\s\S]*jobId:\s*null/
|
||||
)
|
||||
assertMatch(
|
||||
'入库流水查询明细必须调用 listJobdetail',
|
||||
inJobFlow,
|
||||
/listJobdetail\(this\.detailQueryParams\)/
|
||||
)
|
||||
|
||||
console.log('History query and barcode print checks passed')
|
||||
119
scripts/verify-inbound-job-fixes.js
Normal file
119
scripts/verify-inbound-job-fixes.js
Normal file
@@ -0,0 +1,119 @@
|
||||
const fs = require('fs')
|
||||
const path = require('path')
|
||||
|
||||
const root = path.resolve(__dirname, '..')
|
||||
|
||||
function read(file) {
|
||||
return fs.readFileSync(path.join(root, file), 'utf8')
|
||||
}
|
||||
|
||||
function assertMatch(name, content, pattern) {
|
||||
if (!pattern.test(content)) {
|
||||
throw new Error(name)
|
||||
}
|
||||
}
|
||||
|
||||
function assertOrder(name, content, markers) {
|
||||
let cursor = -1
|
||||
for (const marker of markers) {
|
||||
const index = content.indexOf(marker)
|
||||
if (index === -1 || index <= cursor) {
|
||||
throw new Error(name)
|
||||
}
|
||||
cursor = index
|
||||
}
|
||||
}
|
||||
|
||||
const inJob = read('ruoyi-ui/src/views/in/job/index.vue')
|
||||
assertMatch(
|
||||
'入库作业页面必须加载入库任务类型字典',
|
||||
inJob,
|
||||
/dicts:\s*\[[^\]]*['"]in_job_type['"][^\]]*\]/
|
||||
)
|
||||
assertMatch(
|
||||
'任务状态列必须使用任务状态字典渲染',
|
||||
inJob,
|
||||
/label="任务状态"[\s\S]*dict\.type\.mydo_job_status[\s\S]*scope\.row\.status/
|
||||
)
|
||||
assertMatch(
|
||||
'任务类型列必须使用入库任务类型字典渲染',
|
||||
inJob,
|
||||
/label="任务类型"[\s\S]*dict\.type\.in_job_type[\s\S]*scope\.row\.inOrOut/
|
||||
)
|
||||
assertMatch(
|
||||
'手动作废和手动完成按钮必须按选中作业终态统一禁用',
|
||||
inJob,
|
||||
/:disabled="!canOperateSelectedJob"[\s\S]*:disabled="!canOperateSelectedJob"/
|
||||
)
|
||||
assertMatch(
|
||||
'终态状态必须包含已完成和已作废',
|
||||
inJob,
|
||||
/return\s+\['4',\s*'5'\]\.includes\(String\(status\)\)/
|
||||
)
|
||||
|
||||
const stationPoint = read('ruoyi-ui/src/views/bas/stationpoint/index.vue')
|
||||
assertMatch(
|
||||
'点位配置弹窗点位类型下拉必须与其他控件等宽',
|
||||
stationPoint,
|
||||
/v-model="form\.pointType"[^>]*style="width:\s*100%"/
|
||||
)
|
||||
|
||||
const bindTray = read('pda/pages/warehouse/inbound/bindTray.vue')
|
||||
assertOrder(
|
||||
'PDA 入库点位选择必须放在托盘号下面',
|
||||
bindTray,
|
||||
['<text class="form-label">仓库</text>', '<text class="form-label">托盘号</text>', '<text class="form-label">入库点位</text>']
|
||||
)
|
||||
assertMatch(
|
||||
'PDA 必须在仓库和托盘号不完整时提示先选择仓库并扫描托盘号',
|
||||
bindTray,
|
||||
/请先选择仓库和扫描托盘号/
|
||||
)
|
||||
assertMatch(
|
||||
'PDA 仓库和托盘号完整后必须提示扫描入库点位',
|
||||
bindTray,
|
||||
/请扫描入库点位/
|
||||
)
|
||||
assertMatch(
|
||||
'PDA 绑盘并生成作业成功后必须清空托盘号和已绑定物料',
|
||||
bindTray,
|
||||
/resetBindPayload\(\)[\s\S]*this\.trayCode\s*=\s*''[\s\S]*this\.items\s*=\s*\[\]/
|
||||
)
|
||||
|
||||
const pdaService = read('ruoyi-admin/src/main/java/com/ruoyi/pda/service/impl/PdaServiceImpl.java')
|
||||
assertMatch(
|
||||
'入库作业生成后必须兜底写入初始状态 1 和执行阶段 0',
|
||||
pdaService,
|
||||
/setStatus\("1"\)[\s\S]*setExecutionPhase\("0"\)/
|
||||
)
|
||||
assertMatch(
|
||||
'入库 WCS 下发成功后必须写入状态 3 和执行阶段 1',
|
||||
pdaService,
|
||||
/setStatus\("3"\)[\s\S]*setExecutionPhase\("1"\)/
|
||||
)
|
||||
assertMatch(
|
||||
'入库作业生成后必须补写仓库名称',
|
||||
pdaService,
|
||||
/selectBasWarehouseByWarehouseId[\s\S]*setWarehouseName/
|
||||
)
|
||||
|
||||
const mydoJobMapper = read('ruoyi-admin/src/main/resources/mapper/in/MydoJobMapper.xml')
|
||||
assertMatch(
|
||||
'作业列表查询必须在 warehouse_name 为空时按 warehouse_id 兜底显示仓库名称',
|
||||
mydoJobMapper,
|
||||
/isnull\(nullif\(warehouse_name,\s*''\),\s*\(select top 1 bw\.warehouse_name/
|
||||
)
|
||||
|
||||
const mydoJobService = read('ruoyi-admin/src/main/java/com/ruoyi/in/job/service/impl/MydoJobServiceImpl.java')
|
||||
assertMatch(
|
||||
'共用 WCS 推送成功后必须写入状态 3 和执行阶段 1',
|
||||
mydoJobService,
|
||||
/pushOutJobToWcs[\s\S]*setStatus\("3"\)[\s\S]*setExecutionPhase\("1"\)/
|
||||
)
|
||||
|
||||
const sql = read('sql/20260624_update_job_dicts.sql')
|
||||
assertMatch('SQL 脚本必须包含正执行状态字典', sql, /正执行/)
|
||||
assertMatch('SQL 脚本必须包含生成作业执行阶段字典', sql, /生成作业/)
|
||||
assertMatch('SQL 脚本必须包含下发到WCS执行阶段字典', sql, /下发到WCS/)
|
||||
|
||||
console.log('Inbound job fix checks passed')
|
||||
208
scripts/verify-outbound-stock-fixes.js
Normal file
208
scripts/verify-outbound-stock-fixes.js
Normal file
@@ -0,0 +1,208 @@
|
||||
const fs = require('fs');
|
||||
const path = require('path');
|
||||
|
||||
const root = path.resolve(__dirname, '..');
|
||||
|
||||
function read(relativePath) {
|
||||
return fs.readFileSync(path.join(root, relativePath), 'utf8');
|
||||
}
|
||||
|
||||
function assertContains(file, needle, message) {
|
||||
const content = read(file);
|
||||
if (!content.includes(needle)) {
|
||||
throw new Error(`${message}\nMissing in ${file}: ${needle}`);
|
||||
}
|
||||
}
|
||||
|
||||
function assertMatches(file, pattern, message) {
|
||||
const content = read(file);
|
||||
if (!pattern.test(content)) {
|
||||
throw new Error(`${message}\nPattern not found in ${file}: ${pattern}`);
|
||||
}
|
||||
}
|
||||
|
||||
assertMatches(
|
||||
'ruoyi-admin/src/main/java/com/ruoyi/bas/stock/service/impl/BasStockServiceImpl.java',
|
||||
/"KC"\s*\+\s*STOCK_ID_FORMATTER\.format/,
|
||||
'Manual stock creation must generate KC + millisecond timestamp IDs.'
|
||||
);
|
||||
|
||||
assertContains(
|
||||
'sql/bas_stock_master_detail.sql',
|
||||
"in_type",
|
||||
'Inbound completion stock generation must persist the real inbound type.'
|
||||
);
|
||||
assertMatches(
|
||||
'sql/bas_stock_master_detail.sql',
|
||||
/'KC'\s*\+\s*FORMAT\(@now,\s*'yyyyMMddHHmmssfff'\)/,
|
||||
'Inbound completion procedure must generate KC + millisecond timestamp stock IDs.'
|
||||
);
|
||||
assertContains(
|
||||
'sql/bas_stock_master_detail.sql',
|
||||
"@stock_id + N'-' + CONVERT",
|
||||
'Inbound completion stock detail IDs must use stock ID plus detail sequence.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-admin/src/main/resources/mapper/bas/BasStockDetailMapper.xml',
|
||||
'bsd.product_id, bsd.product_name',
|
||||
'Stock detail queries must keep material code and material name in separate columns.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/bas/stock/index.vue',
|
||||
'label="物料编码" align="center" prop="productId"',
|
||||
'Stock detail UI must render material code from productId.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/bas/stock/index.vue',
|
||||
'label="物料名称" align="center" prop="productName"',
|
||||
'Stock detail UI must render material name from productName.'
|
||||
);
|
||||
|
||||
const outJob = read('ruoyi-ui/src/views/out/job/index.vue');
|
||||
if (!outJob.includes('prop="status"') || !outJob.includes('dict.type.mydo_job_status')) {
|
||||
throw new Error('Outbound job page must filter/render task status with mydo_job_status.');
|
||||
}
|
||||
if (!outJob.includes('dict.type.out_job_type') || !outJob.includes("dicts: ['mydo_job_execution_phase', 'mydo_job_status', 'out_job_type']")) {
|
||||
throw new Error('Outbound job page must render task type with out_job_type.');
|
||||
}
|
||||
if (!outJob.includes("parseTime(scope.row.createTime")) {
|
||||
throw new Error('Outbound job page must render createTime from createTime, not createDate.');
|
||||
}
|
||||
if (!outJob.includes('this.detailQueryParams.status = row.status')) {
|
||||
throw new Error('Finished outbound jobs must pass parent status when loading child job details.');
|
||||
}
|
||||
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/out/stockout/index.vue',
|
||||
'selectedExitId',
|
||||
'Outbound allocation UI must require an exit selection.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/out/stockout/index.vue',
|
||||
'listStationPoint',
|
||||
'Outbound allocation UI must load warehouse exit/entry-exit station points.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/out/stockout/index.vue',
|
||||
'this.detailQueryParams.status = row.status',
|
||||
'Finished outbound bills must pass the parent status when loading child details.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-admin/src/main/java/com/ruoyi/out/stockout/domain/OutStockoutManualAssignDTO.java',
|
||||
'private String exitId;',
|
||||
'Manual outbound allocation DTO must carry the selected exit.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-admin/src/main/resources/mapper/out/OutStockoutMapper.xml',
|
||||
'#{v_exit_id,mode=IN,jdbcType=VARCHAR}',
|
||||
'Outbound allocation mapper must pass the selected exit to procedures.'
|
||||
);
|
||||
assertContains(
|
||||
'sql/out_stockout_flow.sql',
|
||||
'@v_exit_id varchar(80)',
|
||||
'Outbound allocation procedures must accept a selected exit.'
|
||||
);
|
||||
assertContains(
|
||||
'sql/out_stockout_flow.sql',
|
||||
'@exit_id = @v_exit_id',
|
||||
'Outbound allocation procedure must store the selected exit on generated jobs.'
|
||||
);
|
||||
|
||||
assertContains(
|
||||
'ruoyi-admin/src/main/java/com/ruoyi/in/job/service/impl/MydoJobServiceImpl.java',
|
||||
'requestWcsCancelBeforeManualCancel',
|
||||
'Manual job cancellation must reserve a WCS cancellation check.'
|
||||
);
|
||||
|
||||
assertContains(
|
||||
'pda/pages/warehouse/outbound/confirm.vue',
|
||||
'扫描托盘条码',
|
||||
'PDA outbound confirmation must scan tray barcodes.'
|
||||
);
|
||||
assertContains(
|
||||
'pda/pages/warehouse/outbound/confirm.vue',
|
||||
'materials',
|
||||
'PDA outbound confirmation must render tray material details.'
|
||||
);
|
||||
assertContains(
|
||||
'pda/pages/warehouse/outbound/confirm.vue',
|
||||
'v-model="item.actualQuantity"',
|
||||
'PDA outbound confirmation must capture actual outbound quantity per material.'
|
||||
);
|
||||
assertContains(
|
||||
'pda/pages/warehouse/outbound/confirm.vue',
|
||||
'materials: this.outboundInfo.materials.map',
|
||||
'PDA outbound confirmation must submit actual quantities per material.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-admin/src/main/java/com/ruoyi/pda/service/impl/PdaServiceImpl.java',
|
||||
'createReturnInboundJobIfNeeded',
|
||||
'PDA outbound confirmation must create return inbound jobs for residual tray materials.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-admin/src/main/java/com/ruoyi/pda/service/impl/PdaServiceImpl.java',
|
||||
'jobIdService.getId("HL")',
|
||||
'Residual tray return jobs must use the 回流作业 job-id prefix.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-admin/src/main/java/com/ruoyi/pda/service/impl/PdaServiceImpl.java',
|
||||
'taskNoService.getTaskNo("5")',
|
||||
'Residual tray return jobs must use the 回流入库 task-number type.'
|
||||
);
|
||||
assertContains(
|
||||
'sql/20260624_update_job_dicts.sql',
|
||||
"N'回流入库'",
|
||||
'Inbound job dictionaries must render 回流入库 return jobs.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-admin/src/main/resources/mapper/pda/PdaMapper.xml',
|
||||
'selectResidualTrayMaterials',
|
||||
'PDA mapper must query residual tray materials after outbound confirmation.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/out/locationOutbound/index.vue',
|
||||
'active-text="所有货位"',
|
||||
'Specified-location outbound filter switch must be labelled 所有货位.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/out/locationOutbound/index.vue',
|
||||
'listWarehouse',
|
||||
'Specified-location outbound page must load warehouse dropdown options.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/out/locationOutbound/index.vue',
|
||||
'v-model="queryParams.warehouseId"',
|
||||
'Specified-location outbound page must filter by warehouse id dropdown.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/out/locationOutbound/index.vue',
|
||||
'@selection-change="handleSelectionChange"',
|
||||
'Specified-location outbound table must support selecting locations.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/out/locationOutbound/index.vue',
|
||||
'批量生成作业',
|
||||
'Specified-location outbound page must provide a batch generation action.'
|
||||
);
|
||||
assertContains(
|
||||
'ruoyi-ui/src/views/out/locationOutbound/index.vue',
|
||||
'Promise.all(rows.map',
|
||||
'Specified-location outbound page must generate outbound jobs for selected locations.'
|
||||
);
|
||||
const locationOutbound = read('ruoyi-ui/src/views/out/locationOutbound/index.vue');
|
||||
if (locationOutbound.includes('type="expand"')) {
|
||||
throw new Error('Specified-location outbound page must use a lower child-detail table instead of expand rows.');
|
||||
}
|
||||
if (!locationOutbound.includes('@row-click="handleRowClick"') ||
|
||||
!locationOutbound.includes('currentLocation') ||
|
||||
!locationOutbound.includes('locationDetailList')) {
|
||||
throw new Error('Specified-location outbound page must click a parent location row and show child details below.');
|
||||
}
|
||||
if (!locationOutbound.includes('cargoSpaceId: row.cargoSpaceId')) {
|
||||
throw new Error('Specified-location outbound generation must send cargoSpaceId so empty locations can generate jobs.');
|
||||
}
|
||||
if (!locationOutbound.includes("['1', '6'].includes(String(row.cargoSpaceStatus))")) {
|
||||
throw new Error('Specified-location outbound must allow empty and no-stock abnormal locations to generate jobs.');
|
||||
}
|
||||
|
||||
console.log('Outbound and stock regression checks passed.');
|
||||
Reference in New Issue
Block a user