fix(crm): honor open data scopes and role assignees

Unset sections on a saved role policy were still filtered as own-only, so full lead access showed nothing. Activities can now be assigned by org role, and the Tahesab sales report reads as a result instead of a tag wall.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
2026-10-27 18:07:42 +03:30
co-authored by Cursor
parent 8ae6a928f4
commit 9812e4e5ba
8 changed files with 549 additions and 114 deletions
+5
View File
@@ -62,6 +62,11 @@ export function resolveSectionAccess(
if (rolePolicy[sectionKey]) {
return { section: rolePolicy[sectionKey]!, source: 'role' };
}
// فرم محدودهٔ نقش، بخشِ ننوشته را «بدون محدودیت» نشان می‌دهد.
// اگر نقش حتی یک بخش ذخیره کرده باشد، بقیه نباید به دید قدیمی own/team برگردند.
if (Object.keys(rolePolicy).length > 0) {
return { section: { mode: 'all', rules: [] }, source: 'role' };
}
if (input.legacyVisibility != null || input.legacyScopes) {
return {
section: migrateVisibilityToSectionAccess(
+55
View File
@@ -1,5 +1,6 @@
import { describe, it } from 'node:test';
import assert from 'node:assert/strict';
import { leadsDeepWhere, resolveSectionAccess } from '../src/common/data-access';
import {
noteAccessWhere,
normalizeDataVisibility,
@@ -67,3 +68,57 @@ describe('سطح دسترسی به پرونده‌ها', () => {
assert.equal(normalizeDataVisibility('weird'), 'own');
});
});
describe('عمق داده وقتی نقش فقط بعضی بخش‌ها را ذخیره کرده', () => {
const legacyOwn = {
role: 'sales',
legacyVisibility: 'own' as const,
legacyScopes: {},
};
it('بخش ننوشتهٔ نقشِ تنظیم‌شده بدون محدودیت است، نه فقط مسئول خودش', () => {
const leads = resolveSectionAccess('leads', {
...legacyOwn,
rolePolicy: { customers: { mode: 'rules', rules: [] } },
override: {},
});
assert.equal(leads.source, 'role');
assert.deepEqual(leads.section, { mode: 'all', rules: [] });
assert.deepEqual(
leadsDeepWhere({ userId: 'u1', role: 'sales', leadsAccess: leads.section, teamPeerIds: null }),
{},
);
});
it('نقش بدون سیاست جدید همچنان دید قدیمی را نگه می‌دارد', () => {
const leads = resolveSectionAccess('leads', {
...legacyOwn,
rolePolicy: {},
override: {},
});
assert.deepEqual(leads.section, { mode: 'rules', rules: [{ owners: ['self'] }] });
assert.deepEqual(
leadsDeepWhere({ userId: 'u1', role: 'sales', leadsAccess: leads.section, teamPeerIds: null }),
{ assigneeId: 'u1' },
);
});
it('override کاربر بر بخش باز نقش اولویت دارد', () => {
const leads = resolveSectionAccess('leads', {
...legacyOwn,
rolePolicy: { customers: { mode: 'all', rules: [] } },
override: { leads: { mode: 'rules', rules: [{ owners: ['self'] }] } },
});
assert.equal(leads.source, 'override');
assert.deepEqual(leads.section, { mode: 'rules', rules: [{ owners: ['self'] }] });
});
it('سفارشی کردن فقط مشتریان، لید را از دید قدیمی جدا نمی‌کند', () => {
const leads = resolveSectionAccess('leads', {
...legacyOwn,
rolePolicy: {},
override: { customers: { mode: 'all', rules: [] } },
});
assert.deepEqual(leads.section, { mode: 'rules', rules: [{ owners: ['self'] }] });
});
});