JAI CRM
Home Documentation Making it yours Dependency rules

Dependency rules

Why a delete is refused while other records still point at it, which rules ship switched on, and what changes when you switch one off.

Somebody tidies the customer list, picks a duplicate account from 2023 and presses Delete. The product refuses, and names three deals and two invoices that still point at it. That refusal is a dependency rule. This page covers what those rules are, which ones ship with the product, what each protects, and what you get if you switch one off.

What a dependency rule is

A dependency rule is a sentence of the form a customer cannot be deleted while an invoice points at it. It names three things: the record being deleted, the kind of record that points at it, and the field that does the pointing — customerId on the invoice, in that example.

Before a delete goes through on one of the modules in the table below, the product counts the records that match each rule for that module. Deletes elsewhere in the product — a menu item, a person’s membership of a group, a notification template — never consult these rules at all; the engine is wired into about thirty of the product’s hundred-odd delete routes, and the table below is the honest list of what it protects.

If any matching rule is set to block, the delete is refused and up to five of the blocking records of each kind are listed, with a link to open them where that kind of record has a screen of its own. Payment allocations, stock balances, assignments, role assignments and group members have none, so those appear as bare database ids with nothing to click. Nothing is half-deleted: the check and the delete happen in one transaction, so either everything the rule permits happens or nothing does.

There are three behaviours a rule can have.

  • Block — the delete is refused and the blocking records are listed. Shown as Restrict on the screen, and it is what 35 of the 39 shipped rules do.
  • Delete the children too — the pointing records are deleted along with the parent, in the same transaction. Shown as Cascade.
  • Keep the children, clear the link — the pointing records stay where they are and the field that pointed at the deleted record is emptied. Shown as Detach.

Who can open the screen and who can change it

The screen is Settings › Customisation › Dependency rules. It needs the Dependency rules permission under Settings. Out of the box only the business owner and the Administrator role have it — the Manager preset skips every Settings permission except view on Users and view on Circles, so a manager does not see the entry at all.

Viewing and changing are separate. With View, you see the table, every switch is greyed out and the New rule button is hidden. To change anything, a role needs Manage on that row. Manage on its own is enough: it implies every lesser action, so a role holding Manage and nothing else gets a fully working screen.

On Settings › Roles & permissions, the Dependency rules row shows only View and Edit until you turn on “Show every action”. Ticking Edit is the obvious thing to do and it grants nothing: every write on this screen asks for Manage. A role given View and Edit sees live-looking switches, an enabled New rule button and an editable dialog, and every one of them fails with a permission error when used. Turn on “Show every action” and tick Manage, or tick All access.

The rules that ship with the product

Thirty-nine rules are created for every business when it is set up, all switched on, all marked Built in. The Because column on screen explains each one in words — “Invoices raised on the customer”, “Stock movements for the item” — and that wording is what the refusal dialog prints back at whoever tried to delete. The Behaviour column below uses the words the screen itself prints, so rows can be matched by eye.

Deleting thisIs blocked byBehaviour
CustomerInvoicesRestrict
CustomerQuotationsRestrict
CustomerSales ordersRestrict
CustomerCredit notesRestrict
CustomerDealsRestrict
CustomerProjectsRestrict
CustomerPayments receivedRestrict
CompanyCustomersRestrict
LeadCustomersDetach
DealQuotationsRestrict
QuotationSales ordersRestrict
QuotationInvoicesRestrict
QuotationProforma invoicesRestrict
Sales orderInvoicesRestrict
Sales orderProforma invoicesRestrict
Sales orderDelivery challansRestrict
Proforma invoiceInvoicesRestrict
InvoiceCredit notesRestrict
InvoicePayment allocationsRestrict
Bill of supplyPayment allocationsRestrict
Bill of supplyCredit notesRestrict
Retainer invoicePayment allocationsRestrict
VendorPurchase ordersRestrict
VendorPurchase billsRestrict
VendorItemsDetach
Purchase orderGoods receiptsRestrict
ItemStock movementsRestrict
ItemDocument linesRestrict
WarehouseStock balancesRestrict
ProjectProject tasksCascade
ProjectInvoicesRestrict
UserAssignmentsRestrict
GroupGroup membersCascade
RoleRole assignmentsRestrict
RoleRolesRestrict
Tax rateDocument linesRestrict
Bank accountPaymentsRestrict
Expense categoryExpensesRestrict
EmployeeExpensesRestrict

A few of the child names are internal rather than everyday. Payment allocations means money recorded against that document, and it is what the confirmation dialog names when somebody tries to delete an invoice that has been paid — though what actually refuses that delete is the issued-document guard described further down, which fires first and is untouched by switching this rule off. Document lines means a line on any quotation, order, invoice or bill — that is what protects an item and a tax rate from being deleted once they have been used on paperwork. Assignments means records where that person is the owner, assignee or watcher.

Four rules do not block. Deleting a lead clears the link on the customer it was converted into, and the customer stays. Deleting a vendor clears the preferred-supplier field on items and the items stay. Deleting a project deletes the tasks inside it. The fourth, Group → Group members, is marked to delete the members along with the group and never fires at all — see “The group rule does nothing” below.

The rule “Role — Role assignments” ignores people who have left. Someone removed from the business still holds a role assignment row, and without this the role would be undeletable for ever, blamed on staff who left months ago. This condition comes from the shipped definition and cannot be seen or changed on the screen.

A document line is not deleted when its document is. A quotation or invoice is hidden rather than erased, and its lines stay, so an item or a tax rate goes on being blocked by paperwork nobody can open any more. The refusal will name those documents; opening one is not possible.

An update can add a rule you did not have yesterday. The shipped list is seeded once when a business is created, and topped up on each deployment for businesses created earlier — the top-up runs in the same step as the database migration, which the API waits for before it starts. It only ever adds what is missing: a rule you have switched off stays off.

Switching a rule off

  1. Open Settings › Customisation › Dependency rules.
  2. Find the row by its first two columns: Deleting this, and is blocked by.
  3. Click the switch in the On column at the right of the row.
  4. The confirmation reads “Rule switched off — this is recorded”. There is no second confirmation and no Save button; it takes effect immediately.

The banner at the top of the screen counts what is off, so a loosened business says so on the screen it is loosened from. Every change is written to Settings › Audit log against the rule, in plain words: “Switched OFF the guard stopping a customer being deleted while a deal depends on it”, with who did it and when.

Every rule on this screen can be switched off, built-in ones included. There is no rule the product refuses to loosen. What you cannot do is delete one — not a built-in rule, and not one you added yourself. The screen offers no way to delete a rule at all; the only way to retire one is to switch it off.

A worked example: a customer with deals against it

Sharma Textiles Pvt Ltd of Surat was entered twice in 2023. The newer account carries the trading, so the older one is to go. It has three deals — Monsoon range restock at ₹4,20,000, Export samples at ₹1,85,000 and Retail top-up at ₹96,000 — and two invoices totalling ₹2,36,000 including GST at 18%.

  1. Open CRM › Customers, open the older Sharma Textiles record and press Delete.
  2. The dialog checks first and comes back titled “This cannot be deleted yet”. It lists “3 deals on the customer” with the three deal names, each a link, and “2 invoices raised on the customer” with the two numbers. There is no Delete button on that dialog, only Close.
  3. Deal with the records, or loosen the rule. To deal with them: open each deal and each invoice and delete or reassign it, then come back to the customer.
  4. To loosen instead: go to Settings › Customisation › Dependency rules and switch off the row Customer → Deals. Return to the customer and press Delete again.

The second attempt is still refused, and this is where people lose an afternoon. Switching off the deals rule removed one blocker of two. The dialog now says “2 invoices raised on the customer”. Every blocking rule is listed at once and every one of them has to be dealt with — either the records go, or each rule goes off. With both Customer → Deals and Customer → Invoices switched off, the delete goes through.

What you are left with: the customer is gone from the customer list, and the three deals and two invoices are exactly where they were, still carrying that customer’s id. Nothing rewrites them and nothing warns you again. They also still print the deleted customer’s name — the list looks up that name by id and does not exclude deleted records — so the deals list goes on reading “Sharma Textiles Pvt Ltd” against a customer nobody can open.

Deleting several at once behaves differently, and less honestly. On the customer list, ticking twenty rows and choosing Delete goes straight ahead — no confirmation dialog, nothing shown first. The server does check each row and skips the ones that are blocked, and it composes a reply naming what it refused; the screen throws that reply away and reports “20 deleted”, the number you ticked, whatever actually happened. The only sign that six survived is that they are still on the list when it refreshes.

What changes the moment you save

  • The next delete anywhere in the business uses the new setting. The rules are read from the database inside each delete, so there is nothing to refresh and nobody has to sign in again.
  • The check that runs before the dialog opens uses it too, so a loosened rule stops appearing in the list of blockers.
  • An entry appears in Settings › Audit log naming the rule, the direction of the change and the person. That is accurate for the On switch. A save from the rule dialog always records “Switched ON the guard”, even when all you changed was the explanation.
  • The banner on the Dependency rules screen starts counting that rule among the ones switched off.

What switching a rule off will not do

  • It does not delete anything, then or later. It only stops the refusal the next time somebody presses Delete.
  • It does not go back over records deleted before. Nothing is reversed and nothing is re-checked.
  • It does not tidy up after the delete. The deals, invoices and payments that were blocking still hold the id of the record you removed. They are not re-pointed, blanked or flagged.
  • It is not how a record comes back. A deleted lead, customer, company, contact, deal, task or visit, or a record in a module of your own, goes to Settings › Recycle bin and can be restored from there for 60 days; see the recycle bin. Nothing else has a Restore control. A deleted invoice or other sales document, a purchase document, an item or a vendor is hidden rather than erased, but no screen brings it back. Projects, and folders and files in Documents, have an undelete in the system with nothing in the interface wired to it, and the Documents trash offers “Delete forever” and nothing else. The delete dialog says which case you are in: for a record that goes to the bin it says it can be restored for 60 days, and for the rest that nothing in the product will bring it back.
  • It does not widen who may delete. The delete permission on the module is checked first and is unaffected by any of this.

The exceptions that catch people out

Sales documents are protected by something else first

For a quotation, order, invoice, proforma, bill of supply, retainer, credit note or delivery challan, the dependency rules only ever decide the fate of a draft. Anything that has been issued is refused before the rules are consulted, with “has been issued, so it cannot be deleted — cancel it instead, which keeps the number on record for audit”. A second guard refuses any document that is not the most recent of its type in its own branch, because deleting it would leave a gap in a statutory number series; in a business running branches, the newest invoice in another branch does not block. Neither of those is a dependency rule and neither appears on this screen, so switching off Quotation → Invoices will not let you delete a quotation you have already sent.

Neither guard is consulted by the check that runs before the dialog opens, either. That check asks the dependency rules and nothing else, so an issued invoice with no dependants gets a dialog offering a Delete button, and pressing it produces the refusal instead.

Purchase orders and bills carry their own hard-coded checks

A purchase order or purchase bill is also checked for payments applied to it, documents raised from it, debit notes against it and goods receipts booked against it. Those checks are built into the purchase module, are not rules, and cannot be switched off from anywhere. They appear in the delete dialog alongside the real rules, with no matching row in Settings.

Goods receipts are the one that bites. The check that runs before the dialog opens sees them only through the Purchase order → Goods receipts rule, while the delete counts them again in code no setting reaches. Switch that rule off and the dialog will tell you the order can be deleted; pressing Delete then fails with a refusal naming the receipts.

The blocking records are counted across the whole business

The count ignores what the person pressing Delete is allowed to see. A salesperson whose records are limited to their own can be blocked by a colleague’s deal, and the dialog will name that deal and offer a link to it. The link will not open for them.

A detach clears more rows than it names

Deleting a vendor tells you how many items will lose the preferred-supplier link, and that count excludes items that have themselves been deleted. The clearing does not: every item pointing at that vendor has the field emptied, deleted ones included. The number you are shown can be smaller than the number of rows changed. Nothing about it is visible afterwards, and nothing is harmed by it — but if you are reconciling counts, that is where the difference comes from.

The group rule does nothing

The row Group → Group members, marked Cascade, does not fire. The delete for a group asks the engine about a module name the engine does not know, so no rule is found and nothing is cascaded. Deleting a group hides the group and leaves its membership rows behind. The same applies to circles, which are stored the same way. Nothing else is affected — this rule has no blocking behaviour to lose.

The employee rule is not only about salary

The row Employee → Expenses is labelled “Salary entries for the employee”, and that is the wording the refusal uses. It actually counts every expense record against that person, including travel and reimbursement claims. An employee blocked by “2 salary entries” may in fact have two pending taxi claims.

Adding a rule of your own

A rule you add behaves exactly like a shipped one and is marked Yours on the screen.

  1. Press New rule.
  2. Choose the module under “Deleting this” and the module under “is blocked by”.
  3. In “Linked by which field”, type the name of the field on the second module that points at the first, exactly as the database spells it — customerId, vendorId, projectId.
  4. Choose the behaviour.
  5. Put the reason in Explanation. This is the wording the refusal dialog shows, so write it as the sentence you want somebody to read: “Invoices raised on the customer”. Left blank, the dialog falls back to the plural name of the module.
  6. Press Save. The rule is created switched on.

Nothing checks the field name when you save. Type customer_id or clientId and the rule saves cleanly, appears in the table and looks correct. On a sales document, a purchase document, a vendor or a payment made, the rule is then quietly dropped and simply never fires. Everywhere else — a customer, lead, deal, item, project, expense, tax rate, bank account, warehouse, user, role or employee — it makes deleting that kind of record fail with a server error. Worse, the check that runs before the dialog fails on the same bad name and is swallowed silently, so the dialog reports the record as clear to delete and the delete then blows up. If a delete starts failing oddly after you add a rule, the field name is the first thing to check.

Do not add two rules joining the same pair of modules through different fields. The product will accept them — only an exact repeat of parent, child and field is refused as a duplicate — but when a cascade or detach runs it looks the rule up by the child module alone, finds whichever of the two comes first, and clears or deletes through that one’s column. The shipped set never has two rules on one pair, so this only ever bites a business that has added them.

Modules a business has defined for itself cannot be protected from this screen. The two dropdowns are built from the shipped module list only, so a custom module appears in neither, even though the delete for one goes through the same engine and the underlying interface would accept it.

Controls on this screen that do nothing

  • The Edit tick on Settings › Roles & permissions. Every change on this screen asks for Manage. A role with Edit can open the screen and click, and every click is refused.
  • Editing a saved rule’s modules or field. Clicking one of your own rules reopens the dialog with “Deleting this”, “is blocked by” and “Linked by which field” all editable. Changes to those three are dropped on save, and the product still reports “Saved”. Only the behaviour and the explanation can actually be changed after a rule is created. To correct the modules or the field, switch that rule off and add a new one.
  • The stored message field. The rule carries a second text field, documented as the message shown in the blocked-delete dialog. No screen offers it and nothing reads it. The Explanation field is the one that reaches the dialog.
  • Editing a built-in rule. Clicking a Built in row does nothing at all — no dialog opens. A shipped rule’s behaviour cannot be changed from Block to Cascade here; the only control that works on it is the On switch.
  • Deleting any rule. There is no delete control on the screen. The interface behind it refuses to delete a built-in rule, with “This guard ships with the product. Switch it off if you must, which is recorded, rather than deleting it” — a message you will never meet, because nothing on the screen can ask for it.

Something missing or wrong here? Tell us. A question that needed asking usually means a page that needed writing.