fix(intake): 商品企划候选人改为全部内部人员(商品企划部解散后搜不到人)

This commit is contained in:
WuYongJie 2026-10-06 16:29:20 +08:00
parent cfe8cf950c
commit e95a2365f5
2 changed files with 42 additions and 16 deletions

View File

@ -1,4 +1,5 @@
import { prisma } from '@/lib/prisma'
import { isExternalIntakeUser } from '@/lib/non-integrated-external-entry-permissions'
import { listIntakeOwnerOptionNamesByDepartmentScope } from '@/server/services/intake-owner-options.service'
jest.mock('@/lib/prisma', () => ({
@ -18,13 +19,16 @@ jest.mock('@/lib/non-integrated-external-owner-fields', () => ({
}))
const mockedFindMany = prisma.user.findMany as jest.Mock
const mockedIsExternalIntakeUser = isExternalIntakeUser as jest.Mock
describe('intake-owner-options.service', () => {
beforeEach(() => {
mockedFindMany.mockReset()
mockedIsExternalIntakeUser.mockReset()
mockedIsExternalIntakeUser.mockImplementation(() => false)
})
it('lists merchandise planning candidates from the reorganized planning department', async () => {
it('lists every internal user as merchandise planning candidate after the planning department was dissolved', async () => {
mockedFindMany.mockResolvedValue([
{
name: '企划A',
@ -75,10 +79,10 @@ describe('intake-owner-options.service', () => {
await expect(
listIntakeOwnerOptionNamesByDepartmentScope('merchandisePlanning'),
).resolves.toEqual(['企划A', '企划B', '企划C'])
).resolves.toEqual(['企划A', '企划B', '企划C', '策划A', '设计A'])
})
it('keeps legacy brand-center product planning paths as merchandise planning candidates', async () => {
it('keeps legacy brand-center product planning users as merchandise planning candidates', async () => {
mockedFindMany.mockResolvedValue([
{
name: '企划旧',
@ -96,7 +100,7 @@ describe('intake-owner-options.service', () => {
).resolves.toEqual(['企划旧'])
})
it('does not treat brand planning or lookalike departments as merchandise planning', async () => {
it('includes internal users from any department for merchandise planning', async () => {
mockedFindMany.mockResolvedValue([
{
name: '策划A',
@ -120,6 +124,33 @@ describe('intake-owner-options.service', () => {
await expect(
listIntakeOwnerOptionNamesByDepartmentScope('merchandisePlanning'),
).resolves.toEqual([])
).resolves.toEqual(['策划A', '市场企划A'])
})
it('excludes external intake users from merchandise planning candidates', async () => {
mockedIsExternalIntakeUser.mockImplementation(
(user: { name: string }) => user.name === '外部A',
)
mockedFindMany.mockResolvedValue([
{
name: '外部A',
businessRoles: ['EXTERNAL_INTAKE'],
department: null,
team: null,
},
{
name: '内部A',
businessRoles: [],
department: {
name: '产品研发部',
fullPath: '江苏简尚品牌管理有限公司 > 产品研发部',
},
team: null,
},
])
await expect(
listIntakeOwnerOptionNamesByDepartmentScope('merchandisePlanning'),
).resolves.toEqual(['内部A'])
})
})

View File

@ -28,10 +28,6 @@ function normalizeDepartmentText(value: string | null | undefined) {
return value?.replace(/\s+/g, "") ?? "";
}
function hasDepartmentSegment(text: string, segment: string) {
return text.split(">").some((part) => part.trim() === segment);
}
function departmentTextMatchesScope(
values: Array<string | null | undefined>,
scope: IntakeOwnerDepartmentScope,
@ -48,13 +44,6 @@ function departmentTextMatchesScope(
);
}
if (scope === "merchandisePlanning") {
return (
(text.includes("品牌中心") && text.includes("商品企划部")) ||
hasDepartmentSegment(text, "企划部")
);
}
if (scope === "spaceVisual") {
return text.includes("品牌中心") && text.includes("空间视觉部");
}
@ -130,6 +119,12 @@ export async function listIntakeOwnerOptionNamesByDepartmentScope(
if (isOptionExternalIntakeUser) return false;
// 商品企划部已解散(2026-10 用户口径):商品企划不再按部门圈定候选人,
// 直接开放为全部内部人员可搜索填写;外部人员已在上面排除。
if (scope === "merchandisePlanning") {
return true;
}
return departmentTextMatchesScope(
[
user.department?.name,