fix(treasury): scope finance access and hide it when the module is off
Accounts can be edited, including the opening balance, and finance sections and accounts can be granted on a role or on one user. The finance menu stays hidden when the organization module is disabled. Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
@@ -14,6 +14,7 @@ import {
|
||||
DATA_ACCESS_SECTIONS,
|
||||
ROLE_PERMISSION_ITEMS,
|
||||
type DataAccessPolicy,
|
||||
type FinancialAccountDto,
|
||||
type InviteUserRequest,
|
||||
type OrganizationDto,
|
||||
type OrgModuleKey,
|
||||
@@ -74,7 +75,16 @@ const PERMISSION_MODULES: Partial<Record<RolePermissionKey, OrgModuleKey[]>> = {
|
||||
conversations: ['conversations'],
|
||||
conversations_groups: ['conversations'],
|
||||
treasury: ['treasury'],
|
||||
treasury_dashboard: ['treasury'],
|
||||
treasury_incomes: ['treasury'],
|
||||
treasury_expenses: ['treasury'],
|
||||
treasury_receivables: ['treasury'],
|
||||
treasury_accounts: ['treasury'],
|
||||
treasury_payroll: ['treasury'],
|
||||
treasury_recurring: ['treasury'],
|
||||
treasury_reports: ['treasury'],
|
||||
treasury_audit: ['treasury'],
|
||||
treasury_categories: ['treasury'],
|
||||
behavior: ['behavior'],
|
||||
};
|
||||
|
||||
@@ -139,6 +149,10 @@ const roleFormDesc = ref('');
|
||||
const roleFormColor = ref<RoleColor>('teal');
|
||||
const roleFormParentId = ref('');
|
||||
const roleFormPerms = ref<RolePermissionKey[]>(ROLE_PERMISSION_ITEMS.map((p) => p.key));
|
||||
const roleFormAccountIds = ref<string[]>([]);
|
||||
const roleFormOwnAccounts = ref(false);
|
||||
const roleFormAccounts = ref<Array<{ id: string; name: string; responsibleName: string }>>([]);
|
||||
const roleAccountQuery = ref('');
|
||||
|
||||
const deleteOpen = ref(false);
|
||||
const deleteSaving = ref(false);
|
||||
@@ -616,7 +630,11 @@ function openCreateRole(parentId?: string | null) {
|
||||
? [...parent.permissions]
|
||||
: visibleRolePermissions.value.map((p) => p.key);
|
||||
roleFormDataAccess.value = clonePolicy(parent?.dataAccessPolicy);
|
||||
roleFormAccountIds.value = [...(parent?.treasuryAccountIds ?? [])];
|
||||
roleFormOwnAccounts.value = Boolean(parent?.treasuryOwnAccounts);
|
||||
roleAccountQuery.value = '';
|
||||
roleFormOpen.value = true;
|
||||
void loadRoleAccounts();
|
||||
}
|
||||
|
||||
function openCreateChildRole() {
|
||||
@@ -636,7 +654,40 @@ function openEditRole() {
|
||||
roleFormParentId.value = role.systemKey ? '' : (role.parentId ?? '');
|
||||
roleFormPerms.value = [...role.permissions];
|
||||
roleFormDataAccess.value = clonePolicy(role.dataAccessPolicy);
|
||||
roleFormAccountIds.value = [...(role.treasuryAccountIds ?? [])];
|
||||
roleFormOwnAccounts.value = Boolean(role.treasuryOwnAccounts);
|
||||
roleAccountQuery.value = '';
|
||||
roleFormOpen.value = true;
|
||||
void loadRoleAccounts();
|
||||
}
|
||||
|
||||
function isTreasuryDetail(key: RolePermissionKey) {
|
||||
return key.startsWith('treasury_');
|
||||
}
|
||||
|
||||
const filteredRoleAccounts = computed(() => {
|
||||
const query = roleAccountQuery.value.trim();
|
||||
if (!query) return roleFormAccounts.value;
|
||||
return roleFormAccounts.value.filter((account) => account.name.includes(query));
|
||||
});
|
||||
|
||||
async function loadRoleAccounts() {
|
||||
try {
|
||||
const { data } = await api.get<FinancialAccountDto[]>('/treasury/accounts');
|
||||
roleFormAccounts.value = data.map((account) => ({
|
||||
id: account.id,
|
||||
name: account.name,
|
||||
responsibleName: account.responsibleName?.trim() ?? '',
|
||||
}));
|
||||
} catch {
|
||||
roleFormAccounts.value = [];
|
||||
}
|
||||
}
|
||||
|
||||
function toggleRoleAccount(id: string) {
|
||||
roleFormAccountIds.value = roleFormAccountIds.value.includes(id)
|
||||
? roleFormAccountIds.value.filter((item) => item !== id)
|
||||
: [...roleFormAccountIds.value, id];
|
||||
}
|
||||
|
||||
function permOn(key: RolePermissionKey) {
|
||||
@@ -644,6 +695,14 @@ function permOn(key: RolePermissionKey) {
|
||||
}
|
||||
|
||||
function toggleFormPerm(key: RolePermissionKey) {
|
||||
if (key === 'treasury' && permOn('treasury')) {
|
||||
roleFormPerms.value = roleFormPerms.value.filter(
|
||||
(item) => item !== 'treasury' && !item.startsWith('treasury_'),
|
||||
);
|
||||
roleFormAccountIds.value = [];
|
||||
roleFormOwnAccounts.value = false;
|
||||
return;
|
||||
}
|
||||
roleFormPerms.value = permOn(key)
|
||||
? roleFormPerms.value.filter((p) => p !== key)
|
||||
: [...roleFormPerms.value, key];
|
||||
@@ -667,12 +726,16 @@ async function submitRoleForm() {
|
||||
permissions: RolePermissionKey[];
|
||||
dataAccessPolicy?: OrgRoleDto['dataAccessPolicy'];
|
||||
parentId?: string | null;
|
||||
treasuryAccountIds?: string[];
|
||||
treasuryOwnAccounts?: boolean;
|
||||
} = {
|
||||
name: roleFormName.value.trim(),
|
||||
description: roleFormDesc.value.trim(),
|
||||
color: roleFormColor.value,
|
||||
permissions: roleFormPerms.value,
|
||||
dataAccessPolicy: roleFormDataAccess.value,
|
||||
treasuryAccountIds: roleFormAccountIds.value,
|
||||
treasuryOwnAccounts: roleFormOwnAccounts.value,
|
||||
};
|
||||
if (!editing?.systemKey) {
|
||||
body.parentId = roleFormParentId.value || null;
|
||||
@@ -1491,11 +1554,48 @@ onUnmounted(() => {
|
||||
</label>
|
||||
<fieldset class="perm-set">
|
||||
<legend>مجوزهای دسترسی</legend>
|
||||
<label v-for="perm in visibleRolePermissions" :key="perm.key" class="perm-row">
|
||||
<p class="hint">
|
||||
تیک مدیریت مالی در را باز میکند. بخشهای ریز جدا انتخاب میشوند و با روشن کردن مدیریت مالی خودبهخود تیک نمیخورند.
|
||||
تا وقتی هیچ بخش ریزی ذخیره نشده، همه بخشها بهجز حقوق باز میمانند. با ذخیره حتی یک بخش، فقط همانها میمانند. حقوق جداست.
|
||||
</p>
|
||||
<label
|
||||
v-for="perm in visibleRolePermissions"
|
||||
v-show="!isTreasuryDetail(perm.key) || permOn('treasury')"
|
||||
:key="perm.key"
|
||||
class="perm-row"
|
||||
:class="{ 'perm-sub': isTreasuryDetail(perm.key) }"
|
||||
>
|
||||
<input type="checkbox" :checked="permOn(perm.key)" @change="toggleFormPerm(perm.key)" />
|
||||
{{ perm.label }}
|
||||
</label>
|
||||
</fieldset>
|
||||
<fieldset v-if="permOn('treasury')" class="perm-set">
|
||||
<legend>دسترسی حسابها</legend>
|
||||
<p class="hint">
|
||||
این بخش جدا از تیک بخشهای مالی است. میتوانید حسابهایی را بدهید که خود عضو مسئول آنهاست،
|
||||
و جدا از آن حسابهای دیگر را هم انتخاب کنید. اگر هیچکدام انتخاب نشود، همه حسابها باز میماند.
|
||||
</p>
|
||||
<label class="perm-row">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="roleFormOwnAccounts"
|
||||
@change="roleFormOwnAccounts = !roleFormOwnAccounts"
|
||||
/>
|
||||
حسابهایی که خودش مسئول آنهاست
|
||||
</label>
|
||||
<p class="hint">حسابهای دیگر</p>
|
||||
<input v-model="roleAccountQuery" placeholder="جستجوی حساب" />
|
||||
<label v-for="account in filteredRoleAccounts" :key="account.id" class="perm-row">
|
||||
<input
|
||||
type="checkbox"
|
||||
:checked="roleFormAccountIds.includes(account.id)"
|
||||
@change="toggleRoleAccount(account.id)"
|
||||
/>
|
||||
{{ account.name }}
|
||||
<template v-if="account.responsibleName"> — مسئول: {{ account.responsibleName }}</template>
|
||||
</label>
|
||||
<p v-if="!roleFormAccounts.length" class="hint">حسابی برای انتخاب نیست.</p>
|
||||
</fieldset>
|
||||
<fieldset class="perm-set">
|
||||
<legend>محدوده داده</legend>
|
||||
<DataAccessPolicyPanel
|
||||
@@ -2381,6 +2481,10 @@ textarea {
|
||||
color: #0f172a;
|
||||
}
|
||||
|
||||
.perm-sub {
|
||||
padding-inline-start: 1.4rem;
|
||||
}
|
||||
|
||||
.sheet-handle,
|
||||
.sheet-backdrop {
|
||||
display: none;
|
||||
|
||||
Reference in New Issue
Block a user