import { TeamDataScopeService, UserDataContext, buildLeadDataScopeFilter, assertLeadAccessPermission, } from '../../../src/modules/team/service/data-scope'; describe('Point 52: 多租户团队成员细粒度数据隔离与销售管辖范围保护', () => { let service: TeamDataScopeService; beforeEach(() => { service = new TeamDataScopeService(); }); describe('1. buildLeadDataScopeFilter (数据权限范围查询条件构建)', () => { it('租户拥有者 (owner) 与管理员 (admin) 应具备租户级全量权限', () => { const ownerCtx: UserDataContext = { userId: 1, tenantId: 'tenant-100', role: 'owner', }; const adminCtx: UserDataContext = { userId: 2, tenantId: 'tenant-100', role: 'admin', }; const ownerFilter = buildLeadDataScopeFilter(ownerCtx); expect(ownerFilter.tenantId).toBe('tenant-100'); expect(ownerFilter.assignedUserId).toBeUndefined(); // 全员无限制 expect(ownerFilter.departmentId).toBeUndefined(); const adminFilter = buildLeadDataScopeFilter(adminCtx); expect(adminFilter.tenantId).toBe('tenant-100'); expect(adminFilter.assignedUserId).toBeUndefined(); }); it('部门区域销售总监 (sales_manager) 应锁定为本部门管辖范围', () => { const managerCtx: UserDataContext = { userId: 10, tenantId: 'tenant-100', role: 'sales_manager', departmentId: 'dept-middle-east', }; const filter = buildLeadDataScopeFilter(managerCtx); expect(filter.tenantId).toBe('tenant-100'); expect(filter.departmentId).toBe('dept-middle-east'); expect(filter.assignedUserId).toBeUndefined(); }); it('一线销售 (sales_rep/member) 必须严格隔离只能查看本人线索', () => { const repCtx: UserDataContext = { userId: 88, tenantId: 'tenant-100', role: 'sales_rep', departmentId: 'dept-middle-east', }; const filter = buildLeadDataScopeFilter(repCtx); expect(filter.tenantId).toBe('tenant-100'); expect(filter.assignedUserId).toBe(88); }); }); describe('2. assertLeadAccessPermission (单条线索详情读取防越权校验)', () => { const mockLead = { id: 999, tenantId: 'tenant-100', assignedUserId: 88, departmentId: 'dept-middle-east', }; it('允许线索归属人本人 (userId=88) 访问', () => { const repCtx: UserDataContext = { userId: 88, tenantId: 'tenant-100', role: 'sales_rep', }; expect(() => assertLeadAccessPermission(repCtx, mockLead)).not.toThrow(); }); it('允许所属部门主管 (dept-middle-east) 与企业 Owner 跨权限访问', () => { const managerCtx: UserDataContext = { userId: 10, tenantId: 'tenant-100', role: 'sales_manager', departmentId: 'dept-middle-east', }; const ownerCtx: UserDataContext = { userId: 1, tenantId: 'tenant-100', role: 'owner', }; expect(() => assertLeadAccessPermission(managerCtx, mockLead)).not.toThrow(); expect(() => assertLeadAccessPermission(ownerCtx, mockLead)).not.toThrow(); }); it('同租户其他销售 (userId=89) 越权访问时应抛出 403 明确拒绝', () => { const otherRepCtx: UserDataContext = { userId: 89, tenantId: 'tenant-100', role: 'sales_rep', }; expect(() => assertLeadAccessPermission(otherRepCtx, mockLead)).toThrow( /无权访问该客户线索|Forbidden|权限不足/i ); }); it('跨租户访问应坚决阻断', () => { const crossTenantCtx: UserDataContext = { userId: 1, tenantId: 'tenant-200', // 跨租户 role: 'owner', }; expect(() => assertLeadAccessPermission(crossTenantCtx, mockLead)).toThrow( /无权访问该客户线索|Forbidden|权限不足/i ); }); }); });