From e95a2365f5bafa813d3bda6d86f59c07c23d6ec1 Mon Sep 17 00:00:00 2001 From: WuYongJie Date: Tue, 6 Oct 2026 16:29:20 +0800 Subject: [PATCH] =?UTF-8?q?fix(intake):=20=E5=95=86=E5=93=81=E4=BC=81?= =?UTF-8?q?=E5=88=92=E5=80=99=E9=80=89=E4=BA=BA=E6=94=B9=E4=B8=BA=E5=85=A8?= =?UTF-8?q?=E9=83=A8=E5=86=85=E9=83=A8=E4=BA=BA=E5=91=98=EF=BC=88=E5=95=86?= =?UTF-8?q?=E5=93=81=E4=BC=81=E5=88=92=E9=83=A8=E8=A7=A3=E6=95=A3=E5=90=8E?= =?UTF-8?q?=E6=90=9C=E4=B8=8D=E5=88=B0=E4=BA=BA=EF=BC=89?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- .../intake-owner-options.service.test.ts | 41 ++++++++++++++++--- .../services/intake-owner-options.service.ts | 17 +++----- 2 files changed, 42 insertions(+), 16 deletions(-) diff --git a/furniture-3d-system/src/server/services/__tests__/intake-owner-options.service.test.ts b/furniture-3d-system/src/server/services/__tests__/intake-owner-options.service.test.ts index 854b7eee..ccafba64 100644 --- a/furniture-3d-system/src/server/services/__tests__/intake-owner-options.service.test.ts +++ b/furniture-3d-system/src/server/services/__tests__/intake-owner-options.service.test.ts @@ -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']) }) }) diff --git a/furniture-3d-system/src/server/services/intake-owner-options.service.ts b/furniture-3d-system/src/server/services/intake-owner-options.service.ts index bd007f0f..eb3974d6 100644 --- a/furniture-3d-system/src/server/services/intake-owner-options.service.ts +++ b/furniture-3d-system/src/server/services/intake-owner-options.service.ts @@ -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, 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,