fix(users): 排除非内部部门自动业务划归

This commit is contained in:
WuYongJie 2026-05-28 12:01:49 +08:00
parent 6558ba763b
commit f6eba0418f
4 changed files with 103 additions and 61 deletions

View File

@ -0,0 +1,49 @@
import { inferBusinessRolesFromDepartmentPath } from './business-role-inference'
describe('business-role-inference', () => {
it('业务支持、快递、供应商、龙晨品牌中心不自动划归内部业务类型', () => {
const paths = [
'江苏简尚品牌管理有限公司 > 业务支持 > 外协支持',
'江苏简尚品牌管理有限公司 > 快递 > 华东快递',
'江苏简尚品牌管理有限公司 > 快递公司 > 常州快递',
'江苏简尚品牌管理有限公司 > 供应商 > 常州区域 > 常州十四区',
'江苏简尚品牌管理有限公司 > 龙晨品牌中心 > 供应链中心(江苏简尚品牌管理有限公司 > 龙晨品牌中心)',
'江苏简尚品牌管理有限公司 > 龙晨品牌中心 > 营销策划中心',
]
paths.forEach((path) => {
expect(inferBusinessRolesFromDepartmentPath(path)).toMatchObject({
businessRoles: [],
excluded: true,
shouldWarnWhenEmpty: false,
})
expect(inferBusinessRolesFromDepartmentPath(path).reason).toContain('不属于内部人员')
})
})
it('内部业务部门继续自动划归业务类型', () => {
expect(
inferBusinessRolesFromDepartmentPath(
'江苏简尚品牌管理有限公司 > 供应链中心 > 基本盘 采购部 > 采购二部',
).businessRoles,
).toEqual(['PURCHASING'])
expect(
inferBusinessRolesFromDepartmentPath(
'江苏简尚品牌管理有限公司 > 产品研发部 > 基本盘 > 桌类组',
).businessRoles,
).toEqual(['DESIGN'])
expect(
inferBusinessRolesFromDepartmentPath(
'江苏简尚品牌管理有限公司 > 品牌中心 > 空间视觉部',
).businessRoles,
).toEqual(['DESIGN'])
expect(
inferBusinessRolesFromDepartmentPath(
'江苏简尚品牌管理有限公司 > 品牌中心 > 商品企划部',
).businessRoles,
).toEqual(['PLANNING'])
})
})

View File

@ -15,25 +15,20 @@ const EXCLUDED_ROOTS = new Set([
'直播中心',
'商务中心',
'分销部',
'业务支持',
'公共视觉部',
'经营管理中心',
'摄影中心',
'广州项目组',
'摄影需求',
'快递公司',
'人力行政中心',
'外部交流',
])
const LONGCHEN_EXCLUDED_CHILDREN = [
/^客服中心/,
/^财务中心/,
/^运营中心/,
/^总经理室/,
/^直播中心/,
/^商务中心/,
]
const NON_INTERNAL_ROOTS = new Set([
'业务支持',
'供应商',
'龙晨品牌中心',
])
function splitDepartmentPath(fullPath: string | null | undefined): string[] {
return String(fullPath ?? '')
@ -62,12 +57,16 @@ function uniqRoles(roles: BusinessAccountType[]): BusinessAccountType[] {
return [...new Set(roles)]
}
export function isNonInternalDepartmentRoot(root: string | null | undefined): boolean {
const normalizedRoot = String(root ?? '').trim()
return NON_INTERNAL_ROOTS.has(normalizedRoot) || /^快递/.test(normalizedRoot)
}
export function inferBusinessRolesFromDepartmentPath(
fullPath: string | null | undefined,
): BusinessRoleInferenceResult {
const parts = getBusinessParts(fullPath)
const root = parts[0] ?? ''
const child = parts[1] ?? ''
if (!root) {
return {
@ -87,6 +86,15 @@ export function inferBusinessRolesFromDepartmentPath(
}
}
if (isNonInternalDepartmentRoot(root)) {
return {
businessRoles: [],
excluded: true,
shouldWarnWhenEmpty: false,
reason: `${root} 不属于内部人员,不参与业务类型`,
}
}
if (EXCLUDED_ROOTS.has(root) || /^运营中心/.test(root) || /^效率部/.test(root)) {
return {
businessRoles: [],
@ -96,51 +104,6 @@ export function inferBusinessRolesFromDepartmentPath(
}
}
if (root === '龙晨品牌中心') {
if (LONGCHEN_EXCLUDED_CHILDREN.some((pattern) => pattern.test(child))) {
return {
businessRoles: [],
excluded: true,
shouldWarnWhenEmpty: false,
reason: `龙晨品牌中心 > ${child} 不参与业务类型`,
}
}
if (/^供应链中心/.test(child)) {
return {
businessRoles: ['PURCHASING'],
excluded: false,
shouldWarnWhenEmpty: true,
reason: '龙晨品牌中心供应链节点默认归采购',
}
}
if (/^营销策划中心/.test(child)) {
return {
businessRoles: ['PLANNING'],
excluded: false,
shouldWarnWhenEmpty: true,
reason: '龙晨品牌中心营销策划节点默认归企划',
}
}
return {
businessRoles: [],
excluded: false,
shouldWarnWhenEmpty: true,
reason: '龙晨品牌中心需要按内部节点确认业务类型',
}
}
if (root === '供应商') {
return {
businessRoles: ['SUPPLIER'],
excluded: false,
shouldWarnWhenEmpty: true,
reason: '供应商节点默认归供应商',
}
}
if (root === '仓储中心') {
return {
businessRoles: ['WAREHOUSE'],

View File

@ -51,4 +51,31 @@ describe('primary-department', () => {
]),
).toBe('finance-1')
})
it('业务支持、快递、供应商、龙晨品牌中心不会压过可确认的内部部门', () => {
expect(
choosePrimaryDepartmentExternalId(['supplier-1', 'longchen-1', 'express-1', 'business-1', 'unknown-1'], [
{
externalId: 'supplier-1',
fullPath: '江苏简尚品牌管理有限公司 > 供应商 > 常州区域 > 常州十四区',
},
{
externalId: 'longchen-1',
fullPath: '江苏简尚品牌管理有限公司 > 龙晨品牌中心 > 供应链中心',
},
{
externalId: 'express-1',
fullPath: '江苏简尚品牌管理有限公司 > 快递 > 华东快递',
},
{
externalId: 'business-1',
fullPath: '江苏简尚品牌管理有限公司 > 业务支持 > 外协支持',
},
{
externalId: 'unknown-1',
fullPath: '江苏简尚品牌管理有限公司 > 未映射内部部门',
},
]),
).toBe('unknown-1')
})
})

View File

@ -1,4 +1,7 @@
import { inferBusinessRolesFromDepartmentPath } from '@/lib/business-role-inference'
import {
inferBusinessRolesFromDepartmentPath,
isNonInternalDepartmentRoot,
} from '@/lib/business-role-inference'
export interface DepartmentPathCandidate {
externalId: string
@ -49,12 +52,12 @@ function scoreDepartment(fullPath: string | null | undefined): number {
const root = getBusinessRoot(fullPath)
const inference = inferBusinessRolesFromDepartmentPath(fullPath)
const hasInternalRole = inference.businessRoles.some((role) => role !== 'SUPPLIER')
const isSupplierRoot = root === '供应商'
const isNonInternalRoot = isNonInternalDepartmentRoot(root)
if (hasInternalRole) return 500
if (root && !isSupplierRoot && inference.excluded) return 300
if (root && !isSupplierRoot && !inference.excluded) return 400
if (inference.businessRoles.includes('SUPPLIER')) return 200
if (root && !isNonInternalRoot && !inference.excluded) return 400
if (root && !isNonInternalRoot && inference.excluded) return 300
if (isNonInternalRoot) return 200
if (!inference.excluded) return 100
return 0
}