Merge origin/codex/xuxiake-mainline into codex/local-3001-integration
This commit is contained in:
commit
8a10b7f72f
@ -29,7 +29,7 @@ function jstWarehouse(
|
||||
name: string
|
||||
wmsCoId: number | null
|
||||
isMain: boolean
|
||||
attribute: string | null
|
||||
attribute?: string | null
|
||||
createdAt?: string | null
|
||||
updatedAt?: string | null
|
||||
status?: string | null
|
||||
@ -54,10 +54,6 @@ function repository(
|
||||
}
|
||||
}
|
||||
|
||||
function jstWarehouse(records: Array<{ name: string; wmsCoId: number | null; isMain: boolean; status?: string | null }> = []) {
|
||||
return { listWarehouses: jest.fn().mockResolvedValue(records) }
|
||||
}
|
||||
|
||||
describe('SupplyChainProductArchiveWarehouseConfigService', () => {
|
||||
it('infers ownership from the storage type and the warehouse name', () => {
|
||||
// 名称含「工厂-」「配件-」→ 工厂
|
||||
@ -70,39 +66,48 @@ describe('SupplyChainProductArchiveWarehouseConfigService', () => {
|
||||
expect(inferProductArchiveWarehouseOwnership('横林二仓')).toBe('JIANSHANG')
|
||||
})
|
||||
|
||||
it('combines archive warehouse names with saved configurations', async () => {
|
||||
it('lists only warehouses that exist in the jst warehouse master', async () => {
|
||||
const service = new SupplyChainProductArchiveWarehouseConfigService(repository({
|
||||
warehouseNames: ['杭州仓', '上海仓'],
|
||||
warehouseNames: ['上海仓', '北京仓'],
|
||||
configurations: [configuration()],
|
||||
}), jstWarehouse())
|
||||
}), jstWarehouse([
|
||||
{ name: '杭州仓', wmsCoId: 11, isMain: false },
|
||||
]))
|
||||
|
||||
const result = await service.list({})
|
||||
|
||||
expect(result.items).toEqual([
|
||||
expect.objectContaining({
|
||||
id: null,
|
||||
warehouseName: '上海仓',
|
||||
// 未配置的仓库按名称给默认值:不含「代发」= 入库
|
||||
storageType: 'INBOUND',
|
||||
status: null,
|
||||
configured: false,
|
||||
}),
|
||||
expect.objectContaining({
|
||||
id: 'config-1',
|
||||
warehouseName: '杭州仓',
|
||||
storageType: 'INBOUND',
|
||||
status: 'ACTIVE',
|
||||
configured: true,
|
||||
}),
|
||||
])
|
||||
// 档案历史名称与配置表里聚水潭查无此仓的条目都不展示。
|
||||
expect(result.items.map((item) => item.warehouseName)).toEqual(['杭州仓'])
|
||||
expect(result.items[0]).toEqual(expect.objectContaining({
|
||||
id: 'config-1',
|
||||
warehouseName: '杭州仓',
|
||||
storageType: 'INBOUND',
|
||||
status: 'ACTIVE',
|
||||
configured: true,
|
||||
}))
|
||||
expect(result.pageInfo.total).toBe(1)
|
||||
})
|
||||
|
||||
it('falls back to archive warehouse names when the jst master read fails', async () => {
|
||||
const service = new SupplyChainProductArchiveWarehouseConfigService(repository({
|
||||
warehouseNames: ['上海仓'],
|
||||
configurations: [configuration()],
|
||||
}), { listWarehouses: jest.fn().mockRejectedValue(new Error('source down')) })
|
||||
|
||||
const result = await service.list({})
|
||||
|
||||
// 聚水潭读取失败时降级为旧行为:档案历史名称兜底,配置照常展示,避免整页空白。
|
||||
expect(result.items.map((item) => item.warehouseName)).toEqual(['上海仓', '杭州仓'])
|
||||
expect(result.pageInfo.total).toBe(2)
|
||||
})
|
||||
|
||||
it('matches saved configurations to archive warehouses ignoring case and spaces', async () => {
|
||||
it('matches saved configurations to jst warehouses ignoring case and spaces', async () => {
|
||||
const service = new SupplyChainProductArchiveWarehouseConfigService(repository({
|
||||
warehouseNames: [' HangZhou '],
|
||||
warehouseNames: ['历史仓'],
|
||||
configurations: [configuration({ warehouseName: 'hangzhou' })],
|
||||
}), jstWarehouse())
|
||||
}), jstWarehouse([
|
||||
{ name: ' HangZhou ', wmsCoId: 11, isMain: false },
|
||||
]))
|
||||
|
||||
const result = await service.list({})
|
||||
|
||||
@ -111,14 +116,19 @@ describe('SupplyChainProductArchiveWarehouseConfigService', () => {
|
||||
id: 'config-1',
|
||||
warehouseName: 'hangzhou',
|
||||
configured: true,
|
||||
}), jstWarehouse())
|
||||
wmsCoId: 11,
|
||||
}))
|
||||
})
|
||||
|
||||
it('can filter to unconfigured warehouse names before pagination', async () => {
|
||||
const service = new SupplyChainProductArchiveWarehouseConfigService(repository({
|
||||
warehouseNames: ['杭州仓', '上海仓', '北京仓'],
|
||||
warehouseNames: ['历史仓'],
|
||||
configurations: [configuration()],
|
||||
}), jstWarehouse())
|
||||
}), jstWarehouse([
|
||||
{ name: '杭州仓', wmsCoId: 11, isMain: false },
|
||||
{ name: '上海仓', wmsCoId: 22, isMain: false },
|
||||
{ name: '北京仓', wmsCoId: 33, isMain: false },
|
||||
]))
|
||||
|
||||
const result = await service.list({ status: 'UNCONFIGURED', page: 1, pageSize: 1 })
|
||||
|
||||
@ -129,9 +139,12 @@ describe('SupplyChainProductArchiveWarehouseConfigService', () => {
|
||||
|
||||
it('filters by config status codes and source status text together', async () => {
|
||||
const service = new SupplyChainProductArchiveWarehouseConfigService(repository({
|
||||
warehouseNames: ['杭州仓', '上海仓'],
|
||||
warehouseNames: [],
|
||||
configurations: [configuration({ status: 'INACTIVE' })],
|
||||
}), jstWarehouse())
|
||||
}), jstWarehouse([
|
||||
{ name: '杭州仓', wmsCoId: 11, isMain: false },
|
||||
{ name: '上海仓', wmsCoId: 22, isMain: false },
|
||||
]))
|
||||
|
||||
// 配置状态多选:表头下拉的 启用/停用/未配置 走这一支。
|
||||
expect((await service.list({ statuses: ['ACTIVE'] })).items).toHaveLength(0)
|
||||
@ -145,9 +158,12 @@ describe('SupplyChainProductArchiveWarehouseConfigService', () => {
|
||||
|
||||
it('shows inferred ownership for unconfigured warehouse rows', async () => {
|
||||
const service = new SupplyChainProductArchiveWarehouseConfigService(repository({
|
||||
warehouseNames: ['工厂-常州仓', '横林二仓'],
|
||||
warehouseNames: [],
|
||||
configurations: [],
|
||||
}), jstWarehouse())
|
||||
}), jstWarehouse([
|
||||
{ name: '工厂-常州仓', wmsCoId: 11, isMain: false },
|
||||
{ name: '横林二仓', wmsCoId: 22, isMain: false },
|
||||
]))
|
||||
|
||||
const result = await service.list({})
|
||||
|
||||
@ -162,9 +178,12 @@ describe('SupplyChainProductArchiveWarehouseConfigService', () => {
|
||||
|
||||
it('defaults the inbound/dropship flag from the warehouse name', async () => {
|
||||
const service = new SupplyChainProductArchiveWarehouseConfigService(repository({
|
||||
warehouseNames: ['工厂-常州博一代发仓', '简尚-横林三仓'],
|
||||
warehouseNames: [],
|
||||
configurations: [],
|
||||
}), jstWarehouse())
|
||||
}), jstWarehouse([
|
||||
{ name: '工厂-常州博一代发仓', wmsCoId: 11, isMain: false },
|
||||
{ name: '简尚-横林三仓', wmsCoId: 22, isMain: false },
|
||||
]))
|
||||
|
||||
const result = await service.list({})
|
||||
const byName = new Map(result.items.map((item) => [item.warehouseName, item]))
|
||||
@ -217,6 +236,7 @@ describe('SupplyChainProductArchiveWarehouseConfigService', () => {
|
||||
},
|
||||
jstWarehouse([
|
||||
{ name: '工厂-常州博一代发仓', wmsCoId: 1, isMain: false, attribute: null },
|
||||
{ name: '杭州仓', wmsCoId: 2, isMain: false, attribute: null },
|
||||
]),
|
||||
)
|
||||
|
||||
|
||||
@ -243,15 +243,15 @@ export class SupplyChainProductArchiveWarehouseConfigService {
|
||||
) {}
|
||||
|
||||
/**
|
||||
* 仓库名称以聚水潭仓库档案(jst_warehouseInfo.name)为准,
|
||||
* 读取失败时不阻断页面,退回到产品档案里的仓库名。
|
||||
* 仓库名称只取聚水潭仓库档案(jst_warehouseInfo.name)。
|
||||
* 读取失败时返回 null:调用方降级为产品档案历史名称兜底,避免数据源抖动把整页清空。
|
||||
*/
|
||||
private async loadJstWarehouses(): Promise<JstWarehouseRecord[]> {
|
||||
private async loadJstWarehouses(): Promise<JstWarehouseRecord[] | null> {
|
||||
try {
|
||||
return await this.jstWarehouse.listWarehouses()
|
||||
} catch (cause) {
|
||||
console.error('[warehouse-config] jst warehouse read failed', cause)
|
||||
return []
|
||||
return null
|
||||
}
|
||||
}
|
||||
|
||||
@ -262,7 +262,7 @@ export class SupplyChainProductArchiveWarehouseConfigService {
|
||||
async refreshWarehouseSource() {
|
||||
this.jstWarehouse.invalidateCache()
|
||||
const warehouses = await this.loadJstWarehouses()
|
||||
return { warehouseCount: warehouses.length }
|
||||
return { warehouseCount: (warehouses ?? []).length }
|
||||
}
|
||||
|
||||
/** 产品档案的仓库→采购对照,用于工厂仓的默认负责人;读取失败不影响页面。 */
|
||||
@ -324,7 +324,7 @@ export class SupplyChainProductArchiveWarehouseConfigService {
|
||||
attribute: string | null
|
||||
status: string | null
|
||||
}>()
|
||||
for (const warehouse of jstWarehouses) {
|
||||
for (const warehouse of jstWarehouses ?? []) {
|
||||
options.set(normalizeWarehouseName(warehouse.name), {
|
||||
name: warehouse.name,
|
||||
wmsCoId: warehouse.wmsCoId,
|
||||
@ -386,7 +386,7 @@ export class SupplyChainProductArchiveWarehouseConfigService {
|
||||
this.loadPurchaserByWarehouse(),
|
||||
])
|
||||
const jstWarehouseByName = new Map(
|
||||
jstWarehouses.map((warehouse) => [normalizeWarehouseName(warehouse.name), warehouse]),
|
||||
(jstWarehouses ?? []).map((warehouse) => [normalizeWarehouseName(warehouse.name), warehouse]),
|
||||
)
|
||||
const statuses = input.statuses ?? []
|
||||
const ownerships = input.ownerships ?? []
|
||||
@ -398,16 +398,19 @@ export class SupplyChainProductArchiveWarehouseConfigService {
|
||||
const createdDates = input.createdDates ?? []
|
||||
const updatedDates = input.updatedDates ?? []
|
||||
const merged = new Map<string, WarehouseConfigDTO>()
|
||||
// 仓库名称以聚水潭仓库档案为准,产品档案里的历史名称作为补充保留。
|
||||
for (const warehouseName of [
|
||||
...jstWarehouses.map((warehouse) => warehouse.name),
|
||||
...result.warehouseNames,
|
||||
]) {
|
||||
// 仓库名称只取聚水潭仓库档案;产品档案里的历史名称聚水潭查无此仓,不再展示。
|
||||
// 聚水潭读取失败时降级为档案历史名称兜底,避免数据源抖动把整页清空。
|
||||
for (const warehouseName of jstWarehouses === null
|
||||
? result.warehouseNames
|
||||
: jstWarehouses.map((warehouse) => warehouse.name)) {
|
||||
const key = normalizeWarehouseName(warehouseName)
|
||||
if (key && !merged.has(key)) merged.set(key, mapUnconfigured(warehouseName))
|
||||
}
|
||||
for (const configuration of result.configurations) {
|
||||
merged.set(normalizeWarehouseName(configuration.warehouseName), mapRecord(configuration))
|
||||
const key = normalizeWarehouseName(configuration.warehouseName)
|
||||
// 以聚水潭档案为基准时,配置表里聚水潭查无此仓的条目同样不展示。
|
||||
if (jstWarehouses !== null && !jstWarehouseByName.has(key)) continue
|
||||
merged.set(key, mapRecord(configuration))
|
||||
}
|
||||
// 仓库编号与仓库属性统一以聚水潭仓库档案为准,配置表里不重复存一份。
|
||||
for (const [key, item] of merged) {
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user