Compare commits

..

6 Commits

Author SHA1 Message Date
Shariq Ansari
6e9c09e085 Merge pull request #58717 from shariquerik/feat/desk-v2-company-item
feat(desk-v2): contribute the Default Company navigation item kind
2026-09-02 21:31:29 +05:30
shariquerik
e0a862fbe4 docs: keep only what the default company helper's name does not say
Greptile: the first line restated the return expression. What is left is the part
that is not visible from the code -- the renderer reads the same key, which is what
stops the item being filtered against one company and drawn pointing at another.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 20:58:42 +05:30
shariquerik
626d8b322c feat(desk-v2): contribute the Default Company navigation item kind
The first navigation item kind contributed by an app that is not frappe, which is
what charter point 6 of frappe/frappe#42226 promised and frappe/frappe#42424 asked
for: an app adds a kind through the same mechanism the framework's own eight go
through, and the framework grows no case for it.

The kind is one folder under `setup/navigation_item_type/default_company/`: the
`Navigation Item Type` record, which arrives at `bench migrate`; `frontend/item.js`
beside it, which arrives at `bench build`; and `default_company.py`, which
`hooks.py` names under `navigation_item_resolvers`. One row in the Setup sidebar
uses it, above the `Company` list.

It points at the company this site works in. That is a destination none of the
eight kinds can express: a `Record` item names its document, and the company's
name is chosen during the setup wizard, so ERPNext has no name to ship. The
renderer computes it from `boot.sysdefaults.company`, which every desk v2 boot
already sends, and the resolver reads the same key -- so the item cannot be
filtered against one company and drawn pointing at another.

The type declares the `Custom` permission rule rather than `Readable DocType`,
and that is the reason it carries server code at all. `Readable DocType` asks
whether a person may read `Company`; the honest question is whether they may open
*this* company, which a `User Permission` decides and which ERPNext sites use
routinely. Measured both ways on a real site: a System Manager pinned to another
company keeps the item under `Readable DocType` and loses it under `Custom`.

The shipped row carries no label on purpose, so the renderer's fallback names the
item after the company itself.

One thing the build found: a `Global Defaults` naming a company somebody has since
deleted makes `has_permission` raise. Left alone, the framework fails the kind
closed and writes an Error Log -- and would write another on every boot of every
session, because the cause is the site's data rather than a passing fault. It is
answered as the same "nothing to point at" an unfinished setup wizard gets. The
leak is invisible to Administrator, who never reaches the document.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 20:53:22 +05:30
Shariq Ansari
7fe6b46a9e Merge pull request #58713 from shariquerik/feat/desk-v2-module-rail
feat(desk-v2): ship ERPNext's module-primary rail and its module sidebars
2026-09-02 20:18:24 +05:30
shariquerik
8b93d25824 test: assert the shipped rows, not what the resolver made of them
Greptile P2, and right: the fixture checks read `resolve_navigation`, which has
already dropped a row naming a missing doctype, a heading over nothing and a
linked item whose sidebar emptied. Against that output they were asserting that
the resolver works, which is frappe's test.

They now read the standard `Rail` and `Sidebar` rows as authored. Checked that
each can fail: an orphan `parent_key` and an empty section both insert happily.
A missing doctype does not -- `link_to` is a Dynamic Link and `_validate_links`
refuses the row at import -- so that test now says what it is actually for, a
doctype removed after the rows were imported.

Adds one: every `parent_key` names a section beside it. An orphan is promoted to
the top level rather than dropped, so it loses its nesting in silence.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:32:06 +05:30
shariquerik
9551f213ae feat(desk-v2): ship ERPNext's module-primary rail and its module sidebars
The module-primary half of frappe/frappe#42226's charter point 2, opposite CRM's
doctype-primary rail: the same table, the same resolver and the same item kinds,
with modules as the rail's primary items.

One `Rail` record of 20 items -- 18 `Sidebar` items over a module sidebar each,
and two `Module` items for the modules whose sidebar would hold one row or none.
The sidebars are authored, not derived: the module *page* keeps deriving from
module contents and the two lists differ on purpose, which is what desk v1's own
curation already says -- 107 doctypes sit on a module page and not in that
module's sidebar, and 101 sidebar links point outside their module.

The rows are converted from desk v1's module sidebars, which stay untouched and
keep serving v1. 486 v1 rows become 317: `Report`, `Dashboard`, `Workspace` and
`Page` items have no desk v2 destination and are not authored, headings left
over nothing are dropped, and two duplicate rows in Accounts go. `Portal` is on
v1's dock and is not authored at all -- it holds no doctypes, so it has neither
a sidebar to open nor a module page to land on.

ERPNext ships no navigation code: the rows arrive through `sync_for`'s
app-rooted walk at migrate.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
2026-09-02 19:20:00 +05:30
57 changed files with 5776 additions and 432 deletions

View File

@@ -4,36 +4,6 @@ set -e
cd ~ || exit
# Authenticate git against github.com with the job token: anonymous git-over-HTTPS from the
# runners gets throttled to a 401, which kills whichever clone is in flight — the frappe fetch
# below, or payments under `bench get-app`. See the PR description.
#
# A credential helper rather than a url.insteadOf rewrite, because `git clone` PERSISTS a
# rewritten URL into the new repo's .git/config: an insteadOf would leave the token sitting in
# apps/payments/.git/config on the runner. A helper is consulted only when github.com actually
# challenges, and leaves the stored remote URL untouched. Passing it through GIT_CONFIG_* keeps
# the token out of ~/.gitconfig too, and child processes inherit it (bench shells out to git).
ci_github_token=${CI_GITHUB_TOKEN:-${GITHUB_TOKEN:-}}
if [ -n "$ci_github_token" ]; then
export CI_GITHUB_TOKEN="$ci_github_token"
export GIT_CONFIG_COUNT=3
# Reset first: git runs EVERY configured helper and calls `store` on them after a successful
# auth, so a `credential.helper=store` inherited from the image's gitconfig would write the
# token to ~/.git-credentials. An empty value clears the list before ours is added.
export GIT_CONFIG_KEY_0="credential.helper"
export GIT_CONFIG_VALUE_0=""
export GIT_CONFIG_KEY_1="credential.https://github.com.username"
export GIT_CONFIG_VALUE_1="x-access-token"
export GIT_CONFIG_KEY_2="credential.https://github.com.helper"
# Single-quoted: $CI_GITHUB_TOKEN is expanded by the shell git runs the helper in, so the
# token is read from the environment at call time and never stored anywhere. Answering only
# `get` makes the helper inert for git's `store`/`erase` calls.
export GIT_CONFIG_VALUE_2='!f() { test "$1" = get && echo "password=$CI_GITHUB_TOKEN"; }; f'
fi
# Whatever happens, never sit on a credential prompt: fail fast and legibly instead.
export GIT_TERMINAL_PROMPT=0
githubbranch=${GITHUB_BASE_REF:-${GITHUB_REF##*/}}
frappeuser=${FRAPPE_USER:-"frappe"}
frappecommitish=${FRAPPE_BRANCH:-}

View File

@@ -121,8 +121,6 @@ jobs:
env:
DB: mariadb
TYPE: server
# Anonymous git to github.com gets throttled to a 401; authenticate the clones.
CI_GITHUB_TOKEN: ${{ github.token }}
- name: Run Patch Tests
run: |

View File

@@ -129,8 +129,6 @@ jobs:
TYPE: server
FRAPPE_USER: ${{ github.event.inputs.user }}
FRAPPE_BRANCH: ${{ github.event.inputs.branch }}
# Anonymous git to github.com gets throttled to a 401; authenticate the clones.
CI_GITHUB_TOKEN: ${{ github.token }}
- name: Run Tests
run: |

View File

@@ -102,8 +102,6 @@ jobs:
TYPE: server
FRAPPE_USER: ${{ github.event.inputs.user }}
FRAPPE_BRANCH: ${{ github.event.client_payload.sha || github.event.inputs.branch }}
# Anonymous git to github.com gets throttled to a 401; authenticate the clones.
CI_GITHUB_TOKEN: ${{ github.token }}
DB_HOST: 127.0.0.1
DB_USER_HOST: '%'
WKHTMLTOX_DEB: /tmp/wkhtmltox.deb

View File

@@ -103,8 +103,6 @@ jobs:
DB: postgres
TYPE: server
FRAPPE_BRANCH: develop
# Anonymous git to github.com gets throttled to a 401; authenticate the clones.
CI_GITHUB_TOKEN: ${{ github.token }}
BENCH_CACHE_DIR: /home/runner/bench-cache
- name: Warm up test data

View File

@@ -1489,10 +1489,10 @@ balanced-match@^4.0.2:
resolved "https://registry.yarnpkg.com/balanced-match/-/balanced-match-4.0.4.tgz#bfb10662feed8196a2c62e7c68e17720c274179a"
integrity sha512-BLrgEcRTwX2o6gGxGOCNyMvGSp35YofuYzw9h1IMTRmKqttAZZVU67bdb9Pr2vUHA8+j3i2tJfjO6C6+4myGTA==
baseline-browser-mapping@^2.11.12:
version "2.11.20"
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.11.20.tgz#26078c7a4b08299656ea7ddceaebec955dc44303"
integrity sha512-H0ulySigv6icDJ1F7SjtdCD6PrhTpdYCmP0CactWy1+ekh0AFd0o1Wn5T8b+hnTmdBx19u9yhL6wvCylXMY7zw==
baseline-browser-mapping@^2.10.38:
version "2.10.40"
resolved "https://registry.yarnpkg.com/baseline-browser-mapping/-/baseline-browser-mapping-2.10.40.tgz#f372c8eb36ff4ad0b5e7ae467014abef124554ba"
integrity sha512-BSSLZ9/Cjjv7Gtj5B68ZzXcXUg8iOf3fme+FCuh8rC/Go+Kmh8cox7M3A8dolou16s64QjLPOSdngh7GxXvkSw==
brace-expansion@^5.0.5:
version "5.0.7"
@@ -1509,15 +1509,15 @@ brace-expansion@^5.0.8:
balanced-match "^4.0.2"
browserslist@^4.24.0:
version "4.28.8"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.8.tgz#a3c79ceb70028527e5da7dafc887f3200b5168c0"
integrity sha512-V2NpofLblG64mfOtSgDhOJESZEGogzDMBv/q+W6oc4LXWP/q75eOXoOaaOu1EOadB9U4Bwx/e0yzbvwKH8zalA==
version "4.28.4"
resolved "https://registry.yarnpkg.com/browserslist/-/browserslist-4.28.4.tgz#dd8b8167a32845ff5f8cd6ce13f5abba16cd04c9"
integrity sha512-MTc8i/x9jBQd1iMw2CFGS+rwMa07eYjLR0CCTLDACl9xhxy+nIs3KeML/biicXtk9JrZ6dnnTatmc7ErPXIxqw==
dependencies:
baseline-browser-mapping "^2.11.12"
caniuse-lite "^1.0.30001809"
electron-to-chromium "^1.5.402"
node-releases "^2.0.53"
update-browserslist-db "^1.3.0"
baseline-browser-mapping "^2.10.38"
caniuse-lite "^1.0.30001799"
electron-to-chromium "^1.5.376"
node-releases "^2.0.48"
update-browserslist-db "^1.2.3"
call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
version "1.0.2"
@@ -1527,10 +1527,10 @@ call-bind-apply-helpers@^1.0.1, call-bind-apply-helpers@^1.0.2:
es-errors "^1.3.0"
function-bind "^1.1.2"
caniuse-lite@^1.0.30001809:
version "1.0.30001810"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001810.tgz#4970b477dea3278374de9bc43aa8f5d39fc3cda2"
integrity sha512-TITQPUkaz+aVk5GL6NhOdwk1aEaNTSDPsGFWrTuhKGtjTF70jL/Oht2W4c6rXUe5fu7Ie19VIahAXHIIiWWNeg==
caniuse-lite@^1.0.30001799:
version "1.0.30001800"
resolved "https://registry.yarnpkg.com/caniuse-lite/-/caniuse-lite-1.0.30001800.tgz#b896c773e1c39400809415162bb5320371291b36"
integrity sha512-MMHtuAz9Ys840zAY5F4k6fV5GaivZ9sPk+nz0mY+GYVzRBnYkN0mpqkSR92oWRQ19yQWo4HvBV/FnC16AJX8MA==
ccount@^2.0.0:
version "2.0.1"
@@ -1697,10 +1697,10 @@ dunder-proto@^1.0.1:
es-errors "^1.3.0"
gopd "^1.2.0"
electron-to-chromium@^1.5.402:
version "1.5.420"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.420.tgz#fc66d26a722d6f227e2092acdf38dd55b198cb44"
integrity sha512-2yD6XreGusOfNV+dUcvipJEXc3n/n7fgr7996aszTG+YY5E4mqM4tOq/3uhP129cazL9YHbVWSpc79ePotWtPA==
electron-to-chromium@^1.5.376:
version "1.5.383"
resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.5.383.tgz#5bd22306497d454103b289b0fef97260c56d0855"
integrity sha512-I2484/KkAvl8lm9VyjH2JnbOIV0d/UCqT7gbzs6l+o6Vmn9wgB66uVcKX+Vk6HrXtY6fbWTOEXuv8waDTuFNCw==
engine.io-client@~6.5.1:
version "6.5.4"
@@ -3012,10 +3012,10 @@ natural-compare@^1.4.0:
resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7"
integrity sha512-OWND8ei3VtNC9h7V60qff3SVobHr996CTwgxubgyQYEpg290h9J0buyECNNJexkFm5sOajh5G116RYA1c8ZMSw==
node-releases@^2.0.53:
version "2.0.54"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.54.tgz#09af17d5647aa9f221ec5cf2becb95b68a981afe"
integrity sha512-YHs7BmmcsdAI5Ozuf8JZo6PT0mv2GIWC9vMfvUC3dp65M8hn7Ux8CPL+2oBI7juNuj9d0ndhTcznq2ODBps9cQ==
node-releases@^2.0.48:
version "2.0.50"
resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.50.tgz#597197a852071ce42fc2550e58e223242bcba969"
integrity sha512-J6l92tKHX6w8Jy5nO1Vuc01NoIiRGi/d6qBKVxh+IQ8Cr3b6HbVNfKiF8ZpFKufTwpwxMmce2W3iQZ861ZRyTg==
object-assign@^4.1.1:
version "4.1.1"
@@ -3589,10 +3589,10 @@ unist-util-visit@^5.0.0:
unist-util-is "^6.0.0"
unist-util-visit-parents "^6.0.0"
update-browserslist-db@^1.3.0:
version "1.3.2"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.3.2.tgz#9d99fbff56c50bb11ba5fd35cece5916da595836"
integrity sha512-UQ+MSxlhRm1bzjhU+DcuXfjFO1FzNtqhK5+9Yvlp90ItDLk5vT932A0rFu619nf7RVS+Y/VeaUW1jaRDqZ8VJw==
update-browserslist-db@^1.2.3:
version "1.2.3"
resolved "https://registry.yarnpkg.com/update-browserslist-db/-/update-browserslist-db-1.2.3.tgz#64d76db58713136acbeb4c49114366cc6cc2e80d"
integrity sha512-Js0m9cx+qOgDxo0eMiFGEueWztz+d4+M3rGlmKPT+T4IS/jP4ylw3Nwpu6cpTTP8R1MAC1kF4VbdLt3ARf209w==
dependencies:
escalade "^3.2.0"
picocolors "^1.1.1"

View File

@@ -122,7 +122,6 @@
"description": "Setting Account Type helps in selecting this Account in transactions.",
"fieldname": "account_type",
"fieldtype": "Select",
"in_preview": 1,
"in_standard_filter": 1,
"label": "Account Type",
"oldfieldname": "account_type",
@@ -204,7 +203,7 @@
"idx": 1,
"is_tree": 1,
"links": [],
"modified": "2026-09-03 12:59:42.190900",
"modified": "2026-08-21 23:11:37.851001",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Account",

View File

@@ -62,7 +62,7 @@ frappe.treeview_settings["Account"] = {
const flags = [];
if (node.data.account_number) {
flags.push(frappe.ui.badge({ label: node.data.account_number }));
flags.push(frappe.ui.badge({ label: node.data.account_number, size: "sm" }));
}
const company = frappe.treeview_settings["Account"].treeview?.page?.fields_dict?.company?.get_value();
@@ -72,21 +72,26 @@ frappe.treeview_settings["Account"] = {
company_currency &&
node.data.account_currency !== company_currency
) {
flags.push(frappe.ui.badge({ label: node.data.account_currency, theme: "blue" }));
flags.push(frappe.ui.badge({ label: node.data.account_currency, theme: "blue", size: "sm" }));
}
if (node.data.freeze_account === "Yes") {
flags.push(
frappe.ui.badge({
label: __("Frozen"),
icon: "lock",
title: __("Frozen - entries restricted"),
theme: "orange",
})
$(
`<span class="inline-flex text-ink-gray-4" title="${__("Frozen — entries restricted")}">
${frappe.utils.icon("lock", "sm")}
</span>`
)[0]
);
}
erpnext.utils.render_tree_node_flags(node, flags);
if (flags.length) {
const $flags = $(
'<span class="tree-node-flags inline-flex items-center gap-1.5 ms-2 shrink-0"></span>'
);
flags.forEach((flag) => $flags.append(flag));
$flags.insertAfter(node.$tree_link.find("a.tree-label"));
}
},
on_node_render: function (node, deep) {
const render_balances = () => {

View File

@@ -12,19 +12,6 @@ frappe.treeview_settings["Cost Center"] = {
],
root_label: "Cost Centers",
get_tree_nodes: "erpnext.accounts.utils.get_children",
get_label: function (node) {
// clean display name — the number renders as a badge (see onrender)
return frappe.utils.escape_html(node.data.cost_center_name || node.title || node.label);
},
onrender: function (node) {
if (node.is_root || !node.data) return;
const flags = [];
if (node.data.cost_center_number) {
flags.push(frappe.ui.badge({ label: node.data.cost_center_number }));
}
erpnext.utils.render_tree_node_flags(node, flags);
},
add_tree_node: "erpnext.accounts.utils.add_cc",
menu_items: [
{

View File

@@ -190,10 +190,8 @@ class TemplateStructureValidator(Validator):
if not row.calculation_formula:
result.add_error(
ValidationIssue(
message=_("{0} is required when {1} is {2}").format(
get_formula_field_label(row.data_source),
row.meta.get_translated_label("data_source"),
_(row.data_source),
message=_("{0} is required for {1}").format(
get_formula_field_label(row.data_source), row.data_source
),
row_idx=row.idx,
)
@@ -221,14 +219,7 @@ class DependencyValidator(Validator):
for row in self.template.rows:
if row.reference_code and row.data_source == "Calculated Amount" and row.calculation_formula:
# skip self-reference, `CalculationFormulaValidator` already reports it
deps = [
code
for code in extract_reference_codes_from_formula(
row.calculation_formula, list(available_codes)
)
if code != row.reference_code
]
deps = extract_reference_codes_from_formula(row.calculation_formula, list(available_codes))
if deps:
graph[row.reference_code] = deps
@@ -290,9 +281,7 @@ class DependencyValidator(Validator):
row_idx = self._get_row_idx(ref_code)
result.add_error(
ValidationIssue(
message=_("Line references undefined in {0}: {1}").format(
get_formula_field_label("Calculated Amount"), ", ".join(undefined)
),
message=_("Line References undefined in Formula: {0}").format(", ".join(undefined)),
row_idx=row_idx,
)
)
@@ -319,6 +308,17 @@ class CalculationFormulaValidator(Validator):
if row.data_source != "Calculated Amount":
return result
if not row.calculation_formula:
result.add_error(
ValidationIssue(
message=_("{0} is required for Calculated Amount").format(
get_formula_field_label(row.data_source)
),
row_idx=row.idx,
)
)
return result
formula = self._preprocess_formula(row.calculation_formula)
row.calculation_formula = formula
@@ -343,6 +343,16 @@ class CalculationFormulaValidator(Validator):
)
)
# Check undefined references
undefined = set(refs) - set(available_codes)
if undefined:
result.add_error(
ValidationIssue(
message=_("Formula references undefined codes: {0}").format(", ".join(undefined)),
row_idx=row.idx,
)
)
# Try to evaluate with dummy values
eval_error = self._test_formula_evaluation(formula, available_codes)
if eval_error:
@@ -405,6 +415,17 @@ class AccountFilterValidator(Validator):
if row.data_source != "Account Data":
return result
if not row.calculation_formula:
result.add_error(
ValidationIssue(
message=_("{0} is required for Account Data").format(
get_formula_field_label(row.data_source)
),
row_idx=row.idx,
)
)
return result
try:
filter_config = json.loads(row.calculation_formula)
error = self._validate_filter_structure(
@@ -416,9 +437,7 @@ class AccountFilterValidator(Validator):
if error:
result.add_error(
ValidationIssue(
message=_("[{0}] {1}", context="Financial Report Template").format(
get_formula_field_label(row.data_source), error
),
message=_("{0}: {1}").format(get_formula_field_label(row.data_source), error),
row_idx=row.idx,
)
)
@@ -426,9 +445,8 @@ class AccountFilterValidator(Validator):
except json.JSONDecodeError as e:
result.add_error(
ValidationIssue(
message=_("[{0}] {1}", context="Financial Report Template").format(
get_formula_field_label(row.data_source),
_("Invalid JSON format: {0}").format(str(e)),
message=_("{0}: Invalid JSON format: {1}").format(
get_formula_field_label(row.data_source), str(e)
),
row_idx=row.idx,
)
@@ -536,9 +554,8 @@ class FormulaValidator(Validator):
frappe.clear_last_message()
if isinstance(e, frappe.PermissionError):
message = _("[{0}] {1}", context="Financial Report Template").format(
get_formula_field_label(row.data_source),
_("Method '{0}' must be whitelisted and permit GET requests").format(api_path),
message = _("{0}: Method '{1}' must be whitelisted and permit GET requests").format(
get_formula_field_label(row.data_source), api_path
)
else:
message = _("Could not validate {0}: {1}").format(

View File

@@ -854,7 +854,6 @@
"added": 0,
"child": 1,
"collapsible": 1,
"filters": "{\"is_return\": 1}",
"hidden": 0,
"indent": 0,
"is_default_module": 0,
@@ -865,7 +864,8 @@
"open_in_new_tab": 0,
"route_options": "{\"is_return\": 1}",
"show_arrow": 0,
"type": "Link"
"type": "Link",
"filters": "{\"is_return\": 1}"
},
{
"added": 0,
@@ -931,7 +931,6 @@
"added": 0,
"child": 1,
"collapsible": 1,
"filters": "{\"is_return\": 1}",
"hidden": 0,
"indent": 0,
"is_default_module": 0,
@@ -942,7 +941,8 @@
"open_in_new_tab": 0,
"route_options": "{\"is_return\": 1}",
"show_arrow": 0,
"type": "Link"
"type": "Link",
"filters": "{\"is_return\": 1}"
},
{
"added": 0,
@@ -1154,6 +1154,20 @@
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 1,
"label": "Payments",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Section Break"
},
{
"added": 0,
"child": 1,
@@ -1404,12 +1418,27 @@
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 1,
"label": "Financial Reports",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Section Break"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"icon": "wallet",
"indent": 1,
"is_default_module": 0,
"keep_closed": 0,
"label": "Financial Reports",
"link_type": "DocType",
"open_in_new_tab": 1,
"open_in_new_tab": 0,
"show_arrow": 0,
"type": "Section Break"
},
@@ -1848,7 +1877,7 @@
"type": "Link"
}
],
"modified": "2026-09-01 17:33:21.459367",
"modified": "2026-08-28 12:00:00.000000",
"modified_by": "Administrator",
"module": "Accounts",
"name": "Accounts",

View File

@@ -1359,28 +1359,22 @@ def get_children(
parent_fieldname = "parent_" + doctype.lower().replace(" ", "_")
fields = ["name as value", "is_group as expandable"]
filters = [["docstatus", "<", 2]]
if frappe.db.has_column(doctype, "disabled"):
if include_disabled:
# the tree marks disabled rows, so it needs the flag
fields.append("disabled")
else:
filters.append(["disabled", "=", False])
# extra columns the tree views render as badges / clean labels
node_fields = {
"Account": ["root_type", "account_name", "account_number", "account_currency", "freeze_account"],
"Cost Center": ["cost_center_name", "cost_center_number"],
}
fields += node_fields.get(doctype, [])
if frappe.db.has_column(doctype, "disabled") and not include_disabled:
filters.append(["disabled", "=", False])
if is_root:
filters.append(IfNull(Field(parent_fieldname), "") == "")
filters.append(["company", "=", company])
if doctype == "Account":
fields.append("report_type")
else:
filters.append([parent_fieldname, "=", parent])
fields.append(parent_fieldname + " as parent")
account_fields = ["account_name", "account_number", "account_currency", "freeze_account"]
if is_root:
fields += ["root_type", "report_type", *account_fields] if doctype == "Account" else []
filters.append(["company", "=", company])
else:
fields += ["root_type", *account_fields] if doctype == "Account" else []
fields += [parent_fieldname + " as parent"]
acc = frappe.get_list(doctype, fields=fields, filters=filters)

View File

@@ -0,0 +1,48 @@
{
"app": "erpnext",
"creation": "2026-08-16 00:00:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"header_icon": "layers",
"idx": 0,
"items": [
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Bulk Transaction Log Detail",
"link_to": "Bulk Transaction Log Detail",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Bulk Transaction Log",
"link_to": "Bulk Transaction Log",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
}
],
"modified": "2026-08-16 00:00:00.000000",
"modified_by": "Administrator",
"module": "Bulk Transaction",
"name": "Bulk Transaction",
"owner": "Administrator",
"sequence_id": 0.0,
"standard": 1,
"title": "Bulk Transaction"
}

View File

@@ -1,6 +1,6 @@
{
"app": "erpnext",
"creation": "2026-08-16 00:00:00",
"creation": "2026-08-16 00:00:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"header_icon": "shopping-cart",
@@ -283,6 +283,97 @@
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"icon": "rocket",
"indent": 1,
"is_default_module": 0,
"keep_closed": 1,
"label": "Subcontracting",
"link_type": "DocType",
"open_in_new_tab": 0,
"show_arrow": 0,
"type": "Section Break"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"icon": "folder-tree",
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Subcontracting BOM",
"link_to": "Subcontracting BOM",
"link_type": "DocType",
"open_in_new_tab": 0,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Subcontracting Inward Order",
"link_to": "Subcontracting Inward Order",
"link_type": "DocType",
"open_in_new_tab": 0,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Subcontracting Delivery",
"link_to": "Stock Entry",
"link_type": "DocType",
"open_in_new_tab": 0,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Subcontracting Order",
"link_to": "Subcontracting Order",
"link_type": "DocType",
"open_in_new_tab": 0,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Subcontracting Receipt",
"link_to": "Subcontracting Receipt",
"link_type": "DocType",
"open_in_new_tab": 0,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
@@ -540,11 +631,12 @@
"type": "Link"
}
],
"modified": "2026-09-01 17:37:29.971719",
"modified": "2026-08-16 00:00:00.000000",
"modified_by": "Administrator",
"module": "Buying",
"name": "Buying",
"owner": "Administrator",
"sequence_id": 0.0,
"standard": 1,
"title": "Buying"
}

View File

@@ -0,0 +1,33 @@
{
"app": "erpnext",
"creation": "2026-08-16 00:00:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"header_icon": "messages-square",
"idx": 0,
"items": [
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Communication Medium",
"link_to": "Communication Medium",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
}
],
"modified": "2026-08-16 00:00:00.000000",
"modified_by": "Administrator",
"module": "Communication",
"name": "Communication",
"owner": "Administrator",
"sequence_id": 0.0,
"standard": 1,
"title": "Communication"
}

View File

@@ -133,6 +133,30 @@
"link_type": "Sidebar",
"title": "Quality"
},
{
"added": 0,
"hidden": 0,
"icon": "messages-square",
"link_to": "Communication",
"link_type": "Sidebar",
"title": "Communication"
},
{
"added": 0,
"hidden": 0,
"icon": "phone",
"link_to": "Telephony",
"link_type": "Sidebar",
"title": "Telephony"
},
{
"added": 0,
"hidden": 0,
"icon": "layers",
"link_to": "Bulk Transaction",
"link_type": "Sidebar",
"title": "Bulk Transaction"
},
{
"added": 0,
"hidden": 0,
@@ -140,9 +164,17 @@
"link_to": "Subcontracting",
"link_type": "Sidebar",
"title": "Subcontracting"
},
{
"added": 0,
"hidden": 0,
"icon": "file-code",
"link_to": "EDI",
"link_type": "Sidebar",
"title": "EDI"
}
],
"modified": "2026-09-02 14:58:17.082794",
"modified": "2026-08-28 12:00:00.000000",
"modified_by": "Administrator",
"name": "erpnext",
"owner": "Administrator",

View File

@@ -0,0 +1,48 @@
{
"app": "erpnext",
"creation": "2026-08-16 00:00:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"header_icon": "file-code",
"idx": 0,
"items": [
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Code List",
"link_to": "Code List",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Common Code",
"link_to": "Common Code",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
}
],
"modified": "2026-08-16 00:00:00.000000",
"modified_by": "Administrator",
"module": "EDI",
"name": "EDI",
"owner": "Administrator",
"sequence_id": 0.0,
"standard": 1,
"title": "EDI"
}

View File

@@ -21,101 +21,9 @@
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"icon": "phone",
"indent": 1,
"is_default_module": 0,
"keep_closed": 0,
"label": "Telephony",
"link_type": "DocType",
"open_in_new_tab": 0,
"show_arrow": 0,
"type": "Section Break"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"icon": "settings",
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Incoming Call Settings",
"link_to": "Incoming Call Settings",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"icon": "settings",
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Voice Call Settings",
"link_to": "Voice Call Settings",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Call Log",
"link_to": "Call Log",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Telephony Call Type",
"link_to": "Telephony Call Type",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Communication Medium",
"link_to": "Communication Medium",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
}
],
"modified": "2026-09-02 14:58:17.082794",
"modified": "2026-08-16 00:00:00.000000",
"modified_by": "Administrator",
"module": "ERPNext Integrations",
"name": "ERPNext Integrations",

View File

@@ -10,6 +10,28 @@ source_link = "https://github.com/frappe/erpnext"
app_logo_url = "/assets/erpnext/images/erpnext-logo.svg"
app_home = "/desk/home"
# ERPNext addresses its doctypes through their module: /apps/erpnext/accounts/
# sales-invoice/SI-001 (frappe/frappe#42211). The shape is fixed per app rather than per
# doctype, foreign doctypes included, because a shape that varied inside one app would be
# unparseable.
#
# desk v2 only. On `develop` this is dead config, and it is what the module rail below
# needs to have anywhere to land: a `Module` item resolves to a module page, and a
# non-modular prefix has no module route at all.
app_modular = True
# The server half of ERPNext's own navigation item kind, keyed by type name. The other two
# halves are files: the `Navigation Item Type` record, which arrives at migrate, and the
# renderer beside it, which arrives at build. Server code is optional for a kind, and this
# one needs it because the type declares the `Custom` permission rule -- the framework
# appends `.can_see` to this path and hands it every item of the kind at once
# (frappe/frappe#42424).
#
# desk v2 only, and harmless on `develop`, where nothing reads the hook.
navigation_item_resolvers = {
"Default Company": "erpnext.setup.navigation_item_type.default_company.default_company"
}
add_to_apps_screen = [
{
"name": app_name,
@@ -21,23 +43,6 @@ add_to_apps_screen = [
}
]
# Modules that are a folder of code and nothing else. Their doctypes, reports and controllers stay
# where they are; what they no longer own is navigation, which now sits in the sidebar named beside
# each. Left in the dock, each would carry an entry of its own for two to four records. See
# `frappe.utils.modules.get_code_only_modules`.
#
# The value names the modules that inherited that navigation, so a Call Log or a Code List resolves
# to a sidebar the user can actually navigate to instead of dead-ending in a module the dock never
# shows.
code_only_modules = {
"Telephony": ["ERPNext Integrations"],
# Its one doctype, Communication Medium, describes how a call reaches someone, so it sits in
# the Telephony section beside the call settings rather than in a shell of its own.
"Communication": ["ERPNext Integrations"],
"EDI": ["Utilities"],
"Bulk Transaction": ["Utilities"],
}
develop_version = "17.x.x-develop"
app_include_js = "erpnext.bundle.js"

View File

@@ -1,6 +1,6 @@
{
"app": "erpnext",
"creation": "2026-08-16 00:00:00",
"creation": "2026-08-16 00:00:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"header_icon": "wrench",
@@ -41,7 +41,7 @@
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 1,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Reports",
@@ -67,11 +67,12 @@
"type": "Link"
}
],
"modified": "2026-09-01 19:30:16.713938",
"modified": "2026-08-16 00:00:00.000000",
"modified_by": "Administrator",
"module": "Maintenance",
"name": "Maintenance",
"owner": "Administrator",
"sequence_id": 0.0,
"standard": 1,
"title": "Maintenance"
}

View File

@@ -1,7 +1,6 @@
# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
# See license.txt
import datetime
from unittest.mock import patch
import frappe
from frappe.utils import add_to_date, now_datetime, nowdate
@@ -9,20 +8,12 @@ from frappe.utils import add_to_date, now_datetime, nowdate
from erpnext.accounts.doctype.sales_invoice.mapper import make_sales_return
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
from erpnext.projects.doctype.task.test_task import create_task
from erpnext.projects.doctype.timesheet.timesheet import (
OverlapError,
get_projectwise_timesheet_data,
make_sales_invoice,
)
from erpnext.projects.doctype.timesheet.timesheet import OverlapError, make_sales_invoice
from erpnext.setup.doctype.employee.test_employee import make_employee
from erpnext.tests.utils import ERPNextTestSuite
class TestTimesheet(ERPNextTestSuite):
def test_get_projectwise_timesheet_data_without_allowed_projects(self):
with patch("frappe.get_list", side_effect=[["TS-0001"], []]):
self.assertEqual(get_projectwise_timesheet_data(), [])
def test_timesheet_post_update(self):
frappe.get_doc(
{

View File

@@ -339,14 +339,10 @@ def get_projectwise_timesheet_data(
& (tsd.is_billable == 1)
& tsd.sales_invoice.isnull()
& (tsd.parent.isin(allowed_timesheets))
& ((tsd.project.isin(allowed_projects)) | (tsd.project.isnull()))
)
)
if allowed_projects:
query = query.where((tsd.project.isin(allowed_projects)) | (tsd.project.isnull()))
else:
query = query.where(tsd.project.isnull())
if project:
query = query.where(tsd.project == project)
if parent:

View File

@@ -426,26 +426,6 @@ $.extend(erpnext.utils, {
}
return rows;
},
/**
* Row flags for the Account / Cost Center trees: the caller's badges plus
* a shared "Disabled" marker for records shown through the tree's
* "include disabled" toggle.
* @param {Object} node tree node (from treeview_settings.onrender)
* @param {Array<string|HTMLElement>} flags badge markup / elements
*/
render_tree_node_flags: function (node, flags = []) {
if (cint(node.data?.disabled)) {
flags.push(frappe.ui.badge({ label: __("Disabled"), variant: "outline" }));
node.$tree_link.find("a.tree-label").addClass("text-ink-gray-5");
}
if (!flags.length) return;
const $flags = $(
'<span class="tree-node-flags inline-flex items-center gap-1.5 ms-2 shrink-0"></span>'
);
flags.forEach((flag) => $flags.append(flag));
$flags.insertAfter(node.$tree_link.find("a.tree-label"));
},
get_tree_options: function (option) {
// get valid options for tree based on user permission & locals dict
let unscrub_option = frappe.model.unscrub(option);

View File

@@ -0,0 +1,276 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Rail",
"extends": "",
"idx": 0,
"items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "landmark",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "accounts",
"label": "Accounts",
"link_doctype": "Sidebar",
"link_to": "module_def_accounts",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "handshake",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "crm",
"label": "CRM",
"link_doctype": "Sidebar",
"link_to": "module_def_crm",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "shopping-cart",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "buying",
"label": "Buying",
"link_doctype": "Sidebar",
"link_to": "module_def_buying",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "folder-kanban",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "projects",
"label": "Projects",
"link_doctype": "Sidebar",
"link_to": "module_def_projects",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "store",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "selling",
"label": "Selling",
"link_doctype": "Sidebar",
"link_to": "module_def_selling",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "sliders-horizontal",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "setup",
"label": "Setup",
"link_doctype": "Sidebar",
"link_to": "module_def_setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "building-2",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "manufacturing",
"label": "Manufacturing",
"link_doctype": "Sidebar",
"link_to": "module_def_manufacturing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "package",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "stock",
"label": "Stock",
"link_doctype": "Sidebar",
"link_to": "module_def_stock",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "headset",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "support",
"label": "Support",
"link_doctype": "Sidebar",
"link_to": "module_def_support",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "pocket-knife",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "utilities",
"label": "Utilities",
"link_doctype": "Sidebar",
"link_to": "module_def_utilities",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "archive",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "assets",
"label": "Assets",
"link_doctype": "Sidebar",
"link_to": "module_def_assets",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "wrench",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "maintenance",
"label": "Maintenance",
"link_doctype": "Sidebar",
"link_to": "module_def_maintenance",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "globe",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "regional",
"label": "Regional",
"link_doctype": "Sidebar",
"link_to": "module_def_regional",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "plug",
"item_type": "Module",
"keep_closed": 0,
"key": "erpnext-integrations",
"label": "Integrations",
"link_doctype": "Module Def",
"link_to": "ERPNext Integrations",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "shield-check",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "quality-management",
"label": "Quality",
"link_doctype": "Sidebar",
"link_to": "module_def_quality_management",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "messages-square",
"item_type": "Module",
"keep_closed": 0,
"key": "communication",
"label": "Communication",
"link_doctype": "Module Def",
"link_to": "Communication",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "phone",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "telephony",
"label": "Telephony",
"link_doctype": "Sidebar",
"link_to": "module_def_telephony",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "layers",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "bulk-transaction",
"label": "Bulk Transaction",
"link_doctype": "Sidebar",
"link_to": "module_def_bulk_transaction",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "factory",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "subcontracting",
"label": "Subcontracting",
"link_doctype": "Sidebar",
"link_to": "module_def_subcontracting",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"icon": "file-code",
"item_type": "Sidebar",
"keep_closed": 0,
"key": "edi",
"label": "EDI",
"link_doctype": "Sidebar",
"link_to": "module_def_edi",
"switches_app": 0
}
],
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "erpnext",
"owner": "Administrator",
"standard": 1,
"user": ""
}

View File

@@ -1,6 +1,6 @@
{
"app": "erpnext",
"creation": "2026-08-16 00:00:00",
"creation": "2026-08-16 00:00:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"header_icon": "globe",
@@ -21,6 +21,22 @@
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"icon": "settings",
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "UAE VAT Settings",
"link_to": "UAE VAT Settings",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
@@ -42,7 +58,7 @@
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 1,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Reports",
@@ -116,11 +132,12 @@
"type": "Link"
}
],
"modified": "2026-09-01 17:54:06.004401",
"modified": "2026-08-16 00:00:00.000000",
"modified_by": "Administrator",
"module": "Regional",
"name": "Regional",
"owner": "Administrator",
"sequence_id": 0.0,
"standard": 1,
"title": "Regional"
}

View File

@@ -1203,8 +1203,6 @@ def get_billing_shipping_address(
@frappe.whitelist(methods=["POST"])
def create_transaction_deletion_request(company: str):
frappe.only_for("System Manager")
# User Permission check
frappe.has_permission("Company", ptype="delete", doc=company, throw=True)
from erpnext.setup.doctype.transaction_deletion_record.transaction_deletion_record import (
is_deletion_doc_running,
@@ -1213,7 +1211,6 @@ def create_transaction_deletion_request(company: str):
is_deletion_doc_running(company)
tdr = frappe.get_doc({"doctype": "Transaction Deletion Record", "company": company})
tdr.flags.ignore_permissions = 1
tdr.insert()
tdr.generate_to_delete_list()

View File

@@ -1,6 +1,5 @@
{
"actions": [],
"allow_bulk_edit": 1,
"autoname": "TDL.####",
"creation": "2021-04-06 20:17:18.404716",
"doctype": "DocType",
@@ -167,18 +166,19 @@
"read_only": 1
}
],
"in_create": 1,
"index_web_pages_for_search": 1,
"is_submittable": 1,
"links": [],
"modified": "2026-09-02 20:32:19.679290",
"modified": "2025-11-18 15:02:46.427695",
"modified_by": "Administrator",
"module": "Setup",
"name": "Transaction Deletion Record",
"naming_rule": "Expression",
"naming_rule": "Expression (old style)",
"owner": "Administrator",
"permissions": [
{
"create": 1,
"delete": 1,
"email": 1,
"export": 1,
"print": 1,
@@ -186,6 +186,7 @@
"report": 1,
"role": "System Manager",
"share": 1,
"submit": 1,
"write": 1
}
],

View File

@@ -0,0 +1,15 @@
{
"creation": "2026-09-03 10:00:00.000000",
"docstatus": 0,
"doctype": "Navigation Item Type",
"idx": 0,
"label": "Default Company",
"modified": "2026-09-03 10:00:00.000000",
"modified_by": "Administrator",
"module": "Setup",
"name": "Default Company",
"owner": "Administrator",
"permission_rule": "Custom",
"target_doctype": "Company",
"type_name": "Default Company"
}

View File

@@ -0,0 +1,67 @@
# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
"""The server half of the `Default Company` navigation item kind.
Optional, and here because this kind needs it: `permission_rule` on the type record is
`Custom`, so the framework hands every item of the kind to `can_see` and takes the list
it returns (`frappe/shell/navigation_filter.py`). The path is named in `hooks.py` under
`navigation_item_resolvers`, keyed by the type name; the framework appends `.can_see`.
It sits beside the record and the renderer rather than in a navigation module of its
own, because a kind is one contribution and not a scattering across three folders.
"""
from typing import TYPE_CHECKING
import frappe
if TYPE_CHECKING:
from frappe.shell.navigation_filter import NavigationContext
def default_company() -> str | None:
"""The same key the renderer reads out of `boot.sysdefaults`, so the item cannot be
filtered against one company and then drawn pointing at another."""
return frappe.defaults.get_defaults().get("company")
def can_see(items: list[dict], context: "NavigationContext") -> list[dict]:
"""Which of these items this user may follow.
`Custom` rather than `Readable DocType`, and that is the whole reason the kind carries
server code at all. The item points at one company *document*, and restricting a user
to a subset of companies with `User Permission` is ordinary on an ERPNext site -- so
the doctype-level bucket would leave the item on the rail for somebody whose only
company is a different one. frappe/frappe#42231 accepted that leak for `Record` items
and wrote it down as a cost; a kind with exactly one destination can afford the honest
check instead.
One permission call for the batch rather than one per item. Every item of this kind
shares the site's default company, so there is one question to ask however many rows
name it -- which is what the batched signature is for (frappe/frappe#42231 measured 553
per-item checks at 3,594 ms against 25 ms for a single pass, inside boot's blocking
fetch).
"""
company = default_company()
# Nothing to point at. Dropped here rather than left for the renderer so the row stays
# out of boot entirely, instead of being sent and then declined by the browser.
if not company:
return []
try:
permitted = frappe.has_permission("Company", doc=company, user=context.user)
except frappe.DoesNotExistError:
# Global Defaults naming a company somebody has since deleted. Left to raise, the
# framework catches it, fails the kind closed and writes one Error Log -- and it would
# write another on the next boot, and on every other person's, because the cause is a
# site's data rather than a passing fault. It is the same "nothing to point at" as an
# unfinished setup wizard, so it is answered the same way.
#
# Caught rather than checked ahead of time: `has_permission` already loads the document
# (lazily, without child tables), so an existence check would be a second query on every
# boot to save one on almost none.
return []
return items if permitted else []

View File

@@ -0,0 +1,35 @@
// The `Default Company` kind: the one company this site works in.
//
// ERPNext's own kind, and the first one contributed by an app that is not frappe
// (frappe/frappe#42424). It exists because the eight framework kinds cannot express it:
// a `Record` item names its document, and the company's name is chosen during the setup
// wizard, so ERPNext has no name to ship. The destination is therefore computed here,
// out of a value the boot already carries.
//
// `boot.sysdefaults` is `frappe.defaults.get_defaults()`, which every desk v2 boot sends
// and which holds `company` on any ERPNext site past setup. Nothing new rides in boot for
// this, and the server half reads the same key when it decides who may see the item, so
// the two cannot point at different companies.
import { routeFor } from "@shell";
export default {
render(item, { boot }) {
const company = boot.sysdefaults?.company;
// A site still in the setup wizard has no default company. The server drops the item
// before boot for exactly this case; this is the second fence, and it is here rather
// than trusted away because a renderer runs on whatever the browser was handed.
if (!company) return null;
return { to: routeFor("Company", company) };
},
// No authored label on the shipped row, deliberately: the company's name is the most
// useful thing this item can say, and it is not knowable when the row is written. An
// authored label would still win (frappe/frappe#42230), so a site that prefers a fixed
// word can set one.
label(item, { boot }) {
return boot.sysdefaults?.company;
},
};

View File

@@ -1,6 +1,6 @@
{
"app": "erpnext",
"creation": "2026-08-16 00:00:00",
"creation": "2026-08-16 00:00:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"header_icon": "sliders-horizontal",
@@ -419,9 +419,9 @@
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 1,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"keep_closed": 1,
"label": "Home",
"link_type": "DocType",
"open_in_new_tab": 1,
@@ -504,11 +504,12 @@
"type": "Link"
}
],
"modified": "2026-09-01 17:52:52.506437",
"modified": "2026-08-16 00:00:00.000000",
"modified_by": "Administrator",
"module": "Setup",
"name": "Setup",
"owner": "Administrator",
"sequence_id": 0.0,
"standard": 1,
"title": "Setup"
}

View File

@@ -0,0 +1,940 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Accounts",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_accounts",
"navigation_items": [
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 0,
"key": "section-setup",
"label": "Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "account",
"label": "Chart of Accounts",
"link_doctype": "DocType",
"link_to": "Account",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "cost-center",
"label": "Chart of Cost Centers",
"link_doctype": "DocType",
"link_to": "Cost Center",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "account-category",
"label": "Account Category",
"link_doctype": "DocType",
"link_to": "Account Category",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "accounting-dimension",
"label": "Accounting Dimension",
"link_doctype": "DocType",
"link_to": "Accounting Dimension",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "currency",
"label": "Currency",
"link_doctype": "DocType",
"link_to": "Currency",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "currency-exchange",
"label": "Currency Exchange",
"link_doctype": "DocType",
"link_to": "Currency Exchange",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "finance-book",
"label": "Finance Book",
"link_doctype": "DocType",
"link_to": "Finance Book",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "mode-of-payment",
"label": "Mode of Payment",
"link_doctype": "DocType",
"link_to": "Mode of Payment",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "payment-term",
"label": "Payment Term",
"link_doctype": "DocType",
"link_to": "Payment Term",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "journal-entry-template",
"label": "Journal Entry Template",
"link_doctype": "DocType",
"link_to": "Journal Entry Template",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "terms-and-conditions",
"label": "Terms and Conditions",
"link_doctype": "DocType",
"link_to": "Terms and Conditions",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "company",
"label": "Company",
"link_doctype": "DocType",
"link_to": "Company",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "fiscal-year",
"label": "Fiscal Year",
"link_doctype": "DocType",
"link_to": "Fiscal Year",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-opening-closing",
"label": "Opening & Closing",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "chart-of-accounts-importer",
"label": "COA Importer",
"link_doctype": "DocType",
"link_to": "Chart of Accounts Importer",
"parent_key": "section-opening-closing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "opening-invoice-creation-tool",
"label": "Opening Invoice Tool",
"link_doctype": "DocType",
"link_to": "Opening Invoice Creation Tool",
"parent_key": "section-opening-closing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "accounting-period",
"label": "Accounting Period",
"link_doctype": "DocType",
"link_to": "Accounting Period",
"parent_key": "section-opening-closing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "exchange-rate-revaluation",
"label": "FX Revaluation",
"link_doctype": "DocType",
"link_to": "Exchange Rate Revaluation",
"parent_key": "section-opening-closing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "period-closing-voucher",
"label": "Period Closing Voucher",
"link_doctype": "DocType",
"link_to": "Period Closing Voucher",
"parent_key": "section-opening-closing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-taxes",
"label": "Taxes",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-taxes-and-charges-template",
"label": "Sales Tax Template",
"link_doctype": "DocType",
"link_to": "Sales Taxes and Charges Template",
"parent_key": "section-taxes",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "purchase-taxes-and-charges-template",
"label": "Purchase Tax Template",
"link_doctype": "DocType",
"link_to": "Purchase Taxes and Charges Template",
"parent_key": "section-taxes",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item-tax-template",
"label": "Item Tax Template",
"link_doctype": "DocType",
"link_to": "Item Tax Template",
"parent_key": "section-taxes",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "tax-category",
"label": "Tax Category",
"link_doctype": "DocType",
"link_to": "Tax Category",
"parent_key": "section-taxes",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "tax-rule",
"label": "Tax Rule",
"link_doctype": "DocType",
"link_to": "Tax Rule",
"parent_key": "section-taxes",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "tax-withholding-category",
"label": "Tax Withholding Category",
"link_doctype": "DocType",
"link_to": "Tax Withholding Category",
"parent_key": "section-taxes",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "tax-withholding-group",
"label": "Tax Withholding Group",
"link_doctype": "DocType",
"link_to": "Tax Withholding Group",
"parent_key": "section-taxes",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "lower-deduction-certificate",
"label": "Deduction Certificate",
"link_doctype": "DocType",
"link_to": "Lower Deduction Certificate",
"parent_key": "section-taxes",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-budgeting",
"label": "Budgeting",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "budget",
"label": "Budget",
"link_doctype": "DocType",
"link_to": "Budget",
"parent_key": "section-budgeting",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "cost-center-allocation",
"label": "Cost Center Allocation",
"link_doctype": "DocType",
"link_to": "Cost Center Allocation",
"parent_key": "section-budgeting",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-share-management",
"label": "Share Management",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "shareholder",
"label": "Shareholder",
"link_doctype": "DocType",
"link_to": "Shareholder",
"parent_key": "section-share-management",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "share-transfer",
"label": "Share Transfer",
"link_doctype": "DocType",
"link_to": "Share Transfer",
"parent_key": "section-share-management",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-subscriptions",
"label": "Subscriptions",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subscription",
"label": "Subscription",
"link_doctype": "DocType",
"link_to": "Subscription",
"parent_key": "section-subscriptions",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subscription-plan",
"label": "Subscription Plan",
"link_doctype": "DocType",
"link_to": "Subscription Plan",
"parent_key": "section-subscriptions",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subscription-settings",
"label": "Subscription Settings",
"link_doctype": "DocType",
"link_to": "Subscription Settings",
"parent_key": "section-subscriptions",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-settings",
"label": "Settings",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "accounts-settings",
"label": "Accounts Settings",
"link_doctype": "DocType",
"link_to": "Accounts Settings",
"parent_key": "section-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "currency-exchange-settings",
"label": "Currency Exchange Settings",
"link_doctype": "DocType",
"link_to": "Currency Exchange Settings",
"parent_key": "section-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 0,
"key": "section-receivables",
"label": "Receivables",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "customer",
"label": "Customer",
"link_doctype": "DocType",
"link_to": "Customer",
"parent_key": "section-receivables",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-invoice",
"label": "Sales Invoice",
"link_doctype": "DocType",
"link_to": "Sales Invoice",
"parent_key": "section-receivables",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 0,
"key": "section-payables",
"label": "Payables",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "supplier",
"label": "Supplier",
"link_doctype": "DocType",
"link_to": "Supplier",
"parent_key": "section-payables",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "purchase-invoice",
"label": "Purchase Invoice",
"link_doctype": "DocType",
"link_to": "Purchase Invoice",
"parent_key": "section-payables",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 0,
"key": "section-payments",
"label": "Payments",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "payment-entry",
"label": "Payment Entry",
"link_doctype": "DocType",
"link_to": "Payment Entry",
"parent_key": "section-payments",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "journal-entry",
"label": "Journal Entry",
"link_doctype": "DocType",
"link_to": "Journal Entry",
"parent_key": "section-payments",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "payment-request",
"label": "Payment Request",
"link_doctype": "DocType",
"link_to": "Payment Request",
"parent_key": "section-payments",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "payment-order",
"label": "Payment Order",
"link_doctype": "DocType",
"link_to": "Payment Order",
"parent_key": "section-payments",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "payment-reconciliation",
"label": "Payment Reconciliation",
"link_doctype": "DocType",
"link_to": "Payment Reconciliation",
"parent_key": "section-payments",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "unreconcile-payment",
"label": "Unreconcile Payment",
"link_doctype": "DocType",
"link_to": "Unreconcile Payment",
"parent_key": "section-payments",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "process-payment-reconciliation",
"label": "Process Payment Reconciliation",
"link_doctype": "DocType",
"link_to": "Process Payment Reconciliation",
"parent_key": "section-payments",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "repost-accounting-ledger",
"label": "Repost Accounting Ledger",
"link_doctype": "DocType",
"link_to": "Repost Accounting Ledger",
"parent_key": "section-payments",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "repost-payment-ledger",
"label": "Repost Payment Ledger",
"link_doctype": "DocType",
"link_to": "Repost Payment Ledger",
"parent_key": "section-payments",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 0,
"key": "section-banking",
"label": "Banking",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bank-clearance",
"label": "Bank Clearance",
"link_doctype": "DocType",
"link_to": "Bank Clearance",
"parent_key": "section-banking",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bank-reconciliation-tool",
"label": "Bank Reconciliation",
"link_doctype": "DocType",
"link_to": "Bank Reconciliation Tool",
"parent_key": "section-banking",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-banking-setup",
"label": "Banking Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bank",
"label": "Bank",
"link_doctype": "DocType",
"link_to": "Bank",
"parent_key": "section-banking-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bank-account",
"label": "Bank Account",
"link_doctype": "DocType",
"link_to": "Bank Account",
"parent_key": "section-banking-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bank-account-type",
"label": "Bank Account Type",
"link_doctype": "DocType",
"link_to": "Bank Account Type",
"parent_key": "section-banking-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bank-account-subtype",
"label": "Bank Account Subtype",
"link_doctype": "DocType",
"link_to": "Bank Account Subtype",
"parent_key": "section-banking-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bank-guarantee",
"label": "Bank Guarantee",
"link_doctype": "DocType",
"link_to": "Bank Guarantee",
"parent_key": "section-banking-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "plaid-settings",
"label": "Plaid Settings",
"link_doctype": "DocType",
"link_to": "Plaid Settings",
"parent_key": "section-banking-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-dunning",
"label": "Dunning",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "dunning",
"label": "Dunning",
"link_doctype": "DocType",
"link_to": "Dunning",
"parent_key": "section-dunning",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "dunning-type",
"label": "Dunning Type",
"link_doctype": "DocType",
"link_to": "Dunning Type",
"parent_key": "section-dunning",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 0,
"key": "section-financial-reports",
"label": "Financial Reports",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "financial-report-template",
"label": "Financial Report Template",
"link_doctype": "DocType",
"link_to": "Financial Report Template",
"parent_key": "section-financial-reports",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Accounts",
"user": ""
}

View File

@@ -0,0 +1,206 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Assets",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_assets",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "asset",
"label": "Asset",
"link_doctype": "DocType",
"link_to": "Asset",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "asset-depreciation-schedule",
"label": "Depreciation Schedule",
"link_doctype": "DocType",
"link_to": "Asset Depreciation Schedule",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "asset-capitalization",
"label": "Asset Capitalization",
"link_doctype": "DocType",
"link_to": "Asset Capitalization",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "asset-movement",
"label": "Asset Movement",
"link_doctype": "DocType",
"link_to": "Asset Movement",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-maintenance",
"label": "Maintenance",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "asset-maintenance-team",
"label": "Asset Maintenance Team",
"link_doctype": "DocType",
"link_to": "Asset Maintenance Team",
"parent_key": "section-maintenance",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "asset-maintenance",
"label": "Asset Maintenance",
"link_doctype": "DocType",
"link_to": "Asset Maintenance",
"parent_key": "section-maintenance",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "asset-maintenance-log",
"label": "Asset Maintenance Log",
"link_doctype": "DocType",
"link_to": "Asset Maintenance Log",
"parent_key": "section-maintenance",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "asset-value-adjustment",
"label": "Asset Value Adjustment",
"link_doctype": "DocType",
"link_to": "Asset Value Adjustment",
"parent_key": "section-maintenance",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "asset-repair",
"label": "Asset Repair",
"link_doctype": "DocType",
"link_to": "Asset Repair",
"parent_key": "section-maintenance",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-setup",
"label": "Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item",
"label": "Item",
"link_doctype": "DocType",
"link_to": "Item",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "asset-category",
"label": "Asset Category",
"link_doctype": "DocType",
"link_to": "Asset Category",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "location",
"label": "Location",
"link_doctype": "DocType",
"link_to": "Location",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "accounts-settings",
"label": "Settings",
"link_doctype": "DocType",
"link_to": "Accounts Settings",
"parent_key": "section-setup",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Assets",
"user": ""
}

View File

@@ -0,0 +1,43 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Bulk Transaction",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_bulk_transaction",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bulk-transaction-log-detail",
"label": "Bulk Transaction Log Detail",
"link_doctype": "DocType",
"link_to": "Bulk Transaction Log Detail",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bulk-transaction-log",
"label": "Bulk Transaction Log",
"link_doctype": "DocType",
"link_to": "Bulk Transaction Log",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Bulk Transaction",
"user": ""
}

View File

@@ -0,0 +1,320 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Buying",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_buying",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "material-request",
"label": "Material Request",
"link_doctype": "DocType",
"link_to": "Material Request",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "request-for-quotation",
"label": "Request for Quotation",
"link_doctype": "DocType",
"link_to": "Request for Quotation",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "supplier-quotation",
"label": "Supplier Quotation",
"link_doctype": "DocType",
"link_to": "Supplier Quotation",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "purchase-order",
"label": "Purchase Order",
"link_doctype": "DocType",
"link_to": "Purchase Order",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "purchase-invoice",
"label": "Purchase Invoice",
"link_doctype": "DocType",
"link_to": "Purchase Invoice",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-setup",
"label": "Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "supplier",
"label": "Supplier",
"link_doctype": "DocType",
"link_to": "Supplier",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "supplier-group",
"label": "Supplier Group",
"link_doctype": "DocType",
"link_to": "Supplier Group",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item",
"label": "Item",
"link_doctype": "DocType",
"link_to": "Item",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "price-list",
"label": "Price List",
"link_doctype": "DocType",
"link_to": "Price List",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "address",
"label": "Address",
"link_doctype": "DocType",
"link_to": "Address",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "contact",
"label": "Contacts",
"link_doctype": "DocType",
"link_to": "Contact",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "supplier-scorecard",
"label": "Supplier Scorecard",
"link_doctype": "DocType",
"link_to": "Supplier Scorecard",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "supplier-scorecard-criteria",
"label": "Supplier Scorecard Criteria",
"link_doctype": "DocType",
"link_to": "Supplier Scorecard Criteria",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "supplier-scorecard-variable",
"label": "Supplier Scorecard Variable",
"link_doctype": "DocType",
"link_to": "Supplier Scorecard Variable",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "supplier-scorecard-standing",
"label": "Supplier Scorecard Standing",
"link_doctype": "DocType",
"link_to": "Supplier Scorecard Standing",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-subcontracting",
"label": "Subcontracting",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subcontracting-bom",
"label": "Subcontracting BOM",
"link_doctype": "DocType",
"link_to": "Subcontracting BOM",
"parent_key": "section-subcontracting",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subcontracting-inward-order",
"label": "Subcontracting Inward Order",
"link_doctype": "DocType",
"link_to": "Subcontracting Inward Order",
"parent_key": "section-subcontracting",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "stock-entry",
"label": "Subcontracting Delivery",
"link_doctype": "DocType",
"link_to": "Stock Entry",
"parent_key": "section-subcontracting",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subcontracting-order",
"label": "Subcontracting Order",
"link_doctype": "DocType",
"link_to": "Subcontracting Order",
"parent_key": "section-subcontracting",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subcontracting-receipt",
"label": "Subcontracting Receipt",
"link_doctype": "DocType",
"link_to": "Subcontracting Receipt",
"parent_key": "section-subcontracting",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-reports",
"label": "Reports",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "buying-settings",
"label": "Settings",
"link_doctype": "DocType",
"link_to": "Buying Settings",
"parent_key": "section-reports",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Buying",
"user": ""
}

View File

@@ -0,0 +1,370 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "CRM",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_crm",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "lead",
"label": "Lead",
"link_doctype": "DocType",
"link_to": "Lead",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "opportunity",
"label": "Opportunity",
"link_doctype": "DocType",
"link_to": "Opportunity",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "customer",
"label": "Customer",
"link_doctype": "DocType",
"link_to": "Customer",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-maintenance",
"label": "Maintenance",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "maintenance-schedule",
"label": "Maintenance Schedule",
"link_doctype": "DocType",
"link_to": "Maintenance Schedule",
"parent_key": "section-maintenance",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "maintenance-visit",
"label": "Maintenance Visit",
"link_doctype": "DocType",
"link_to": "Maintenance Visit",
"parent_key": "section-maintenance",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "warranty-claim",
"label": "Warranty Claim",
"link_doctype": "DocType",
"link_to": "Warranty Claim",
"parent_key": "section-maintenance",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-sales-pipeline",
"label": "Sales Pipeline",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "contract",
"label": "Contract",
"link_doctype": "DocType",
"link_to": "Contract",
"parent_key": "section-sales-pipeline",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "appointment",
"label": "Appointment",
"link_doctype": "DocType",
"link_to": "Appointment",
"parent_key": "section-sales-pipeline",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "communication",
"label": "Communication",
"link_doctype": "DocType",
"link_to": "Communication",
"parent_key": "section-sales-pipeline",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-campaign",
"label": "Campaign",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "campaign",
"label": "Campaign",
"link_doctype": "DocType",
"link_to": "Campaign",
"parent_key": "section-campaign",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "email-campaign",
"label": "Email Campaign",
"link_doctype": "DocType",
"link_to": "Email Campaign",
"parent_key": "section-campaign",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sms-center",
"label": "SMS Center",
"link_doctype": "DocType",
"link_to": "SMS Center",
"parent_key": "section-campaign",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sms-log",
"label": "SMS Log",
"link_doctype": "DocType",
"link_to": "SMS Log",
"parent_key": "section-campaign",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "email-group",
"label": "Email Group",
"link_doctype": "DocType",
"link_to": "Email Group",
"parent_key": "section-campaign",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-setup",
"label": "Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "territory",
"label": "Territory",
"link_doctype": "DocType",
"link_to": "Territory",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "customer-group",
"label": "Customer Group",
"link_doctype": "DocType",
"link_to": "Customer Group",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "contact",
"label": "Contact",
"link_doctype": "DocType",
"link_to": "Contact",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "prospect",
"label": "Prospect",
"link_doctype": "DocType",
"link_to": "Prospect",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-person",
"label": "Sales Person",
"link_doctype": "DocType",
"link_to": "Sales Person",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-stage",
"label": "Sales Stage",
"link_doctype": "DocType",
"link_to": "Sales Stage",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "utm-source",
"label": "Lead Source",
"link_doctype": "DocType",
"link_to": "UTM Source",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-settings",
"label": "Settings",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "crm-settings",
"label": "CRM Settings",
"link_doctype": "DocType",
"link_to": "CRM Settings",
"parent_key": "section-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sms-settings",
"label": "SMS Settings",
"link_doctype": "DocType",
"link_to": "SMS Settings",
"parent_key": "section-settings",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "CRM",
"user": ""
}

View File

@@ -0,0 +1,43 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "EDI",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_edi",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "code-list",
"label": "Code List",
"link_doctype": "DocType",
"link_to": "Code List",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "common-code",
"label": "Common Code",
"link_doctype": "DocType",
"link_to": "Common Code",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "EDI",
"user": ""
}

View File

@@ -0,0 +1,43 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Maintenance",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_maintenance",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "maintenance-schedule",
"label": "Maintenance Schedule",
"link_doctype": "DocType",
"link_to": "Maintenance Schedule",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "maintenance-visit",
"label": "Maintenance Visit",
"link_doctype": "DocType",
"link_to": "Maintenance Visit",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Maintenance",
"user": ""
}

View File

@@ -0,0 +1,295 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Manufacturing",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_manufacturing",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bom",
"label": "BOM",
"link_doctype": "DocType",
"link_to": "BOM",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "work-order",
"label": "Work Order",
"link_doctype": "DocType",
"link_to": "Work Order",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "job-card",
"label": "Job Card",
"link_doctype": "DocType",
"link_to": "Job Card",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "stock-entry",
"label": "Stock Entry",
"link_doctype": "DocType",
"link_to": "Stock Entry",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-material-planning",
"label": "Material Planning",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item-lead-time",
"label": "Item Lead Time",
"link_doctype": "DocType",
"link_to": "Item Lead Time",
"parent_key": "section-material-planning",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "production-plan",
"label": "Production Plan",
"link_doctype": "DocType",
"link_to": "Production Plan",
"parent_key": "section-material-planning",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "master-production-schedule",
"label": "Master Production Schedule",
"link_doctype": "DocType",
"link_to": "Master Production Schedule",
"parent_key": "section-material-planning",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-forecast",
"label": "Sales Forecast",
"link_doctype": "DocType",
"link_to": "Sales Forecast",
"parent_key": "section-material-planning",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-tools",
"label": "Tools",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bom-creator",
"label": "BOM Creator",
"link_doctype": "DocType",
"link_to": "BOM Creator",
"parent_key": "section-tools",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "bom-update-tool",
"label": "BOM Update Tool",
"link_doctype": "DocType",
"link_to": "BOM Update Tool",
"parent_key": "section-tools",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "downtime-entry",
"label": "Downtime Entry",
"link_doctype": "DocType",
"link_to": "Downtime Entry",
"parent_key": "section-tools",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-setup",
"label": "Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item",
"label": "Item",
"link_doctype": "DocType",
"link_to": "Item",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "warehouse",
"label": "Warehouse",
"link_doctype": "DocType",
"link_to": "Warehouse",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "operation",
"label": "Operation",
"link_doctype": "DocType",
"link_to": "Operation",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "workstation",
"label": "Workstation",
"link_doctype": "DocType",
"link_to": "Workstation",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "workstation-type",
"label": "Workstation Type",
"link_doctype": "DocType",
"link_to": "Workstation Type",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "plant-floor",
"label": "Plant Floor",
"link_doctype": "DocType",
"link_to": "Plant Floor",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "routing",
"label": "Routing",
"link_doctype": "DocType",
"link_to": "Routing",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "manufacturing-settings",
"label": "Settings",
"link_doctype": "DocType",
"link_to": "Manufacturing Settings",
"parent_key": "section-setup",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Manufacturing",
"user": ""
}

View File

@@ -0,0 +1,155 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Projects",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_projects",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "project",
"label": "Project",
"link_doctype": "DocType",
"link_to": "Project",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "task",
"label": "Task",
"link_doctype": "DocType",
"link_to": "Task",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "timesheet",
"label": "Timesheet",
"link_doctype": "DocType",
"link_to": "Timesheet",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-setup",
"label": "Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "activity-type",
"label": "Activity Type",
"link_doctype": "DocType",
"link_to": "Activity Type",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "activity-cost",
"label": "Activity Cost",
"link_doctype": "DocType",
"link_to": "Activity Cost",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "project-template",
"label": "Project Template",
"link_doctype": "DocType",
"link_to": "Project Template",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "project-type",
"label": "Project Type",
"link_doctype": "DocType",
"link_to": "Project Type",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "project-update",
"label": "Project Update",
"link_doctype": "DocType",
"link_to": "Project Update",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-reports",
"label": "Reports",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "projects-settings",
"label": "Settings",
"link_doctype": "DocType",
"link_to": "Projects Settings",
"parent_key": "section-reports",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Projects",
"user": ""
}

View File

@@ -0,0 +1,153 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Quality Management",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_quality_management",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-inspection",
"label": "Quality Inspection",
"link_doctype": "DocType",
"link_to": "Quality Inspection",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-goal",
"label": "Quality Goal",
"link_doctype": "DocType",
"link_to": "Quality Goal",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-review",
"label": "Quality Review",
"link_doctype": "DocType",
"link_to": "Quality Review",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-action",
"label": "Quality Action",
"link_doctype": "DocType",
"link_to": "Quality Action",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "non-conformance",
"label": "Non Conformance",
"link_doctype": "DocType",
"link_to": "Non Conformance",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-feedback",
"label": "Quality Feedback",
"link_doctype": "DocType",
"link_to": "Quality Feedback",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-meeting",
"label": "Quality Meeting",
"link_doctype": "DocType",
"link_to": "Quality Meeting",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-setup",
"label": "Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-procedure",
"label": "Quality Procedure",
"link_doctype": "DocType",
"link_to": "Quality Procedure",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-feedback-template",
"label": "Feedback Template",
"link_doctype": "DocType",
"link_to": "Quality Feedback Template",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-inspection-template",
"label": "Quality Inspection Template",
"link_doctype": "DocType",
"link_to": "Quality Inspection Template",
"parent_key": "section-setup",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Quality",
"user": ""
}

View File

@@ -0,0 +1,55 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Regional",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_regional",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "lower-deduction-certificate",
"label": "Lower Deduction Certificate",
"link_doctype": "DocType",
"link_to": "Lower Deduction Certificate",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "uae-vat-settings",
"label": "UAE VAT Settings",
"link_doctype": "DocType",
"link_to": "UAE VAT Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "south-africa-vat-settings",
"label": "South Africa VAT Settings",
"link_doctype": "DocType",
"link_to": "South Africa VAT Settings",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Regional",
"user": ""
}

View File

@@ -0,0 +1,502 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Selling",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_selling",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quotation",
"label": "Quotation",
"link_doctype": "DocType",
"link_to": "Quotation",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-order",
"label": "Sales Order",
"link_doctype": "DocType",
"link_to": "Sales Order",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-invoice",
"label": "Sales Invoice",
"link_doctype": "DocType",
"link_to": "Sales Invoice",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-pos",
"label": "POS",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "pos-profile",
"label": "POS Profile",
"link_doctype": "DocType",
"link_to": "POS Profile",
"parent_key": "section-pos",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "pos-invoice",
"label": "POS Invoice",
"link_doctype": "DocType",
"link_to": "POS Invoice",
"parent_key": "section-pos",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "pos-opening-entry",
"label": "POS Opening Entry",
"link_doctype": "DocType",
"link_to": "POS Opening Entry",
"parent_key": "section-pos",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "pos-closing-entry",
"label": "POS Closing Entry",
"link_doctype": "DocType",
"link_to": "POS Closing Entry",
"parent_key": "section-pos",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "pos-invoice-merge-log",
"label": "POS Invoice Merge Log",
"link_doctype": "DocType",
"link_to": "POS Invoice Merge Log",
"parent_key": "section-pos",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "pos-settings",
"label": "POS Settings",
"link_doctype": "DocType",
"link_to": "POS Settings",
"parent_key": "section-pos",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "loyalty-program",
"label": "Loyalty Program",
"link_doctype": "DocType",
"link_to": "Loyalty Program",
"parent_key": "section-pos",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "loyalty-point-entry",
"label": "Loyalty Point Entry",
"link_doctype": "DocType",
"link_to": "Loyalty Point Entry",
"parent_key": "section-pos",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-items-pricing",
"label": "Items & Pricing",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item",
"label": "Item",
"link_doctype": "DocType",
"link_to": "Item",
"parent_key": "section-items-pricing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item-group",
"label": "Item Group",
"link_doctype": "DocType",
"link_to": "Item Group",
"parent_key": "section-items-pricing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "price-list",
"label": "Price List",
"link_doctype": "DocType",
"link_to": "Price List",
"parent_key": "section-items-pricing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item-price",
"label": "Item Price",
"link_doctype": "DocType",
"link_to": "Item Price",
"parent_key": "section-items-pricing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "pricing-rule",
"label": "Pricing Rule",
"link_doctype": "DocType",
"link_to": "Pricing Rule",
"parent_key": "section-items-pricing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "promotional-scheme",
"label": "Promotional Scheme",
"link_doctype": "DocType",
"link_to": "Promotional Scheme",
"parent_key": "section-items-pricing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "coupon-code",
"label": "Coupon Code",
"link_doctype": "DocType",
"link_to": "Coupon Code",
"parent_key": "section-items-pricing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "blanket-order",
"label": "Blanket Order",
"link_doctype": "DocType",
"link_to": "Blanket Order",
"parent_key": "section-items-pricing",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-setup",
"label": "Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "customer",
"label": "Customer",
"link_doctype": "DocType",
"link_to": "Customer",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "customer-group",
"label": "Customer Group",
"link_doctype": "DocType",
"link_to": "Customer Group",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "address",
"label": "Address",
"link_doctype": "DocType",
"link_to": "Address",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "contact",
"label": "Contact",
"link_doctype": "DocType",
"link_to": "Contact",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "territory",
"label": "Territory",
"link_doctype": "DocType",
"link_to": "Territory",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "campaign",
"label": "Campaign",
"link_doctype": "DocType",
"link_to": "Campaign",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-person",
"label": "Sales Person",
"link_doctype": "DocType",
"link_to": "Sales Person",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-partner",
"label": "Sales Partner",
"link_doctype": "DocType",
"link_to": "Sales Partner",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "monthly-distribution",
"label": "Monthly Distribution",
"link_doctype": "DocType",
"link_to": "Monthly Distribution",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "terms-and-conditions",
"label": "Terms Template",
"link_doctype": "DocType",
"link_to": "Terms and Conditions",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-taxes-and-charges-template",
"label": "Tax Template",
"link_doctype": "DocType",
"link_to": "Sales Taxes and Charges Template",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "product-bundle",
"label": "Product Bundle",
"link_doctype": "DocType",
"link_to": "Product Bundle",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "utm-source",
"label": "UTM Source",
"link_doctype": "DocType",
"link_to": "UTM Source",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "shipping-rule",
"label": "Shipping Rule",
"link_doctype": "DocType",
"link_to": "Shipping Rule",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-reports",
"label": "Reports",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "selling-settings",
"label": "Settings",
"link_doctype": "DocType",
"link_to": "Selling Settings",
"parent_key": "section-reports",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Selling",
"user": ""
}

View File

@@ -0,0 +1,403 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Setup",
"modified": "2026-09-02 20:36:43.873382",
"modified_by": "Administrator",
"name": "module_def_setup",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "global-defaults",
"label": "Global Defaults",
"link_doctype": "DocType",
"link_to": "Global Defaults",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "system-settings",
"label": "System Settings",
"link_doctype": "DocType",
"link_to": "System Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "accounts-settings",
"label": "Accounts Settings",
"link_doctype": "DocType",
"link_to": "Accounts Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "pos-settings",
"label": "POS Settings",
"link_doctype": "DocType",
"link_to": "POS Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "selling-settings",
"label": "Selling Settings",
"link_doctype": "DocType",
"link_to": "Selling Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "buying-settings",
"label": "Buying Settings",
"link_doctype": "DocType",
"link_to": "Buying Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "stock-settings",
"label": "Stock Settings",
"link_doctype": "DocType",
"link_to": "Stock Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "manufacturing-settings",
"label": "Manufacturing Settings",
"link_doctype": "DocType",
"link_to": "Manufacturing Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "projects-settings",
"label": "Projects Settings",
"link_doctype": "DocType",
"link_to": "Projects Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "crm-settings",
"label": "CRM Settings",
"link_doctype": "DocType",
"link_to": "CRM Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "support-settings",
"label": "Support Settings",
"link_doctype": "DocType",
"link_to": "Support Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-other-settings",
"label": "Other Settings",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subscription-settings",
"label": "Subscription Settings",
"link_doctype": "DocType",
"link_to": "Subscription Settings",
"parent_key": "section-other-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item-variant-settings",
"label": "Item Variant Settings",
"link_doctype": "DocType",
"link_to": "Item Variant Settings",
"parent_key": "section-other-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "delivery-settings",
"label": "Delivery Settings",
"link_doctype": "DocType",
"link_to": "Delivery Settings",
"parent_key": "section-other-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "currency-exchange-settings",
"label": "Currency Exchange Settings",
"link_doctype": "DocType",
"link_to": "Currency Exchange Settings",
"parent_key": "section-other-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "appointment-booking-settings",
"label": "Appointment Booking Settings",
"link_doctype": "DocType",
"link_to": "Appointment Booking Settings",
"parent_key": "section-other-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "stock-reposting-settings",
"label": "Stock Reposting Settings",
"link_doctype": "DocType",
"link_to": "Stock Reposting Settings",
"parent_key": "section-other-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-organization",
"label": "Organization",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "Default Company",
"keep_closed": 0,
"key": "default-company",
"link_doctype": "Company",
"parent_key": "section-organization",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "company",
"label": "Company",
"link_doctype": "DocType",
"link_to": "Company",
"parent_key": "section-organization",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "letter-head",
"label": "Letter Head",
"link_doctype": "DocType",
"link_to": "Letter Head",
"parent_key": "section-organization",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "department",
"label": "Department",
"link_doctype": "DocType",
"link_to": "Department",
"parent_key": "section-organization",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "branch",
"label": "Branch",
"link_doctype": "DocType",
"link_to": "Branch",
"parent_key": "section-organization",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "user",
"label": "User",
"link_doctype": "DocType",
"link_to": "User",
"parent_key": "section-organization",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "email-account",
"label": "Email Account",
"link_doctype": "DocType",
"link_to": "Email Account",
"parent_key": "section-organization",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-home",
"label": "Home",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item",
"label": "Item",
"link_doctype": "DocType",
"link_to": "Item",
"parent_key": "section-home",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "customer",
"label": "Customer",
"link_doctype": "DocType",
"link_to": "Customer",
"parent_key": "section-home",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "supplier",
"label": "Supplier",
"link_doctype": "DocType",
"link_to": "Supplier",
"parent_key": "section-home",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "sales-invoice",
"label": "Sales Invoice",
"link_doctype": "DocType",
"link_to": "Sales Invoice",
"parent_key": "section-home",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Setup",
"user": ""
}

View File

@@ -0,0 +1,461 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Stock",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_stock",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "stock-entry",
"label": "Stock Entry",
"link_doctype": "DocType",
"link_to": "Stock Entry",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "purchase-receipt",
"label": "Purchase Receipt",
"link_doctype": "DocType",
"link_to": "Purchase Receipt",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "delivery-note",
"label": "Delivery Note",
"link_doctype": "DocType",
"link_to": "Delivery Note",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "material-request",
"label": "Material Request",
"link_doctype": "DocType",
"link_to": "Material Request",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "pick-list",
"label": "Pick List",
"link_doctype": "DocType",
"link_to": "Pick List",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-tools",
"label": "Tools",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "stock-reconciliation",
"label": "Stock Reconciliation",
"link_doctype": "DocType",
"link_to": "Stock Reconciliation",
"parent_key": "section-tools",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "landed-cost-voucher",
"label": "Landed Cost Voucher",
"link_doctype": "DocType",
"link_to": "Landed Cost Voucher",
"parent_key": "section-tools",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "repost-item-valuation",
"label": "Repost Item Valuation",
"link_doctype": "DocType",
"link_to": "Repost Item Valuation",
"parent_key": "section-tools",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "packing-slip",
"label": "Packing Slip",
"link_doctype": "DocType",
"link_to": "Packing Slip",
"parent_key": "section-tools",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-inspection",
"label": "Quality Inspection",
"link_doctype": "DocType",
"link_to": "Quality Inspection",
"parent_key": "section-tools",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-setup",
"label": "Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item",
"label": "Item",
"link_doctype": "DocType",
"link_to": "Item",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item-group",
"label": "Item Group",
"link_doctype": "DocType",
"link_to": "Item Group",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item-attribute",
"label": "Item Attribute",
"link_doctype": "DocType",
"link_to": "Item Attribute",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "brand",
"label": "Brand",
"link_doctype": "DocType",
"link_to": "Brand",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "warehouse",
"label": "Warehouse",
"link_doctype": "DocType",
"link_to": "Warehouse",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "uom",
"label": "Unit of Measure (UOM)",
"link_doctype": "DocType",
"link_to": "UOM",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "uom-conversion-factor",
"label": "UOM Conversion Factor",
"link_doctype": "DocType",
"link_to": "UOM Conversion Factor",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "serial-no",
"label": "Serial No",
"link_doctype": "DocType",
"link_to": "Serial No",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "batch",
"label": "Batch No",
"link_doctype": "DocType",
"link_to": "Batch",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "serial-and-batch-bundle",
"label": "Serial and Batch Bundle",
"link_doctype": "DocType",
"link_to": "Serial and Batch Bundle",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item-standard-cost",
"label": "Item Standard Cost",
"link_doctype": "DocType",
"link_to": "Item Standard Cost",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "inventory-dimension",
"label": "Inventory Dimension",
"link_doctype": "DocType",
"link_to": "Inventory Dimension",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "shipping-rule",
"label": "Shipping Rule",
"link_doctype": "DocType",
"link_to": "Shipping Rule",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item-alternative",
"label": "Item Alternative",
"link_doctype": "DocType",
"link_to": "Item Alternative",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quality-inspection-template",
"label": "Quality Inspection Template",
"link_doctype": "DocType",
"link_to": "Quality Inspection Template",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "delivery-trip",
"label": "Delivery Trip",
"link_doctype": "DocType",
"link_to": "Delivery Trip",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-reports",
"label": "Reports",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "quick-stock-balance",
"label": "Quick Stock Balance",
"link_doctype": "DocType",
"link_to": "Quick Stock Balance",
"parent_key": "section-reports",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-settings",
"label": "Settings",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "stock-settings",
"label": "Stock Settings",
"link_doctype": "DocType",
"link_to": "Stock Settings",
"parent_key": "section-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "item-variant-settings",
"label": "Item Variant Settings",
"link_doctype": "DocType",
"link_to": "Item Variant Settings",
"parent_key": "section-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "stock-reposting-settings",
"label": "Stock Reposting Settings",
"link_doctype": "DocType",
"link_to": "Stock Reposting Settings",
"parent_key": "section-settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "delivery-settings",
"label": "Delivery Settings",
"link_doctype": "DocType",
"link_to": "Delivery Settings",
"parent_key": "section-settings",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Stock",
"user": ""
}

View File

@@ -0,0 +1,67 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Subcontracting",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_subcontracting",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subcontracting-order",
"label": "Subcontracting Order",
"link_doctype": "DocType",
"link_to": "Subcontracting Order",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subcontracting-receipt",
"label": "Subcontracting Receipt",
"link_doctype": "DocType",
"link_to": "Subcontracting Receipt",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subcontracting-bom",
"label": "Subcontracting BOM",
"link_doctype": "DocType",
"link_to": "Subcontracting BOM",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "subcontracting-inward-order",
"label": "Subcontracting Inward Order",
"link_doctype": "DocType",
"link_to": "Subcontracting Inward Order",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Subcontracting",
"user": ""
}

View File

@@ -0,0 +1,141 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Support",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_support",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "issue",
"label": "Issue",
"link_doctype": "DocType",
"link_to": "Issue",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "maintenance-schedule",
"label": "Maintenance Schedule",
"link_doctype": "DocType",
"link_to": "Maintenance Schedule",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "maintenance-visit",
"label": "Maintenance Visit",
"link_doctype": "DocType",
"link_to": "Maintenance Visit",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "warranty-claim",
"label": "Warranty Claim",
"link_doctype": "DocType",
"link_to": "Warranty Claim",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-setup",
"label": "Setup",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "issue-type",
"label": "Issue Type",
"link_doctype": "DocType",
"link_to": "Issue Type",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "issue-priority",
"label": "Issue Priority",
"link_doctype": "DocType",
"link_to": "Issue Priority",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "service-level-agreement",
"label": "Service Level Agreement",
"link_doctype": "DocType",
"link_to": "Service Level Agreement",
"parent_key": "section-setup",
"switches_app": 0
},
{
"added": 0,
"collapsible": 1,
"hidden": 0,
"item_type": "Section",
"keep_closed": 1,
"key": "section-reports",
"label": "Reports",
"link_doctype": "",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "support-settings",
"label": "Settings",
"link_doctype": "DocType",
"link_to": "Support Settings",
"parent_key": "section-reports",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Support",
"user": ""
}

View File

@@ -0,0 +1,67 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Telephony",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_telephony",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "incoming-call-settings",
"label": "Incoming Call Settings",
"link_doctype": "DocType",
"link_to": "Incoming Call Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "voice-call-settings",
"label": "Voice Call Settings",
"link_doctype": "DocType",
"link_to": "Voice Call Settings",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "call-log",
"label": "Call Log",
"link_doctype": "DocType",
"link_to": "Call Log",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "telephony-call-type",
"label": "Telephony Call Type",
"link_doctype": "DocType",
"link_to": "Telephony Call Type",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Telephony",
"user": ""
}

View File

@@ -0,0 +1,55 @@
{
"app": "erpnext",
"creation": "2026-09-02 22:15:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"idx": 0,
"items": [],
"link_doctype": "Module Def",
"link_to": "Utilities",
"modified": "2026-09-02 22:15:00.000000",
"modified_by": "Administrator",
"name": "module_def_utilities",
"navigation_items": [
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "rename-tool",
"label": "Rename Tool",
"link_doctype": "DocType",
"link_to": "Rename Tool",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "video",
"label": "Video",
"link_doctype": "DocType",
"link_to": "Video",
"switches_app": 0
},
{
"added": 0,
"collapsible": 0,
"hidden": 0,
"item_type": "DocType",
"keep_closed": 0,
"key": "video-settings",
"label": "Video Settings",
"link_doctype": "DocType",
"link_to": "Video Settings",
"switches_app": 0
}
],
"owner": "Administrator",
"standard": 1,
"title": "Utilities",
"user": ""
}

View File

@@ -5,12 +5,12 @@ frappe.listview_settings["Batch"] = {
return [__("Disabled"), "gray", "disabled,=,1"];
} else if (
doc.expiry_date &&
frappe.datetime.get_diff(doc.expiry_date, frappe.datetime.nowdate()) < 0
frappe.datetime.get_diff(doc.expiry_date, frappe.datetime.nowdate()) <= 0
) {
return [
__("Expired"),
"red",
"expiry_date,not in,|expiry_date,<,Today|batch_qty,>,0|disabled,=,0",
"expiry_date,not in,|expiry_date,<=,Today|batch_qty,>,0|disabled,=,0",
];
} else if (!doc.batch_qty) {
return [__("Empty"), "gray", "batch_qty,=,0|disabled,=,0"];

View File

@@ -102,27 +102,8 @@ frappe.ui.form.on("Material Request", {
erpnext.accounts.dimensions.setup_dimension_filters(frm, frm.doctype);
if (!frm.doc.buying_price_list) {
const buying_price_list = frappe.defaults.get_default("buying_price_list");
if (buying_price_list) {
const docname = frm.doc.name;
frappe.call({
type: "GET",
method: "frappe.client.has_permission",
no_spinner: true,
args: {
doctype: "Price List",
docname: buying_price_list,
perm_type: "read",
},
callback: ({ message }) => {
if (
message?.has_permission &&
frm.doc.name === docname &&
!frm.doc.buying_price_list
) {
frm.set_value("buying_price_list", buying_price_list);
}
},
});
if (frappe.has_permission("Price List", "read", buying_price_list)) {
frm.set_value("buying_price_list", buying_price_list);
}
}
},

View File

@@ -0,0 +1,80 @@
{
"app": "erpnext",
"creation": "2026-08-16 00:00:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"header_icon": "phone",
"idx": 0,
"items": [
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"icon": "settings",
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Incoming Call Settings",
"link_to": "Incoming Call Settings",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"icon": "settings",
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Voice Call Settings",
"link_to": "Voice Call Settings",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Call Log",
"link_to": "Call Log",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Telephony Call Type",
"link_to": "Telephony Call Type",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
}
],
"modified": "2026-08-16 00:00:00.000000",
"modified_by": "Administrator",
"module": "Telephony",
"name": "Telephony",
"owner": "Administrator",
"sequence_id": 0.0,
"standard": 1,
"title": "Telephony"
}

View File

@@ -0,0 +1,293 @@
# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
"""ERPNext's shipped desk v2 navigation: one Rail record and eighteen module Sidebars.
These are fixture tests. The rows arrive as JSON at `bench migrate` and the framework resolves
them, so what there is to get wrong is the content of those rows: a rail item naming a sidebar
nobody ships, a row pointing at a doctype this site does not have, or two rows claiming one key.
Each of those resolves to a quietly shorter list rather than to an error, which is why they are
asserted here.
This is the module-primary half of charter point 2 (frappe/frappe#42226): the same table, the
same resolver and the same item kinds that give CRM a doctype-primary rail, giving ERPNext one
made of modules. The rail is a `Sidebar` item per module that has an authored sidebar and a
`Module` item per module that does not.
The one piece of ERPNext navigation code lives elsewhere: `test_navigation_kind.py` covers the
`Default Company` item kind, which is the app contributing a kind rather than authoring rows.
Every test runs as somebody other than Administrator. The permission filter short-circuits for
an administrator (`frappe/shell/navigation_filter.py`), so an Administrator suite would pass
against a rail that is not being filtered at all.
"""
import frappe
from frappe.shell.navigation import resolve_navigation
from frappe.tests import IntegrationTestCase
APP = "erpnext"
# The rail, in the order it is authored -- which is the order ERPNext already curated for desk
# v1's dock, since that list is what a person using ERPNext expects to see.
RAIL = (
"accounts",
"crm",
"buying",
"projects",
"selling",
"setup",
"manufacturing",
"stock",
"support",
"utilities",
"assets",
"maintenance",
"regional",
"erpnext-integrations",
"quality-management",
"communication",
"telephony",
"bulk-transaction",
"subcontracting",
"edi",
)
# The two modules whose authored sidebar would hold one row or none, so none is shipped. Their
# rail item is a `Module`, which lands on the module page -- a list derived from the module's
# contents, which is a different list on purpose (frappe/frappe#42357).
#
# `Portal` is on desk v1's dock and is deliberately not here: it holds no doctypes at all, so
# it has neither a sidebar to open nor a module page to land on, and the renderer would find no
# address and skip the row.
INDEPENDENT = ("erpnext-integrations", "communication")
# Every other module ships a sidebar, addressed at its `Module Def`. The scrubbed address is
# both the standard record's name and the key boot files it under, and it is the string the
# rail item of type `Sidebar` carries in `link_to`.
LINKED = tuple(key for key in RAIL if key not in INDEPENDENT)
def rail_of(user: str) -> list[dict]:
frappe.set_user(user)
try:
return resolve_navigation(APP)["rail"]
finally:
frappe.set_user("Administrator")
class TestERPNextNavigation(IntegrationTestCase):
@classmethod
def setUpClass(cls):
super().setUpClass()
cls.user = make_erpnext_user("erpnext.navigation.test@example.com")
def setUp(self):
frappe.set_user(self.user)
self.addCleanup(frappe.set_user, "Administrator")
# `IntegrationTestCase` rolls back once per CLASS, so a `Block Module` row written by one
# test is still there for the next -- and three tests below block the same module, so the
# one that asserts what the rail looks like *before* the block would depend on running
# first. Cleared here rather than in a cleanup, so it holds however the tests are ordered.
self.unblock()
self.addCleanup(self.unblock)
def unblock(self):
"""Give every module back, and clear the cache the block is read through."""
frappe.set_user("Administrator")
doc = frappe.get_doc("User", self.user)
if doc.block_modules:
doc.set("block_modules", [])
doc.save(ignore_permissions=True)
frappe.clear_cache(user=self.user)
frappe.set_user(self.user)
def test_the_rail_is_the_twenty_authored_items(self):
"""As Administrator, who is filtered by nothing, so this is the shipped list itself."""
frappe.set_user("Administrator")
self.assertEqual(tuple(item["key"] for item in resolve_navigation(APP)["rail"]), RAIL)
def test_a_linked_item_names_a_sidebar_this_app_ships(self):
"""A typo in `link_to` costs the item its panel and nothing else, so nothing reports it.
Read off the **shipped rows**, not the resolved payload. `Sidebar` declares the
`Derived From Children` permission rule, so an item naming an address that resolves to no
rows is dropped by the server's own cascade -- silently, and correctly, because that is
also what an emptied sidebar has to do. Asserting against the resolved list would
therefore be asserting that the cascade works, which is frappe's test and not this one.
"""
linked = [row for row in shipped("Rail", "erpnext") if row.item_type == "Sidebar"]
addresses = set(frappe.get_all("Sidebar", filters={"app": APP, "standard": 1}, pluck="name"))
self.assertEqual(tuple(row.key for row in linked), LINKED)
for row in linked:
self.assertIn(row.link_to, addresses, row.key)
def test_an_independent_item_is_a_module_and_opens_nothing(self):
"""Charter point 1 makes independent a first-class state, and needs no field to say so:
a `Module` item lands on the module page and has no sidebar to open."""
frappe.set_user("Administrator")
navigation = resolve_navigation(APP)
rail = {item["key"]: item for item in navigation["rail"]}
for key in INDEPENDENT:
self.assertEqual(rail[key]["item_type"], "Module")
self.assertNotIn(frappe.scrub(f"Module Def {rail[key]['link_to']}"), navigation["sidebars"])
def test_every_sidebar_is_addressed_at_a_module_that_exists(self):
"""The address is the module, not the desk v1 sidebar the rows were curated for -- and
those two differ: v1's `Quality` sidebar belongs to the `Quality Management` module."""
for name in frappe.get_all(
"Sidebar", filters={"app": APP, "standard": 1, "link_doctype": "Module Def"}, pluck="name"
):
module = frappe.db.get_value("Sidebar", name, "link_to")
self.assertTrue(frappe.db.exists("Module Def", module), name)
self.assertEqual(name, frappe.scrub(f"Module Def {module}"))
def test_every_destination_is_a_doctype_this_site_has(self):
"""Read off the shipped rows rather than the resolved payload, which has already dropped
any row it could not place.
A typo cannot get this far: `link_to` is a Dynamic Link, so `_validate_links` refuses the
row at import with `Could not find Row #N: Link To` -- checked, not assumed. What is left
for this to catch is a doctype removed *after* the rows were imported, which arrives as a
quietly shorter sidebar and nothing else.
"""
for container, address in every_container():
for row in shipped(container, address):
if row.item_type == "DocType":
self.assertTrue(frappe.db.exists("DocType", row.link_to), f"{address}/{row.key}")
def test_keys_are_unique_within_each_container(self):
"""Every site and user edit is filed against a key, so two rows sharing one collide."""
for container, address in every_container():
keys = [row.key for row in shipped(container, address)]
self.assertEqual(len(keys), len(set(keys)), address)
def test_no_section_is_shipped_over_nothing(self):
"""A heading with no rows under it is dropped by the cascade at read time, so shipping one
would mean shipping a row that can never render. Left out at authoring instead -- and read
here off the shipped rows, since the cascade would have hidden it either way."""
for container, address in every_container():
rows = shipped(container, address)
parents = {row.parent_key for row in rows}
for row in rows:
if row.item_type == "Section":
self.assertIn(row.key, parents, f"{address}/{row.key}")
def test_every_parent_key_names_a_section_beside_it(self):
"""A row filed under a heading that is not there loses its nesting silently: the resolver
promotes an orphan to the top level rather than dropping it."""
for container, address in every_container():
rows = shipped(container, address)
sections = {row.key for row in rows if row.item_type == "Section"}
for row in rows:
if row.parent_key:
self.assertIn(row.parent_key, sections, f"{address}/{row.key}")
def test_a_real_user_sees_fewer_modules_than_administrator(self):
"""The filter is doing something, which is the one thing an Administrator suite cannot
show. An `Accounts User` has no reason to be offered `Regional` or `Telephony`."""
frappe.set_user("Administrator")
everything = len(resolve_navigation(APP)["rail"])
self.assertLess(len(rail_of(self.user)), everything)
def test_a_blocked_module_ships_nothing(self):
"""The veto on a module-primary rail, which is what this rail is here to exercise.
`block_modules` gates module-derived items, and a module-primary rail reaches a module
through a `Sidebar` item holding `DocType` rows -- so before frappe/frappe#42423 blocking
Accounts left all 73 rows and the rail item standing. The block now names the sidebar's
*address*, and the rail item goes with it through the cascade it already ran under.
"""
before = [item["key"] for item in rail_of(self.user)]
self.assertIn("accounts", before)
block("Accounts", self.user)
after = rail_of(self.user)
self.assertEqual([item["key"] for item in after], [key for key in before if key != "accounts"])
def test_a_blocked_module_takes_its_sidebar_with_it(self):
block("Accounts", self.user)
frappe.set_user(self.user)
self.assertNotIn("module_def_accounts", resolve_navigation(APP)["sidebars"])
def test_a_doctype_in_a_blocked_module_is_still_reachable(self):
"""Hiding a module hides the way to a document, never the document. `Sales Invoice` is
an Accounts doctype and ERPNext's Selling sidebar links it, which is one of the 101 rows
that point outside their own module."""
block("Accounts", self.user)
frappe.set_user(self.user)
sidebars = resolve_navigation(APP)["sidebars"]
self.assertTrue(
any(
row.get("link_to") == "Sales Invoice"
for address, rows in sidebars.items()
if address != "module_def_accounts"
for row in rows
)
)
def every_container() -> list[tuple[str, str]]:
"""Every standard record ERPNext ships, as `(doctype, name)`."""
return [("Rail", "erpnext")] + [
("Sidebar", name)
for name in frappe.get_all("Sidebar", filters={"app": APP, "standard": 1}, pluck="name")
]
def shipped(container: str, address: str) -> list:
"""The rows as authored, before the resolver has filtered or cascaded anything away.
The distinction matters for every fixture assertion below: `resolve_navigation` drops a row
naming a doctype that is gone, a heading over nothing and a linked item whose sidebar
emptied. Read against its output, a test for those is asserting that the resolver works.
"""
return frappe.get_all(
"Navigation Item",
filters={
"parenttype": container,
"parent": address,
"parentfield": "items" if container == "Rail" else "navigation_items",
},
fields=["key", "parent_key", "item_type", "link_doctype", "link_to"],
order_by="idx asc",
)
def block(module: str, user: str):
"""Withdraw a module from one person, the way an administrator does on the User form.
`tabBlock Module` holds no rows on either bench site, so the veto cannot be observed without
seeding one -- which is why it had never been watched on a real rail.
"""
frappe.set_user("Administrator")
doc = frappe.get_doc("User", user)
doc.append("block_modules", {"module": module})
doc.save(ignore_permissions=True)
frappe.clear_cache(user=user)
frappe.set_user(user)
def make_erpnext_user(email: str) -> str:
"""Somebody who works in a few of ERPNext's modules and not in the rest of them."""
if frappe.db.exists("User", email):
return email
user = frappe.get_doc(
{
"doctype": "User",
"email": email,
"first_name": "ERPNext Navigation",
"user_type": "System User",
"roles": [{"role": "Accounts User"}, {"role": "Stock User"}, {"role": "Sales User"}],
}
).insert(ignore_permissions=True)
return user.name

View File

@@ -0,0 +1,224 @@
# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and Contributors
# License: GNU General Public License v3. See license.txt
"""The `Default Company` navigation item kind: ERPNext's own, and the first one an app has
contributed (frappe/frappe#42424).
A kind is two files and, optionally, a hook. The record at
`setup/navigation_item_type/default_company/default_company.json` arrives at `bench migrate`;
the renderer beside it at `frontend/item.js` arrives at `bench build`; and because the record
declares the `Custom` permission rule, `hooks.py` points the framework at a `can_see` in the
same folder. Those are three independent channels, and the failure they share is quiet: a kind
missing its renderer is skipped with a console line, and a kind declaring `Custom` with no
`can_see` fails closed. Both read as an item that is simply not there.
So the pairing is asserted as much as the behaviour.
"""
import os
from unittest.mock import patch
import frappe
from frappe.shell.navigation import resolve_navigation
from frappe.tests import IntegrationTestCase
from erpnext.setup.navigation_item_type.default_company import default_company as kind
TYPE_NAME = "Default Company"
FOLDER = os.path.join(frappe.get_app_path("erpnext"), "setup", "navigation_item_type", "default_company")
# Where the item is authored: ERPNext's Setup sidebar, beside the `Company` list.
SIDEBAR = "module_def_setup"
KEY = "default-company"
# Any name will do where the permission call is stubbed: `can_see` passes the string through
# and never reads the document itself.
COMPANY = "A Company This Site May Or May Not Have"
class TestDefaultCompanyKind(IntegrationTestCase):
"""What the app ships, and whether the three halves agree with each other."""
def test_the_type_record_arrives_at_migrate(self):
row = frappe.db.get_value(
"Navigation Item Type", TYPE_NAME, ["permission_rule", "target_doctype", "module"], as_dict=True
)
self.assertIsNotNone(row, "the type record did not arrive; `bench migrate` imports it")
self.assertEqual(row.permission_rule, "Custom")
self.assertEqual(row.target_doctype, "Company")
self.assertEqual(row.module, "Setup")
def test_the_renderer_ships_beside_the_record(self):
"""The pair is the kind. Ship one without the other and the item vanishes quietly --
with no renderer it is skipped and logged to the console, which nobody is reading."""
self.assertTrue(os.path.isfile(os.path.join(FOLDER, "default_company.json")))
self.assertTrue(os.path.isfile(os.path.join(FOLDER, "frontend", "item.js")))
def test_the_hook_names_a_can_see_that_imports(self):
"""A `Custom` type whose hook points at nothing fails closed: every item of the kind is
dropped and one line goes to the Error Log. This is the same lookup the framework does."""
paths = frappe.get_hooks("navigation_item_resolvers", default={}).get(TYPE_NAME)
self.assertTrue(paths, "hooks.py contributes no resolver for the kind")
self.assertTrue(callable(frappe.get_attr(f"{paths[-1]}.can_see")))
def test_the_shipped_row_carries_no_label(self):
"""Deliberate: the renderer's fallback names the item after the company, which is not
knowable when the row is authored. An authored label would win over it."""
row = frappe.db.get_value(
"Navigation Item",
{"parenttype": "Sidebar", "parent": SIDEBAR, "key": KEY},
["item_type", "label", "parent_key"],
as_dict=True,
)
self.assertIsNotNone(row, f"{SIDEBAR} does not ship the {KEY} row")
self.assertEqual(row.item_type, TYPE_NAME)
self.assertFalse(row.label)
self.assertEqual(row.parent_key, "section-organization")
def test_the_type_is_code_owned(self):
"""Charter point 5: a type row is app content, so nobody may mint one on a site.
Read off the permission rows rather than by asking `has_permission`, which answers True
for Administrator whatever the rows say -- the account most likely to be running this.
"""
grants = frappe.get_meta("Navigation Item Type").permissions
self.assertTrue(grants, "the table grants nothing at all, which is a different bug")
for grant in grants:
self.assertFalse(grant.create, grant.role)
self.assertFalse(grant.write, grant.role)
class TestDefaultCompanyVisibility(IntegrationTestCase):
"""`can_see`, which is the whole reason the kind declares `Custom` rather than a bucket."""
def setUp(self):
self.items = [{"key": KEY, "item_type": TYPE_NAME}]
self.context = _Context(frappe.session.user)
def test_a_site_with_no_default_company_ships_nothing(self):
"""A site still in the setup wizard. The item has nothing to point at, and it is dropped
here rather than sent and then declined by the renderer."""
with patch.object(kind, "default_company", return_value=None):
self.assertEqual(kind.can_see(self.items, self.context), [])
def test_the_check_is_on_the_document_and_not_the_doctype(self):
"""The difference the kind exists for. `Readable DocType` asks whether this user may read
`Company` at all; the honest question is whether they may open *this* company, which is
what a `User Permission` decides on an ordinary ERPNext site."""
with patch.object(kind, "default_company", return_value=COMPANY):
with patch.object(frappe, "has_permission", return_value=True) as allowed:
self.assertEqual(kind.can_see(self.items, self.context), self.items)
self.assertEqual(allowed.call_args.args, ("Company",))
self.assertEqual(allowed.call_args.kwargs["doc"], COMPANY)
with patch.object(frappe, "has_permission", return_value=False):
self.assertEqual(kind.can_see(self.items, self.context), [])
def test_a_default_company_that_no_longer_exists_ships_nothing(self):
"""Global Defaults naming a deleted company. Left to raise, this would fail the kind
closed *and* write an Error Log on every boot of every session, since the cause is the
site's data rather than a passing fault.
As somebody other than Administrator, who never reaches the document: the permission
system answers True for them before it looks anything up, so this leak is invisible to
the account most likely to be testing it.
"""
context = _Context(_make_user("default.company.kind@example.com"))
with patch.object(kind, "default_company", return_value="A Company Nobody Has"):
self.assertEqual(kind.can_see(self.items, context), [])
def test_one_permission_call_however_many_items(self):
"""Batched by contract (frappe/frappe#42231): every item of this kind shares one
destination, so there is one question to ask. A loop here is what the 3,594 ms
measurement was made on."""
many = [{"key": f"{KEY}-{n}", "item_type": TYPE_NAME} for n in range(20)]
with patch.object(kind, "default_company", return_value=COMPANY):
with patch.object(frappe, "has_permission", return_value=True) as allowed:
self.assertEqual(kind.can_see(many, self.context), many)
self.assertEqual(allowed.call_count, 1)
def test_a_restricted_user_loses_the_item_from_the_resolved_sidebar(self):
"""End to end, through the framework rather than by calling `can_see`: the same person
keeps or loses the row on nothing but a `User Permission` naming another company.
Run against the companies the site already has rather than ERPNext's `Company` test
records, which cannot be created on a site that already keeps books -- their fiscal years
collide with the real ones. So this is the one case that needs a second company and skips
without one.
"""
companies = frappe.get_all("Company", pluck="name", limit=2)
if len(companies) < 2:
self.skipTest("needs two companies: one to be the default, one to be restricted to")
default, other = companies
user = _make_user("default.company.kind@example.com")
with patch.object(kind, "default_company", return_value=default):
self.assertIn(KEY, _sidebar_keys(user))
_restrict(user, other)
self.assertNotIn(KEY, _sidebar_keys(user))
class _Context:
"""Stands in for `NavigationContext`, of which `can_see` reads one attribute.
A real one would resolve the whole permission pass for a user this test does not otherwise
need, and the narrowness is the point: a resolver that reached for more would be a resolver
recomputing what the framework already paid for.
"""
def __init__(self, user: str):
self.user = user
def _sidebar_keys(user: str) -> list[str]:
frappe.set_user(user)
try:
frappe.clear_cache(user=user)
rows = resolve_navigation("erpnext")["sidebars"].get(SIDEBAR, [])
return [row["key"] for row in rows]
finally:
frappe.set_user("Administrator")
def _restrict(user: str, company: str):
"""Pin somebody to one company, which is how an ERPNext site says it."""
frappe.set_user("Administrator")
frappe.get_doc(
{
"doctype": "User Permission",
"user": user,
"allow": "Company",
"for_value": company,
"apply_to_all_doctypes": 1,
}
).insert(ignore_permissions=True)
frappe.clear_cache(user=user)
def _make_user(email: str) -> str:
if frappe.db.exists("User", email):
return email
return (
frappe.get_doc(
{
"doctype": "User",
"email": email,
"first_name": "Default Company Kind",
"user_type": "System User",
"roles": [{"role": "System Manager"}],
}
)
.insert(ignore_permissions=True)
.name
)

View File

@@ -1,6 +1,6 @@
{
"app": "erpnext",
"creation": "2026-09-02 03:16:19.632349",
"creation": "2026-08-16 00:00:00.000000",
"docstatus": 0,
"doctype": "Sidebar",
"header_icon": "pocket-knife",
@@ -26,110 +26,6 @@
"child": 0,
"collapsible": 1,
"hidden": 0,
"icon": "file-code",
"indent": 1,
"is_default_module": 0,
"keep_closed": 0,
"label": "EDI",
"link_type": "DocType",
"open_in_new_tab": 0,
"show_arrow": 0,
"type": "Section Break"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Code List",
"link_to": "Code List",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Common Code",
"link_to": "Common Code",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"icon": "layers",
"indent": 1,
"is_default_module": 0,
"keep_closed": 0,
"label": "Bulk Transaction",
"link_type": "DocType",
"open_in_new_tab": 0,
"show_arrow": 0,
"type": "Section Break"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Bulk Transaction Log Detail",
"link_to": "Bulk Transaction Log Detail",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Bulk Transaction Log",
"link_to": "Bulk Transaction Log",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 1,
"is_default_module": 0,
"keep_closed": 0,
"label": "Video",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Section Break"
},
{
"added": 0,
"child": 1,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
@@ -142,7 +38,7 @@
},
{
"added": 0,
"child": 1,
"child": 0,
"collapsible": 1,
"hidden": 0,
"icon": "settings",
@@ -156,6 +52,20 @@
"show_arrow": 0,
"type": "Link"
},
{
"added": 0,
"child": 0,
"collapsible": 1,
"hidden": 0,
"indent": 0,
"is_default_module": 0,
"keep_closed": 0,
"label": "Reports",
"link_type": "DocType",
"open_in_new_tab": 1,
"show_arrow": 0,
"type": "Section Break"
},
{
"added": 0,
"child": 1,
@@ -173,11 +83,12 @@
"type": "Link"
}
],
"modified": "2026-09-02 03:26:54.027941",
"modified": "2026-08-16 00:00:00.000000",
"modified_by": "Administrator",
"module": "Utilities",
"name": "Utilities",
"owner": "Administrator",
"sequence_id": 0.0,
"standard": 1,
"title": "Utilities"
}