Skip to content

Organization Settings

Self-service configuration module for managing Zoho organization resources — taxes, chart of accounts, and bank accounts — with bidirectional synchronization to Zoho Books API.

Overview

The Organization Settings module gives the finance team a unified interface to configure per-organization resources that were previously managed through SQL scripts or direct Zoho Books access. It centralizes tax configuration, chart of accounts management, and bank account registration into a tabbed offcanvas panel accessible from the organizations list.

Key Concepts

ConceptDescription
OrganizationA Zoho Books organization (receiver entity) representing a legal entity with its own tax rules and accounts
Individual TaxA single tax rate (e.g., IVA 16%) synced bidirectionally with Zoho Books
Tax GroupA combined retention composed of 2+ individual taxes, stored as a single Zoho tax group ID
Chart of AccountA 2-level hierarchical classification for expenses/income, synced from Zoho's chart of accounts
Bank AccountA payment method (bank, cash, credit card) linked to a Zoho bank account
Sync PreviewA comparison between Zoho's remote data and local DB, showing what's missing before bulk import

Data Flow

Tax CRUD with Zoho Sync

Account Sync from Zoho

Bank Sync from Zoho

Backend Structure

Business Logic

backend/libraries/
└── organization-settings.util.js    # All business logic (taxes, accounts, banks)

The utility class handles:

  • Tax CRUD with Zoho sync dispatch (individual vs. group)
  • Account CRUD with 2-level hierarchy validation and Zoho sync
  • Bank CRUD with activate/deactivate toggle
  • Sync preview (compare Zoho remote vs. local DB) for taxes, accounts, and banks
  • Bulk sync (insert missing records from Zoho)

Zoho Service Methods

backend/services/zoho/index.js
MethodZoho EndpointPurpose
listTaxes(orgId, taxType)GET /v3/settings/taxesFetch all taxes (or by type)
getTaxGroup(orgId, groupId)GET /v3/settings/taxgroups/{id}Fetch group member details
createTax / updateTax / deleteTaxPOST/PUT/DELETE /v3/settings/taxesIndividual tax CRUD
createTaxGroup / updateTaxGroup / deleteTaxGroupPOST/PUT/DELETE /v3/settings/taxgroupsTax group CRUD
listChartOfAccounts(orgId, accountType)GET /v3/chartofaccountsFetch accounts with optional type filter
createChartOfAccount / updateChartOfAccountPOST/PUT /v3/chartofaccountsAccount CRUD
markChartOfAccountActive / markChartOfAccountInactivePOST /v3/chartofaccounts/{id}/active|inactiveToggle account status
listBankAccounts(orgId)GET /v3/bankaccountsFetch all bank accounts

Controller & Routes

All handlers are in backend/controllers/finances.controller.js and routes in backend/routes/finances.routes.js under the /finances/organization/ prefix.

Database

Tables

TablePurpose
zoho_organization_taxesUnified storage for individual taxes and tax groups (self-referencing via child_ids)
zoho_accountsChart of accounts with 2-level hierarchy (parent_account_id), linked to departments
zoho_banksBank/payment method accounts per organization
zoho_invoice_receiversOrganizations (used as read-only source for the organization list)

Entity Relationship

Key Fields

zoho_organization_taxes

ColumnTypeDescription
idINT (PK)Auto-increment
zoho_organization_idINTReference to receiver's Zoho org ID
tax_keyVARCHAR(50)Unique key per org (auto-generated from label)
labelVARCHAR(100)Human-readable name
rateDECIMAL(10,6)Tax rate as decimal (0.16 = 16%)
tax_typeENUMtransferred or retained
typeENUMindividual or group
child_idsJSONArray of IDs from same table (groups only)
zoho_tax_idVARCHAR(100)Zoho Books tax/group ID

zoho_accounts

ColumnTypeDescription
idINT (PK)Auto-increment
organization_idVARCHAR(100)Zoho organization ID
account_idVARCHAR(100)Zoho chart of accounts ID
nameVARCHAR(120)Normalized identifier (auto-generated from description)
descriptionVARCHAR(255)Human-readable name
account_typeVARCHAR(100)Zoho account type (expense, income, asset, etc.)
parent_account_idINT (FK, self)Parent account for 2-level nesting
department_idINT (FK)Department assignment (parent accounts only)
activeTINYINT1 = active, 0 = inactive

zoho_banks

ColumnTypeDescription
idINT (PK)Auto-increment
organization_idVARCHAR(100)Zoho organization ID
account_idVARCHAR(100)Zoho bank account ID
nameVARCHAR(100)Normalized identifier (auto-generated from description)
descriptionVARCHAR(255)Human-readable name
account_typeVARCHAR(50)bank, cash, or credit_card
activeTINYINT1 = active, 0 = inactive

Key Decisions

DecisionReasoningAlternatives Considered
Unified zoho_organization_taxes table for individuals + groupsGroups behave identically to individual taxes in the API. Self-referencing child_ids JSON avoids pivot table complexity.Separate group table + pivot (more JOINs, 3-table schema)
2-level max hierarchy for accountsZoho Books supports parent/child accounts but not deeper nesting. Matches Zoho's constraint.Unlimited nesting (over-engineering, Zoho doesn't support it)
Auto-generated name from descriptionTechnical identifiers (name) are normalized from user input (description) to avoid user mistakes and ensure consistency.Manual name entry (error-prone, inconsistent formatting)
Account type filter for syncZoho can have hundreds of accounts. Filtering by type (Expense, Income, etc.) before fetching prevents overwhelming the user.Fetch all at once (too many results, slow UI)
Department assignment only on parent accountsSub-accounts inherit context from their parent. Assigning departments at child level creates redundancy.Department on all levels (confusing, contradictory assignments)
Activate/deactivate instead of deletePreserves referential integrity — existing invoices and payment requests may reference these records.Hard delete (breaks references), soft delete without toggle (no reactivation)

Dependencies

  • Internal: Payment Requests module (uses getTaxOptions for tax selection), Invoice Form (shared tax options)
  • External: Zoho Books API (bidirectional sync for taxes, accounts, banks)

Envia Admin