AccountedPro - Developer reference

For engineers extending the app or writing code that must respect its rules.

The golden rule for custom reads

The permission hooks and field/child redaction cover normal Desk / REST / MCP access. But raw reads bypass redaction: frappe.db.sql(…), and frappe.get_all / get_list used only for row filtering — they respect row conditions but not field masking or child-row hiding — and Server Scripts / custom Query Reports that assemble their own payloads.

If your code returns document contents to a person, run the rows through readable_rows so field masking and child redaction are applied identically:

frappe.call(
    "advanced_permission.api.readable_rows",
    doctype="Sales Invoice",
    names=["INV-0001", "INV-0002"],
    fields=["name", "customer", "grand_total"],  # optional; defaults to all
)
# -> the same rows the person would get through the normal read path, masked per their doors.

For files, gate downloads with the file guard rather than serving bytes directly:

from advanced_permission.permission.file_guard import assert_file_access
assert_file_access(file_url, user)   # raises if the person may not have this attachment

Whitelisted API

Method Purpose
simulate(user, doctype, name=None) The engine's answer for a user: row condition, visible/total counts, cascade sources, and (with name) opening doors + actions + field access. Manager-gated; powers the Simulator.
readable_rows(doctype, names, fields=None) Rows with the caller's field/child redaction applied — the safe way for custom code to return contents.
has_restrictions(doctype) Whether the DocType has an enabled rule (a cheap client-side check).
get_rule(target_doctype) / save_rule(payload) Load / upsert a whole rule (used by the builder).
list_rules() DocTypes that have a rule, with door counts.
builder_meta() / child_tables(dt) / link_fields(dt) / doc_fields(dt) Metadata for the builder UI.

How a decision is made

  • List WHEREquery_conditions unions the applicable doors' scopes, ANDs cascade Gates, and honours default_deny. A door whose Current user is gate excludes the person is skipped, so a per-user door never gates everyone out. Fails closed on error.
  • Per-documenthas_permission evaluates the opening doors, cascade Gate/Grant/Inherit, and approved grants. Fails safe (defers) on error.
  • Scope compilation — each Field-condition chip compiles to SQL with every value escaped; a compiled fragment can contain a literal %, so per-doc checks escape values inline rather than as bound parameters. Blank sub-conditions are dropped, so an incomplete chip can never emit malformed SQL.

The DocTypes behind it

Useful when granting permissions or moving configuration between sites.

DocType Holds
Access Rule One per governed DocType — doors, cascade, guards, request policy
Access Door (child) A single grant — who × which rows × what they can do
Access Profile A reusable bundle of actions + default field access
Access Profile Field Rule (child) A field → access-level entry on a profile
Access Cascade Target (child) Push visibility onto a linked DocType (Gate/Grant/Inherit)
Access Link Guard (child) Block saving a link to a record the person can't access
Access Grant Request (+ Approver child) A request for elevated access, with routing + expiry
Access Log The audit trail
Throttle Rule Per-window read / export caps

The never-govern list

The app never wires its hooks onto core / meta DocTypes (DocType, DocField, Report, Property Setter, …) or its own config DocTypes. Governing meta DocTypes breaks Frappe's dynamic-link machinery — the symptom is “No permission for DocType” on ordinary forms. If you add a config DocType to the app, add it to that list.

Back to Advanced Permission.

Discard
Save
This page has been updated since your last edit. Your draft may contain outdated content. Load Latest Version

On this page

Review Changes ← Back to Content
Message Status Space Raised By Last update on