import { collectEmployeeOrganizationPaths, mergeDepartmentAndInheritPacks, collectOccupiedOrganizationPaths, countPeopleOnOrganizationPaths, countUniquePeopleOnOrganizationPaths, describeDepartmentGroupStatus, findNearestGroupMemberships, findOrganizationPermissionStorageKey, isUnderOrganizationPath, normalizeOrganizationPath, organizationPathChain, parseOrganizationDepartmentIds, personBelongsToOrganizationPath, pruneOrganizationTree, resolveEmployeeOrganizationPaths, resolveOrganizationPermissionKey, unionPermissionPacks, } from '@/lib/organization-material-permissions' describe('organization material permission keys', () => { test('path chain goes from company to leaf', () => { expect( organizationPathChain('江苏简尚品牌管理有限公司/运营中心A/事业一部/品类十九部'), ).toEqual([ '江苏简尚品牌管理有限公司', '江苏简尚品牌管理有限公司/运营中心A', '江苏简尚品牌管理有限公司/运营中心A/事业一部', '江苏简尚品牌管理有限公司/运营中心A/事业一部/品类十九部', ]) }) test('own path config wins over legacy short names', () => { expect( findOrganizationPermissionStorageKey('江苏简尚品牌管理有限公司/运营中心A', [ '运营中心', '江苏简尚品牌管理有限公司/运营中心A', ]), ).toEqual({ key: '江苏简尚品牌管理有限公司/运营中心A', source: 'own', }) }) test('运营中心A can reuse the old 运营中心 pack', () => { expect( findOrganizationPermissionStorageKey('江苏简尚品牌管理有限公司/运营中心A', ['运营中心']), ).toEqual({ key: '运营中心', source: 'legacy', }) }) test('策划中心 and 摄影中心 use the old 视觉中心 pack even if they have their own rows', () => { expect( findOrganizationPermissionStorageKey('江苏简尚品牌管理有限公司/策划中心', [ '策划中心', '摄影中心', '视觉中心', ]), ).toEqual({ key: '视觉中心', source: 'legacy', }) expect( findOrganizationPermissionStorageKey('江苏简尚品牌管理有限公司/摄影中心', [ '策划中心', '摄影中心', '视觉中心', ]), ).toEqual({ key: '视觉中心', source: 'legacy', }) }) test('卓禾运营 and 朴美运营 reuse the old 运营中心 pack', () => { expect( findOrganizationPermissionStorageKey('江苏简尚品牌管理有限公司/运营中心A/卓禾运营', ['运营中心']), ).toEqual({ key: '运营中心', source: 'legacy', }) expect( findOrganizationPermissionStorageKey('江苏简尚品牌管理有限公司/运营中心B/朴美运营', ['运营中心']), ).toEqual({ key: '运营中心', source: 'legacy', }) }) test('品牌中心 subtree uses the old 视觉中心 pack', () => { expect( findOrganizationPermissionStorageKey( '江苏简尚品牌管理有限公司/品牌中心/品牌创意A部', ['视觉中心'], ), ).toEqual({ key: '视觉中心', source: 'legacy', }) expect( resolveOrganizationPermissionKey( '江苏简尚品牌管理有限公司/品牌中心/商品企划部/桌类', ['视觉中心'], ), ).toEqual({ key: '视觉中心', source: 'inherit', inheritFrom: '江苏简尚品牌管理有限公司/品牌中心/商品企划部', }) }) test('employee org paths follow roster primary, extra posts and department ids', () => { const company = '江苏简尚品牌管理有限公司' const brand = `${company}/品牌中心` const ops = `${company}/运营中心G` const lookup = new Map([ ['2', brand], ['9', ops], ]) expect( resolveEmployeeOrganizationPaths( { departmentPath: brand, departmentMemberships: [{ sourceDeptId: '9', departmentPath: ops }], sourcePayload: { syncedFields: { departmentIds: '[2,9]' } }, }, lookup, ), ).toEqual([brand, ops]) expect(resolveEmployeeOrganizationPaths(null, lookup)).toEqual([]) }) test('permission tree drops revoked empty branches but keeps occupied ancestors', () => { const occupied = collectOccupiedOrganizationPaths([ '江苏简尚品牌管理有限公司/运营中心A/事业一部/品类十九部', ]) const pruned = pruneOrganizationTree( [ { path: '江苏简尚品牌管理有限公司', children: [ { path: '江苏简尚品牌管理有限公司/广州项目组', children: [{ path: '江苏简尚品牌管理有限公司/广州项目组/A组', children: [] }], }, { path: '江苏简尚品牌管理有限公司/运营中心A', children: [ { path: '江苏简尚品牌管理有限公司/运营中心A/事业一部', children: [ { path: '江苏简尚品牌管理有限公司/运营中心A/事业一部/品类十九部', children: [] }, ], }, ], }, ], }, ], occupied, ) expect(pruned).toHaveLength(1) expect(pruned[0].children.map((node) => node.path)).toEqual([ '江苏简尚品牌管理有限公司/运营中心A', ]) expect(pruned[0].children[0].children[0].children.map((node) => node.path)).toEqual([ '江苏简尚品牌管理有限公司/运营中心A/事业一部/品类十九部', ]) }) test('leaf without own rows inherits the parent pack', () => { expect( resolveOrganizationPermissionKey( '江苏简尚品牌管理有限公司/运营中心A/事业一部/品类十九部', ['运营中心'], ), ).toEqual({ key: '运营中心', source: 'inherit', inheritFrom: '江苏简尚品牌管理有限公司/运营中心A', }) }) }) describe('organization people counts', () => { const company = '江苏简尚品牌管理有限公司' const planning = `${company}/品牌中心/商品企划部` const shelf = `${planning}/架类` const support = `${company}/业务支持` const visual = `${support}/视觉支持` test('normalize keeps the original path, it does not join the prefix chain', () => { expect(normalizeOrganizationPath(` ${company}/ 总经理室 / `)).toBe(`${company}/总经理室`) }) test('a person belongs to their own dept and every ancestor, not a sibling', () => { expect(isUnderOrganizationPath(shelf, planning)).toBe(true) expect(isUnderOrganizationPath(shelf, company)).toBe(true) expect(isUnderOrganizationPath(planning, planning)).toBe(true) expect(isUnderOrganizationPath(planning, shelf)).toBe(false) expect(isUnderOrganizationPath(visual, planning)).toBe(false) expect(isUnderOrganizationPath(null, planning)).toBe(false) }) test('tree numbers count each person once per ancestor, never roll children up again', () => { const counts = countPeopleOnOrganizationPaths([shelf, visual, `${company}/人力行政中心`]) expect(counts.get(company)).toBe(3) expect(counts.get(`${company}/品牌中心`)).toBe(1) expect(counts.get(planning)).toBe(1) expect(counts.get(shelf)).toBe(1) expect(counts.get(support)).toBe(1) expect(counts.get(visual)).toBe(1) expect(counts.get(`${company}/人力行政中心`)).toBe(1) }) test('clicking 商品企划部 includes the person sitting in 架类', () => { const people = [ { name: '涂涂', departmentPath: shelf }, { name: '香樟', departmentPath: `${company}/品牌中心/品牌设计部` }, ] expect( people.filter((person) => isUnderOrganizationPath(person.departmentPath, planning)).map((p) => p.name), ).toEqual(['涂涂']) }) test('一人兼多个部门时,每个部门名单都有他,公司人数仍只计一次', () => { const office = `${company}/总经理室` const brand = `${company}/品牌中心` const ops = `${company}/运营中心G` const jiangling = collectEmployeeOrganizationPaths([office, brand, ops, office]) expect(jiangling).toEqual([office, brand, ops]) expect(personBelongsToOrganizationPath(jiangling, brand)).toBe(true) expect(personBelongsToOrganizationPath(jiangling, office)).toBe(true) expect(personBelongsToOrganizationPath(jiangling, `${company}/运营中心A`)).toBe(false) const counts = countUniquePeopleOnOrganizationPaths([ jiangling, [`${company}/人力行政中心`], ]) expect(counts.get(company)).toBe(2) expect(counts.get(brand)).toBe(1) expect(counts.get(office)).toBe(1) expect(counts.get(`${company}/人力行政中心`)).toBe(1) }) test('只保留最深任职,上级部门不另算一个职位', () => { expect( collectEmployeeOrganizationPaths([ `${company}/品牌中心`, `${company}/品牌中心/品牌创意A部`, `${company}/品牌中心`, ]), ).toEqual([`${company}/品牌中心/品牌创意A部`]) }) test('从自己往上找最近的权限组,一个部门只进一组', () => { const leaf = `${company}/运营中心A/事业一部/品类十九部` const ops = `${company}/运营中心A` const memberships = [ { departmentPath: ops, slug: 'operations', name: '运营' }, { departmentPath: company, slug: 'all', name: '全员' }, ] expect(findNearestGroupMemberships(leaf, memberships)).toEqual({ attachedPath: ops, items: [{ departmentPath: ops, slug: 'operations', name: '运营' }], }) expect(findNearestGroupMemberships(`${company}/财务中心`, memberships)).toEqual({ attachedPath: company, items: [{ departmentPath: company, slug: 'all', name: '全员' }], }) expect(findNearestGroupMemberships(`${company}/人力行政中心`, [])).toBeNull() }) test('分配部门时标明已在本组、已在别组、随上级或未进组', () => { const ops = `${company}/运营中心A` const leaf = `${company}/运营中心A/事业一部/品类十九部` const memberships = [{ departmentPath: ops, slug: 'operations', name: '运营' }] expect(describeDepartmentGroupStatus(ops, 'operations', memberships)).toMatchObject({ kind: 'own', label: '已在本组', }) expect(describeDepartmentGroupStatus(ops, 'visual', memberships)).toMatchObject({ kind: 'other', label: '已在「运营」', }) expect(describeDepartmentGroupStatus(leaf, 'visual', memberships)).toMatchObject({ kind: 'inherit', label: '随 运营中心A · 运营', }) expect(describeDepartmentGroupStatus(`${company}/财务中心`, 'visual', memberships)).toMatchObject({ kind: 'none', label: '未进组', }) }) test('多组合并时允许的取并集,不允许的不会把别组已经给的拿掉', () => { const merged = unionPermissionPacks( { '3D场景': { canView: true, canDownload: true, canDownloadSource: false, canShare: true, canEditAssets: false }, }, { '3D场景': { canView: false, canDownload: false, canDownloadSource: false, canShare: true, canEditAssets: false }, 详情模板: { canView: true, canDownload: true, canDownloadSource: true, canShare: true, canEditAssets: false }, }, { 详情模板: { canView: true, canDownload: false, canDownloadSource: false, canShare: true, canEditAssets: false }, }, ) expect(merged['3D场景']).toEqual({ canView: true, canDownload: true, canDownloadSource: false, canShare: true, canEditAssets: false, }) expect(merged['详情模板']).toEqual({ canView: true, canDownload: true, canDownloadSource: true, canShare: true, canEditAssets: false, }) }) test('用户继承叠在部门权限上,能给的加上,不能把部门已有的拿掉', () => { const merged = mergeDepartmentAndInheritPacks( { '3D场景': { canView: true, canDownload: true, canDownloadSource: false, canShare: true, canEditAssets: false }, '任务-详情': { canView: true, canDownload: false, canDownloadSource: false, canShare: true, canEditAssets: false }, }, { '3D场景': { canView: false, canDownload: false, canDownloadSource: false, canShare: true, canEditAssets: false }, 详情模板: { canView: true, canDownload: true, canDownloadSource: true, canShare: true, canEditAssets: false }, }, ) expect(merged['3D场景']).toEqual({ canView: true, canDownload: true, canDownloadSource: false, canShare: true, canEditAssets: false, }) expect(merged['任务-详情']?.canDownload).toBe(false) expect(merged['详情模板']).toEqual({ canView: true, canDownload: true, canDownloadSource: true, canShare: true, canEditAssets: false, }) }) test('花名册部门 ID 列表会拆出全部任职部门', () => { expect(parseOrganizationDepartmentIds('[22787301,909676348]')).toEqual(['22787301', '909676348']) expect(parseOrganizationDepartmentIds('22802296|911666246|32221130')).toEqual([ '22802296', '911666246', '32221130', ]) }) })