Organization Settings UI
Frontend screens, components, and user flows for the Organization Settings module.
Route Structure
/finances/organizations → Organization list (DataTable)The module is accessed from the Finance menu. The organization list is the single route; all management happens within an offcanvas panel opened from table row actions.
Route is defined alongside other finance routes and requires the menu-organization-settings permission.
Screens
Organization List (/finances/organizations)
Paginated list of all Zoho organizations with country information.
Layout:
| Section | Component | Description |
|---|---|---|
| Page Header | — | Title "Organization Settings" |
| Data Table | Datatable | Organizations with name, RFC, country, actions |
Table columns: Organization Name, RFC/Tax ID, Country, Actions (Manage button)
Component structure:
views/finances/organizations/
├── index.vue # Route view (imports Table)
└── components/
├── Table.vue # Datatable configuration
├── Manage.offcanvas.vue # Tab container offcanvas
├── TaxForm.modal.vue # Individual tax create/edit
├── TaxGroupForm.modal.vue # Tax group create/edit
├── SyncTaxes.modal.vue # Tax sync from Zoho
├── AccountForm.modal.vue # Account create/edit
├── SyncAccounts.modal.vue # Account sync from Zoho (2-step)
├── BankForm.modal.vue # Bank create/edit
├── SyncBanks.modal.vue # Bank sync from Zoho
└── tabs/
├── Taxes.vue # Tax management tab
├── Accounts.vue # Account management tab
└── Banks.vue # Bank management tabManage Offcanvas (Manage.offcanvas.vue)
The main management panel opened when clicking "Manage" on an organization row. Uses TabsV2 to organize three sections. Tabs are lazy-loaded.
Tabs:
| Tab | Component | i18n Key |
|---|---|---|
| Taxes | tabs/Taxes.vue | organizationSettings.taxes |
| Accounts | tabs/Accounts.vue | organizationSettings.accountClassification |
| Banks | tabs/Banks.vue | organizationSettings.bankAccounts |
Lifecycle: On show(), all tabs load their data. On close(), all tabs reset.
Taxes Tab (tabs/Taxes.vue)
Displays individual taxes and tax groups using DetailsV2 cards.
Layout:
┌──────────────────────────────────────────────────┐
│ Individual Taxes [Sync] [Add] │
│ ┌──────────────────────────────────────────────┐ │
│ │ IVA (16%) · transferred · code: 002 │ │
│ │ [Edit] [Delete] │ │
│ └──────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────┐ │
│ │ ReteISR (10%) · retained · code: 001 │ │
│ │ [Edit] [Delete] │ │
│ └──────────────────────────────────────────────┘ │
│ │
│ Tax Groups [Add] │
│ ┌──────────────────────────────────────────────┐ │
│ │ Honorarios + ReteIVA · 11.9167% │ │
│ │ Members: ReteRenta (10.6667%), ReteIVA (1.25%)│
│ │ [Edit] [Delete] │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘Features:
- Group rates show exact decimal precision (e.g., 11.9167% not 12%)
- Groups always have
tax_type: retained SyncTaxes.modal.vue,TaxForm.modal.vue,TaxGroupForm.modal.vueare teleported to<body>to avoid z-index issues
Accounts Tab (tabs/Accounts.vue)
Displays chart of accounts in a 2-level hierarchical list using DetailsV2 cards.
Layout:
┌──────────────────────────────────────────────────┐
│ Chart of Accounts [Sync] [Add] │
│ ┌──────────────────────────────────────────────┐ │
│ │ ▼ Cost of Goods Sold · Dept: Operations │ │
│ │ ├── Raw Materials [Active] │ │
│ │ └── Direct Labor [Active] │ │
│ │ [Edit] [Deactivate] │ │
│ └──────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────┐ │
│ │ ▼ Office Expenses · Dept: Admin │ │
│ │ ├── Office Supplies [Active] │ │
│ │ └── Software Licenses [Inactive] │ │
│ │ [Edit] [Activate] │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘Features:
nameauto-generated fromdescription(not editable by user)department_idonly assignable to parent accounts- Activate/deactivate toggle instead of delete
- Cannot deactivate parent with active children
AccountForm.modal.vueconditionally shows department field based onisChildAccount
Sync Accounts Modal (SyncAccounts.modal.vue)
Two-step flow to manage large account sets:
Step 1: Grid of account type categories as buttons.
Step 2: Tree view with:
- All checkboxes selected by default
- Unchecking parent unchecks all children
- Checking a child auto-checks its parent
- Department select dropdown for parent accounts
- Visual indicators for already-synced and inactive accounts
- "Back" button to return to step 1
Banks Tab (tabs/Banks.vue)
Flat list of bank accounts using DetailsV2 cards.
Layout:
┌──────────────────────────────────────────────────┐
│ Bank Accounts [Sync] [Add] │
│ ┌──────────────────────────────────────────────┐ │
│ │ BBVA Bancomer · bank · ID: 55283... │ │
│ │ [Active] [Edit] │ │
│ └──────────────────────────────────────────────┘ │
│ ┌──────────────────────────────────────────────┐ │
│ │ Caja Chica · cash · [Inactive] │ │
│ │ [Activate] [Edit] │ │
│ └──────────────────────────────────────────────┘ │
└──────────────────────────────────────────────────┘Sync Banks Modal (SyncBanks.modal.vue)
Single-step flow: flat list with checkboxes, all selected by default.
Shows inactive Zoho bank accounts with visual indicator.
Service Layer
client/src/services/organizations.service.jsRegistered as api.organizations. All methods:
| Method | Endpoint | Description |
|---|---|---|
getOrganizations() | GET /finances/organization | List organizations |
getTaxes(orgId) | GET /finances/organization/{orgId}/taxes | List taxes |
createTax(orgId, data) | POST /finances/organization/{orgId}/taxes | Create tax |
updateTax(id, data) | PUT /finances/organization/taxes/{id} | Update tax |
deleteTax(id) | DELETE /finances/organization/taxes/{id} | Delete tax |
getSyncPreview(orgId) | GET /finances/organization/{orgId}/taxes/sync-preview | Tax sync preview |
syncTaxes(orgId, taxes) | POST /finances/organization/{orgId}/taxes/sync | Sync taxes |
getAccounts(orgId) | GET /finances/organization/{orgId}/accounts | List accounts |
createAccount(orgId, data) | POST /finances/organization/{orgId}/accounts | Create account |
updateAccount(id, data) | PUT /finances/organization/accounts/{id} | Update account |
toggleAccountActive(id) | PATCH /finances/organization/accounts/{id}/toggle-active | Toggle status |
getAccountsSyncPreview(orgId, type) | GET /finances/organization/{orgId}/accounts/sync-preview | Account sync preview |
syncAccounts(orgId, accounts) | POST /finances/organization/{orgId}/accounts/sync | Sync accounts |
getBanks(orgId) | GET /finances/organization/{orgId}/banks | List banks |
createBank(orgId, data) | POST /finances/organization/{orgId}/banks | Create bank |
updateBank(id, data) | PUT /finances/organization/banks/{id} | Update bank |
toggleBankActive(id) | PATCH /finances/organization/banks/{id}/toggle-active | Toggle status |
getBanksSyncPreview(orgId) | GET /finances/organization/{orgId}/banks/sync-preview | Bank sync preview |
syncBanks(orgId, banks) | POST /finances/organization/{orgId}/banks/sync | Sync banks |
Module-Specific Components
| Component | Description |
|---|---|
TaxForm.modal.vue | FormGenerator-based modal for individual tax CRUD, auto-generates tax_key |
TaxGroupForm.modal.vue | FormGenerator-based modal for tax groups, type fixed to retained, min 2 children |
SyncTaxes.modal.vue | Modal with checkbox list for bulk Zoho tax import |
AccountForm.modal.vue | FormGenerator-based modal, conditional department_id for parents, auto-generates name |
SyncAccounts.modal.vue | 2-step modal with type filter + hierarchical tree selection |
BankForm.modal.vue | FormGenerator-based modal, auto-generates name from description |
SyncBanks.modal.vue | Modal with flat checkbox list for bulk Zoho bank import |
All modals use <Teleport to="body"> to escape the offcanvas z-index context.
Key Patterns
- FormGenerator for all forms with Vuelidate integration
- DetailsV2 cards for displaying records with action slots
- SwalPlugin (
window.Swal) for confirmation dialogs on delete/toggle actions - Teleport for all modals rendered inside tabs within an offcanvas
- Lazy tab loading in
Manage.offcanvas.vuewith explicitloadX()/reset()lifecycle
