mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-26 13:25:20 +00:00
Merge branch 'develop' into party-import-tool-integrated-with-data-import-tool
This commit is contained in:
45
.github/workflows/notify-support-on-release.yml
vendored
Normal file
45
.github/workflows/notify-support-on-release.yml
vendored
Normal file
@@ -0,0 +1,45 @@
|
||||
name: Notify Support on PR release
|
||||
|
||||
on:
|
||||
issue_comment:
|
||||
types: [created]
|
||||
|
||||
permissions: {}
|
||||
|
||||
jobs:
|
||||
notify-support:
|
||||
if: >-
|
||||
github.event.issue.pull_request
|
||||
&& github.event.comment.user.id == 28699486
|
||||
&& contains(github.event.comment.body, 'This PR is included in version')
|
||||
runs-on: ubuntu-latest
|
||||
timeout-minutes: 2
|
||||
|
||||
steps:
|
||||
- name: Notify support.frappe.io
|
||||
env:
|
||||
COMMENT_ID: ${{ github.event.comment.id }}
|
||||
PR_NUMBER: ${{ github.event.issue.number }}
|
||||
REPOSITORY: ${{ github.repository }}
|
||||
SUPPORT_FRAPPE_AUTH: ${{ secrets.SUPPORT_FRAPPE_AUTH }}
|
||||
run: |
|
||||
payload="$(
|
||||
jq -n \
|
||||
--arg repository "$REPOSITORY" \
|
||||
--argjson pr_number "$PR_NUMBER" \
|
||||
--argjson comment_id "$COMMENT_ID" \
|
||||
'{
|
||||
repository: $repository,
|
||||
pr_number: $pr_number,
|
||||
comment_id: $comment_id
|
||||
}'
|
||||
)"
|
||||
|
||||
curl --fail-with-body \
|
||||
--retry 3 \
|
||||
--retry-all-errors \
|
||||
--request POST \
|
||||
--header "Authorization: $SUPPORT_FRAPPE_AUTH" \
|
||||
--header "Content-Type: application/json" \
|
||||
--data "$payload" \
|
||||
"https://support.frappe.io/api/method/notify_pr_release"
|
||||
@@ -203,7 +203,7 @@
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2026-04-14 18:14:42.202065",
|
||||
"modified": "2026-08-21 23:11:37.851001",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Account",
|
||||
@@ -264,6 +264,46 @@
|
||||
{
|
||||
"role": "HR Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -101,7 +101,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:06:36.896195",
|
||||
"modified": "2026-08-21 23:11:39.423431",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank",
|
||||
@@ -118,11 +118,20 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -269,7 +269,7 @@
|
||||
"link_fieldname": "default_bank_account"
|
||||
}
|
||||
],
|
||||
"modified": "2026-04-11 19:46:27.609994",
|
||||
"modified": "2026-08-21 23:11:39.585456",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Bank Account",
|
||||
@@ -299,6 +299,22 @@
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -126,7 +126,7 @@
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2026-04-14 18:15:27.367298",
|
||||
"modified": "2026-08-21 23:11:40.799391",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Cost Center",
|
||||
@@ -181,6 +181,54 @@
|
||||
{
|
||||
"role": "HR Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -125,7 +125,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2024-11-19 16:35:11.836441",
|
||||
"modified": "2026-08-21 23:11:41.010871",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Coupon Code",
|
||||
@@ -179,11 +179,20 @@
|
||||
"role": "Website Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "coupon_name",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,7 +20,7 @@
|
||||
],
|
||||
"icon": "fa fa-book",
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:09:44.514241",
|
||||
"modified": "2026-08-21 23:11:42.386104",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Finance Book",
|
||||
@@ -55,13 +55,26 @@
|
||||
"report": 1,
|
||||
"role": "Auditor",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"role": "HR Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"search_fields": "finance_book_name",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1,
|
||||
"track_seen": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -82,7 +82,7 @@
|
||||
"icon": "fa fa-calendar",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2024-05-27 17:29:55.560840",
|
||||
"modified": "2026-08-21 23:11:42.509102",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Fiscal Year",
|
||||
@@ -131,10 +131,15 @@
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Auditor"
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "name",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:09:55.573483",
|
||||
"modified": "2026-08-21 23:11:43.571355",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Item Tax Template",
|
||||
@@ -95,12 +95,61 @@
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Item Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "title",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -147,14 +147,14 @@
|
||||
"fieldtype": "Column Break"
|
||||
},
|
||||
{
|
||||
"fieldname": "project",
|
||||
"fieldtype": "Link",
|
||||
"label": "Project",
|
||||
"options": "Project"
|
||||
"fieldname": "project",
|
||||
"fieldtype": "Link",
|
||||
"label": "Project",
|
||||
"options": "Project"
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:03.361383",
|
||||
"modified": "2026-08-21 23:11:44.144864",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Loyalty Program",
|
||||
@@ -171,11 +171,20 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -48,7 +48,7 @@
|
||||
"idx": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2026-04-14 18:16:47.795986",
|
||||
"modified": "2026-08-21 23:11:44.763131",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Mode of Payment",
|
||||
@@ -76,6 +76,30 @@
|
||||
{
|
||||
"role": "HR Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -46,7 +46,7 @@
|
||||
"icon": "fa fa-bar-chart",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:05.873547",
|
||||
"modified": "2026-08-21 23:11:44.908490",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Monthly Distribution",
|
||||
@@ -69,9 +69,14 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager"
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -116,7 +116,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:11.511137",
|
||||
"modified": "2026-08-21 23:11:45.693762",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Payment Term",
|
||||
@@ -157,11 +157,36 @@
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1643,7 +1643,7 @@
|
||||
"icon": "fa fa-file-text",
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-08-12 12:00:00.000000",
|
||||
"modified": "2026-08-21 23:11:45.029925",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Invoice",
|
||||
@@ -1686,6 +1686,14 @@
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"role": "All"
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -582,7 +582,7 @@
|
||||
"link_fieldname": "pos_profile"
|
||||
}
|
||||
],
|
||||
"modified": "2026-02-10 14:24:48.597412",
|
||||
"modified": "2026-08-21 23:11:45.419667",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "POS Profile",
|
||||
@@ -606,6 +606,10 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User"
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -1696,7 +1696,7 @@
|
||||
"idx": 204,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-08-12 12:00:00.000000",
|
||||
"modified": "2026-08-21 23:11:46.733125",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
@@ -1749,6 +1749,18 @@
|
||||
"read": 1,
|
||||
"role": "Accounts Manager",
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -77,7 +77,7 @@
|
||||
"icon": "fa fa-money",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:26.945131",
|
||||
"modified": "2026-08-21 23:11:47.506282",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Taxes and Charges Template",
|
||||
@@ -104,12 +104,29 @@
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Purchase User"
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"show_title_field_in_link": 1,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "title",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -79,7 +79,7 @@
|
||||
"icon": "fa fa-money",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:38.343481",
|
||||
"modified": "2026-08-21 23:11:48.797423",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Taxes and Charges Template",
|
||||
@@ -113,12 +113,33 @@
|
||||
"role": "Sales Master Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"show_title_field_in_link": 1,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "ASC",
|
||||
"states": [],
|
||||
"title_field": "title",
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -149,7 +149,7 @@
|
||||
"icon": "fa fa-truck",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2026-07-22 14:53:27.315435",
|
||||
"modified": "2026-08-21 23:11:49.532098",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Shipping Rule",
|
||||
@@ -195,6 +195,38 @@
|
||||
"role": "Sales Master Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:51.976600",
|
||||
"modified": "2026-08-21 23:11:50.740962",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Tax Category",
|
||||
@@ -68,11 +68,68 @@
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Item Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -100,7 +100,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-07-30 07:13:51.785735",
|
||||
"modified": "2026-08-21 23:11:50.979676",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Tax Withholding Category",
|
||||
@@ -142,6 +142,26 @@
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Item Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-06-29 05:25:50.243710",
|
||||
"modified": "2026-08-21 23:11:51.176158",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Tax Withholding Group",
|
||||
@@ -39,6 +39,30 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -4,6 +4,7 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_ent
|
||||
from erpnext.accounts.doctype.purchase_invoice.test_purchase_invoice import make_purchase_invoice
|
||||
from erpnext.accounts.party import get_party_shipping_address
|
||||
from erpnext.accounts.utils import (
|
||||
get_currency_precision,
|
||||
get_future_stock_vouchers,
|
||||
get_voucherwise_gl_entries,
|
||||
get_zero_cutoff,
|
||||
@@ -154,3 +155,18 @@ class TestUtils(ERPNextTestSuite):
|
||||
self.assertEqual(get_zero_cutoff(None), 0.005)
|
||||
self.assertEqual(get_zero_cutoff("EUR"), 0.005)
|
||||
self.assertEqual(get_zero_cutoff("BHD"), 0.0005)
|
||||
|
||||
def test_get_currency_precision_respects_zero_and_fallback(self):
|
||||
currency_precision = frappe.db.get_default("currency_precision")
|
||||
number_format = frappe.db.get_default("number_format")
|
||||
|
||||
try:
|
||||
frappe.db.set_default("number_format", "#,###.##")
|
||||
frappe.db.set_default("currency_precision", "0")
|
||||
self.assertEqual(get_currency_precision(), 0)
|
||||
|
||||
frappe.db.set_default("currency_precision", "")
|
||||
self.assertEqual(get_currency_precision(), 2)
|
||||
finally:
|
||||
frappe.db.set_default("currency_precision", currency_precision or "")
|
||||
frappe.db.set_default("number_format", number_format or "#,###.##")
|
||||
|
||||
@@ -1200,12 +1200,12 @@ def fix_total_debit_credit():
|
||||
|
||||
|
||||
def get_currency_precision():
|
||||
precision = cint(frappe.db.get_default("currency_precision"))
|
||||
if not precision:
|
||||
number_format = frappe.db.get_default("number_format") or "#,###.##"
|
||||
precision = get_number_format_info(number_format)[2]
|
||||
currency_precision = frappe.db.get_default("currency_precision")
|
||||
if currency_precision not in (None, ""):
|
||||
return cint(currency_precision)
|
||||
|
||||
return precision
|
||||
number_format = frappe.db.get_default("number_format") or "#,###.##"
|
||||
return get_number_format_info(number_format)[2]
|
||||
|
||||
|
||||
def get_fraction_units(currency: str) -> int:
|
||||
|
||||
@@ -627,7 +627,7 @@
|
||||
"link_fieldname": "target_asset"
|
||||
}
|
||||
],
|
||||
"modified": "2026-03-12 16:07:39.543227",
|
||||
"modified": "2026-08-21 23:11:38.364997",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset",
|
||||
@@ -663,6 +663,30 @@
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -73,7 +73,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2025-05-13 15:33:03.791814",
|
||||
"modified": "2026-08-21 23:11:38.710171",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Category",
|
||||
@@ -116,6 +116,10 @@
|
||||
"role": "Quality Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Item Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:06:34.976117",
|
||||
"modified": "2026-08-21 23:11:38.864427",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Maintenance Team",
|
||||
@@ -78,11 +78,16 @@
|
||||
"role": "Manufacturing User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -36,7 +36,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:06:35.869900",
|
||||
"modified": "2026-08-21 23:11:39.003078",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Asset Shift Factor",
|
||||
@@ -66,9 +66,14 @@
|
||||
"role": "Accounts User",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -143,7 +143,7 @@
|
||||
],
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2025-04-29 13:53:13.488906",
|
||||
"modified": "2026-08-21 23:11:43.994913",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Assets",
|
||||
"name": "Location",
|
||||
@@ -198,6 +198,10 @@
|
||||
"role": "Stock Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -440,19 +440,19 @@
|
||||
},
|
||||
{
|
||||
"default": "0",
|
||||
"description": "If checked, this Supplier is only available for transactions in the companies listed below.",
|
||||
"fieldname": "restrict_to_companies",
|
||||
"fieldtype": "Check",
|
||||
"label": "Restrict to Companies",
|
||||
"description": "If checked, this Supplier is only available for transactions in the companies listed below.",
|
||||
"permlevel": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.restrict_to_companies",
|
||||
"fieldname": "allowed_companies",
|
||||
"fieldtype": "Table MultiSelect",
|
||||
"label": "Allowed Companies",
|
||||
"options": "Company Restriction",
|
||||
"depends_on": "eval:doc.restrict_to_companies",
|
||||
"mandatory_depends_on": "eval:doc.restrict_to_companies",
|
||||
"options": "Company Restriction",
|
||||
"permlevel": 1
|
||||
},
|
||||
{
|
||||
@@ -592,7 +592,7 @@
|
||||
"link_fieldname": "party"
|
||||
}
|
||||
],
|
||||
"modified": "2026-08-14 16:10:58.600553",
|
||||
"modified": "2026-08-21 23:11:49.780507",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier",
|
||||
@@ -654,6 +654,30 @@
|
||||
"read": 1,
|
||||
"role": "Purchase Master Manager",
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Website Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -948,7 +948,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-08-12 12:00:00.000000",
|
||||
"modified": "2026-08-21 23:11:50.274992",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation",
|
||||
@@ -1007,6 +1007,14 @@
|
||||
"read": 1,
|
||||
"role": "Purchase Manager",
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -543,7 +543,7 @@
|
||||
"idx": 5,
|
||||
"image_field": "image",
|
||||
"links": [],
|
||||
"modified": "2026-02-10 14:36:37.157961",
|
||||
"modified": "2026-08-21 23:11:43.771048",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Lead",
|
||||
@@ -600,6 +600,10 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales User"
|
||||
},
|
||||
{
|
||||
"role": "Support Team",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -18,7 +18,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2025-12-17 12:09:34.687368",
|
||||
"modified": "2026-08-21 23:11:44.435488",
|
||||
"modified_by": "Administrator",
|
||||
"module": "CRM",
|
||||
"name": "Market Segment",
|
||||
@@ -36,6 +36,10 @@
|
||||
"role": "Sales Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -147,7 +147,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2024-12-05 15:44:21.520093",
|
||||
"modified": "2026-08-21 23:11:40.122402",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Blanket Order",
|
||||
@@ -167,12 +167,37 @@
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"search_fields": "blanket_order_type, to_date",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -771,7 +771,7 @@
|
||||
"image_field": "image",
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-08-19 14:00:00.000000",
|
||||
"modified": "2026-08-21 23:11:39.133941",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "BOM",
|
||||
@@ -802,6 +802,30 @@
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -9,6 +9,7 @@
|
||||
"from_warehouse",
|
||||
"warehouse",
|
||||
"material_request_type",
|
||||
"supplier",
|
||||
"column_break_4",
|
||||
"item_name",
|
||||
"uom",
|
||||
@@ -73,6 +74,15 @@
|
||||
"label": "Type",
|
||||
"options": "\nPurchase\nMaterial Transfer\nMaterial Issue\nManufacture\nSubcontracting\nCustomer Provided"
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"depends_on": "eval:['Purchase', 'Subcontracting'].includes(doc.material_request_type)",
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Supplier",
|
||||
"options": "Supplier"
|
||||
},
|
||||
{
|
||||
"fieldname": "column_break_4",
|
||||
"fieldtype": "Column Break"
|
||||
@@ -267,7 +277,7 @@
|
||||
"grid_page_length": 50,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-08-07 17:31:31.732720",
|
||||
"modified": "2026-08-22 11:00:00.000000",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Material Request Plan Item",
|
||||
|
||||
@@ -46,6 +46,7 @@ class MaterialRequestPlanItem(Document):
|
||||
schedule_date: DF.Date | None
|
||||
stock_reserved_qty: DF.Float
|
||||
sub_assembly_item_reference: DF.Data | None
|
||||
supplier: DF.Link | None
|
||||
uom: DF.Link | None
|
||||
warehouse: DF.Link
|
||||
# end: auto-generated types
|
||||
|
||||
@@ -74,7 +74,7 @@
|
||||
"hide_toolbar": 1,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2026-02-17 11:53:17.940039",
|
||||
"modified": "2026-08-21 23:11:45.858553",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Plant Floor",
|
||||
@@ -92,6 +92,10 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -493,9 +493,12 @@ frappe.ui.form.on("Production Plan", {
|
||||
<span class="${is_fg ? "item-fg" : ""}${is_material ? " text-muted" : ""}">${frappe.utils.escape_html(
|
||||
row.item_code
|
||||
)}</span>`;
|
||||
let procurement_label = row.supplier
|
||||
? __("Procurement ({0})", [frappe.utils.escape_html(row.supplier)])
|
||||
: __("Procurement");
|
||||
let detail = is_material
|
||||
? `<span class="text-muted">${__("Procurement")}</span>`
|
||||
: frappe.utils.escape_html(workstations.join(", ") || "-");
|
||||
? `<span class="text-muted">${procurement_label}</span>`
|
||||
: frappe.utils.escape_html(workstations.join(", ") || row.supplier || "-");
|
||||
|
||||
let starts_in = schedule_starts_in(row.start);
|
||||
|
||||
|
||||
@@ -270,9 +270,21 @@ class ProductionPlan(Document):
|
||||
def on_cancel(self):
|
||||
self.db_set("status", "Cancelled")
|
||||
self.delete_draft_work_order()
|
||||
self.delete_production_plan_schedule()
|
||||
self.update_bin_qty()
|
||||
self.update_sales_order()
|
||||
self.update_stock_reservation()
|
||||
self.delete_sub_assembly_and_material_rows()
|
||||
|
||||
def delete_production_plan_schedule(self):
|
||||
frappe.db.delete("Production Plan Schedule", {"production_plan": self.name})
|
||||
|
||||
def delete_sub_assembly_and_material_rows(self):
|
||||
for doctype in ("Production Plan Sub Assembly Item", "Material Request Plan Item"):
|
||||
frappe.db.delete(doctype, {"parent": self.name, "parenttype": "Production Plan"})
|
||||
|
||||
self.set("sub_assembly_items", [])
|
||||
self.set("mr_items", [])
|
||||
|
||||
def update_stock_reservation(self):
|
||||
if not self.reserve_stock:
|
||||
|
||||
@@ -161,6 +161,7 @@ def get_items_for_material_requests(
|
||||
mr_items = _apply_other_locations(
|
||||
doc, mr_items, warehouses, ignore_ordered_qty, get_parent_warehouse_data
|
||||
)
|
||||
_set_default_suppliers(mr_items, doc.get("company"))
|
||||
|
||||
if not mr_items:
|
||||
_warn_no_mr_items(doc)
|
||||
@@ -464,6 +465,59 @@ def _apply_other_locations(doc, mr_items, warehouses, ignore_ordered_qty, get_pa
|
||||
return new_mr_items
|
||||
|
||||
|
||||
def _set_default_suppliers(mr_items, company):
|
||||
procurement_types = ("Purchase", "Subcontracting")
|
||||
items = {
|
||||
row.get("item_code") for row in mr_items if row.get("material_request_type") in procurement_types
|
||||
}
|
||||
if not items:
|
||||
return
|
||||
|
||||
lead_time_suppliers = _get_default_lead_time_suppliers(items)
|
||||
item_default_suppliers = _get_item_default_suppliers(items, company)
|
||||
|
||||
for row in mr_items:
|
||||
if row.get("material_request_type") not in procurement_types or row.get("supplier"):
|
||||
continue
|
||||
|
||||
item_code = row.get("item_code")
|
||||
supplier = lead_time_suppliers.get(item_code) or item_default_suppliers.get(item_code)
|
||||
if supplier:
|
||||
row["supplier"] = supplier
|
||||
|
||||
|
||||
def _get_default_lead_time_suppliers(items):
|
||||
table = frappe.qb.DocType("Item Lead Time Supplier")
|
||||
rows = (
|
||||
frappe.qb.from_(table)
|
||||
.select(table.parent, table.supplier)
|
||||
.where(
|
||||
table.parent.isin(list(items)) & (table.parenttype == "Item Lead Time") & (table.is_default == 1)
|
||||
)
|
||||
.run(as_dict=True)
|
||||
)
|
||||
return {row.parent: row.supplier for row in rows}
|
||||
|
||||
|
||||
def _get_item_default_suppliers(items, company):
|
||||
if not company:
|
||||
return {}
|
||||
|
||||
table = frappe.qb.DocType("Item Default")
|
||||
rows = (
|
||||
frappe.qb.from_(table)
|
||||
.select(table.parent, table.default_supplier)
|
||||
.where(
|
||||
table.parent.isin(list(items))
|
||||
& (table.parenttype == "Item")
|
||||
& (table.company == company)
|
||||
& table.default_supplier.isnotnull()
|
||||
)
|
||||
.run(as_dict=True)
|
||||
)
|
||||
return {row.parent: row.default_supplier for row in rows}
|
||||
|
||||
|
||||
def _warn_no_mr_items(doc):
|
||||
to_enable = frappe.bold(frappe.get_meta("Production Plan").get_field("ignore_existing_ordered_qty").label)
|
||||
warehouse = frappe.bold(doc.get("for_warehouse"))
|
||||
|
||||
@@ -19,6 +19,7 @@
|
||||
"column_break_item",
|
||||
"operation",
|
||||
"workstation",
|
||||
"supplier",
|
||||
"schedule_section",
|
||||
"from_time",
|
||||
"column_break_time",
|
||||
@@ -117,6 +118,14 @@
|
||||
"options": "Workstation",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.row_type == 'Raw Material' || doc.supplier",
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier",
|
||||
"options": "Supplier",
|
||||
"read_only": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "schedule_section",
|
||||
"fieldtype": "Section Break",
|
||||
@@ -150,7 +159,7 @@
|
||||
],
|
||||
"index_web_pages_for_search": 0,
|
||||
"links": [],
|
||||
"modified": "2026-08-13 11:00:00.000000",
|
||||
"modified": "2026-08-22 11:00:00.000000",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Production Plan Schedule",
|
||||
|
||||
@@ -29,8 +29,9 @@ class ProductionPlanSchedule(Document):
|
||||
operation: DF.Link | None
|
||||
plan_row: DF.Data | None
|
||||
production_plan: DF.Link
|
||||
row_type: DF.Literal["Finished Good", "Sub Assembly"]
|
||||
row_type: DF.Literal["Finished Good", "Sub Assembly", "Raw Material"]
|
||||
subject: DF.Data | None
|
||||
supplier: DF.Link | None
|
||||
task_key: DF.Data | None
|
||||
to_time: DF.Datetime
|
||||
workstation: DF.Link | None
|
||||
|
||||
@@ -158,7 +158,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-01-02 15:09:32.165242",
|
||||
"modified": "2026-08-21 23:11:47.893072",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Manufacturing",
|
||||
"name": "Sales Forecast",
|
||||
@@ -234,6 +234,10 @@
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -7,7 +7,7 @@ from collections import defaultdict
|
||||
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.utils import cint, flt, get_datetime
|
||||
from frappe.utils import add_to_date, cint, flt, get_datetime, getdate
|
||||
|
||||
from erpnext.manufacturing.scheduling import loaders
|
||||
from erpnext.manufacturing.scheduling.engine import SchedulingEngine
|
||||
@@ -126,7 +126,7 @@ def build_plan_tasks(plan, use_item_dates=0, item_dates=None):
|
||||
fg_deps = get_finished_good_dependencies(fg_row, sub_rows, row_bounds)
|
||||
|
||||
fg_tasks, first_keys, _terminal = build_row_tasks(
|
||||
plan, fg_row.bom_no, fg_row.item_code, flt(fg_row.planned_qty), False, fg_row.name, ctx.lead_times
|
||||
plan, fg_row.bom_no, fg_row.item_code, flt(fg_row.planned_qty), False, fg_row.name, ctx
|
||||
)
|
||||
wire_dependencies(fg_tasks, fg_deps)
|
||||
wire_material_dependencies(
|
||||
@@ -151,6 +151,10 @@ def get_build_context(plan):
|
||||
item for items in bom_materials.values() for item in items if item not in produced_items
|
||||
}
|
||||
lead_times = get_lead_time_details(plan, material_items)
|
||||
supplier_lead_times = get_supplier_lead_times(material_items | produced_items)
|
||||
material_lead_days, material_suppliers = get_material_lead_days(
|
||||
material_items, lead_times, supplier_lead_times, get_chosen_suppliers(plan)
|
||||
)
|
||||
|
||||
return frappe._dict(
|
||||
bom_materials={
|
||||
@@ -158,13 +162,41 @@ def get_build_context(plan):
|
||||
for bom, items in bom_materials.items()
|
||||
},
|
||||
lead_times=lead_times,
|
||||
material_lead_days=get_material_lead_days(material_items, lead_times),
|
||||
supplier_lead_times=supplier_lead_times,
|
||||
material_lead_days=material_lead_days,
|
||||
material_suppliers=material_suppliers,
|
||||
material_tasks={},
|
||||
tasks=[],
|
||||
task_info={},
|
||||
)
|
||||
|
||||
|
||||
def get_supplier_lead_times(item_codes):
|
||||
if not item_codes:
|
||||
return {}
|
||||
|
||||
table = frappe.qb.DocType("Item Lead Time Supplier")
|
||||
rows = (
|
||||
frappe.qb.from_(table)
|
||||
.select(table.parent, table.supplier, table.purchase_time, table.buffer_time, table.is_default)
|
||||
.where(table.parent.isin(list(item_codes)) & (table.parenttype == "Item Lead Time"))
|
||||
.run(as_dict=True)
|
||||
)
|
||||
|
||||
grouped = defaultdict(dict)
|
||||
for row in rows:
|
||||
grouped[row.parent][row.supplier] = row
|
||||
return dict(grouped)
|
||||
|
||||
|
||||
def get_chosen_suppliers(plan):
|
||||
chosen = defaultdict(set)
|
||||
for row in plan.get("mr_items") or []:
|
||||
if row.get("supplier"):
|
||||
chosen[row.item_code].add(row.supplier)
|
||||
return chosen
|
||||
|
||||
|
||||
def get_bom_materials(plan):
|
||||
boms = {row.bom_no for row in plan.po_items if row.bom_no}
|
||||
boms.update(row.bom_no for row in plan.sub_assembly_items if row.bom_no)
|
||||
@@ -182,8 +214,8 @@ def get_bom_materials(plan):
|
||||
return materials
|
||||
|
||||
|
||||
def get_material_lead_days(material_items, lead_times):
|
||||
missing = [item for item in material_items if item not in lead_times]
|
||||
def get_material_lead_days(material_items, lead_times, supplier_lead_times, chosen_suppliers):
|
||||
missing = [item for item in material_items if item not in lead_times and item not in supplier_lead_times]
|
||||
item_master_days = {}
|
||||
if missing:
|
||||
item_master_days = dict(
|
||||
@@ -192,15 +224,38 @@ def get_material_lead_days(material_items, lead_times):
|
||||
)
|
||||
)
|
||||
|
||||
lead_days = {}
|
||||
lead_days, suppliers = {}, {}
|
||||
for item in material_items:
|
||||
lead_time = lead_times.get(item)
|
||||
if lead_time:
|
||||
lead_days[item] = cint(lead_time.purchase_time) + cint(lead_time.buffer_time)
|
||||
else:
|
||||
lead_days[item] = cint(item_master_days.get(item))
|
||||
days, supplier = resolve_purchase_lead_time(
|
||||
lead_times.get(item), supplier_lead_times.get(item), chosen_suppliers.get(item)
|
||||
)
|
||||
lead_days[item] = cint(item_master_days.get(item)) if days is None else days
|
||||
if supplier:
|
||||
suppliers[item] = supplier
|
||||
|
||||
return lead_days
|
||||
return lead_days, suppliers
|
||||
|
||||
|
||||
def resolve_purchase_lead_time(lead_time, supplier_rows, chosen_suppliers=None):
|
||||
rows = supplier_rows or {}
|
||||
item_days = cint(lead_time.purchase_time) + cint(lead_time.buffer_time) if lead_time else None
|
||||
|
||||
candidates = []
|
||||
for supplier in chosen_suppliers or []:
|
||||
if supplier in rows:
|
||||
candidates.append(
|
||||
(cint(rows[supplier].purchase_time) + cint(rows[supplier].buffer_time), supplier)
|
||||
)
|
||||
elif item_days is not None:
|
||||
candidates.append((item_days, supplier))
|
||||
|
||||
if candidates:
|
||||
return max(candidates)
|
||||
|
||||
default_row = next((r for r in rows.values() if r.is_default), None)
|
||||
if default_row:
|
||||
return cint(default_row.purchase_time) + cint(default_row.buffer_time), default_row.supplier
|
||||
return (item_days, None) if lead_time else (None, None)
|
||||
|
||||
|
||||
def wire_material_dependencies(bom_no, first_tasks, ctx, consumer_row=None):
|
||||
@@ -229,6 +284,7 @@ def get_material_task(item_code, lead_days, ctx, consumer_row=None):
|
||||
"item_code": item_code,
|
||||
"operation": None,
|
||||
"parent_row": None,
|
||||
"supplier": ctx.material_suppliers.get(item_code),
|
||||
"consumers": [],
|
||||
}
|
||||
|
||||
@@ -250,10 +306,19 @@ def set_chain_earliest_start(row_date, sub_rows, row_bounds, fg_tasks):
|
||||
|
||||
def build_sub_assembly_tasks(plan, sub_rows, ctx):
|
||||
row_bounds = {}
|
||||
row_suppliers = {}
|
||||
for row in sub_rows:
|
||||
subcontracted = row.type_of_manufacturing == "Subcontract"
|
||||
row_suppliers[row.name] = get_subcontract_supplier(row, ctx) if subcontracted else None
|
||||
row_tasks, first_keys, terminal_keys = build_row_tasks(
|
||||
plan, row.bom_no, row.production_item, flt(row.qty), subcontracted, row.name, ctx.lead_times
|
||||
plan,
|
||||
row.bom_no,
|
||||
row.production_item,
|
||||
flt(row.qty),
|
||||
subcontracted,
|
||||
row.name,
|
||||
ctx,
|
||||
row_suppliers[row.name],
|
||||
)
|
||||
row_bounds[row.name] = (first_keys, terminal_keys, row_tasks)
|
||||
if not subcontracted:
|
||||
@@ -280,11 +345,21 @@ def build_sub_assembly_tasks(plan, sub_rows, ctx):
|
||||
ctx.tasks,
|
||||
ctx.task_info,
|
||||
parent_row=row.production_plan_item,
|
||||
supplier=row_suppliers[row.name],
|
||||
)
|
||||
|
||||
return row_bounds
|
||||
|
||||
|
||||
def get_subcontract_supplier(row, ctx):
|
||||
if row.supplier:
|
||||
return row.supplier
|
||||
|
||||
rows = ctx.supplier_lead_times.get(row.production_item) or {}
|
||||
default_row = next((r for r in rows.values() if r.is_default), None)
|
||||
return default_row.supplier if default_row else None
|
||||
|
||||
|
||||
def get_first_tasks(bounds):
|
||||
first_keys, _terminal_keys, row_tasks = bounds
|
||||
return [task for task in row_tasks if task.key in first_keys]
|
||||
@@ -305,7 +380,9 @@ def wire_dependencies(first_tasks, dependency_keys):
|
||||
task.depends_on = list(dict.fromkeys([*task.depends_on, *dependency_keys]))
|
||||
|
||||
|
||||
def register_tasks(row_tasks, row_name, row_type, item_code, tasks, task_info, parent_row=None):
|
||||
def register_tasks(
|
||||
row_tasks, row_name, row_type, item_code, tasks, task_info, parent_row=None, supplier=None
|
||||
):
|
||||
for task in row_tasks:
|
||||
tasks.append(task)
|
||||
task_info[task.key] = {
|
||||
@@ -314,19 +391,26 @@ def register_tasks(row_tasks, row_name, row_type, item_code, tasks, task_info, p
|
||||
"item_code": item_code,
|
||||
"operation": task.label,
|
||||
"parent_row": parent_row,
|
||||
"supplier": supplier,
|
||||
}
|
||||
|
||||
|
||||
def build_row_tasks(plan, bom_no, item_code, qty, subcontracted, prefix, lead_times):
|
||||
def build_row_tasks(plan, bom_no, item_code, qty, subcontracted, prefix, ctx, supplier=None):
|
||||
if not subcontracted and bom_no and frappe.get_cached_value("BOM", bom_no, "with_operations"):
|
||||
row_tasks, terminal_keys = loaders.build_bom_operation_tasks(bom_no, qty, prefix)
|
||||
if row_tasks:
|
||||
first_keys = [task.key for task in row_tasks if not task.depends_on]
|
||||
return row_tasks, first_keys, terminal_keys
|
||||
|
||||
duration = get_lead_time_duration_mins(
|
||||
lead_times.get(item_code), qty, subcontracted, cint(plan.get("no_of_shifts"))
|
||||
)
|
||||
lead_time = ctx.lead_times.get(item_code)
|
||||
if subcontracted:
|
||||
supplier_row = (ctx.supplier_lead_times.get(item_code) or {}).get(supplier)
|
||||
if supplier_row:
|
||||
lead_time = frappe._dict(
|
||||
purchase_time=supplier_row.purchase_time, buffer_time=supplier_row.buffer_time
|
||||
)
|
||||
|
||||
duration = get_lead_time_duration_mins(lead_time, qty, subcontracted, cint(plan.get("no_of_shifts")))
|
||||
task = Task(key=prefix, duration_mins=duration)
|
||||
return [task], [task.key], [task.key]
|
||||
|
||||
@@ -338,20 +422,34 @@ def get_lead_time_duration_mins(lead_time, qty, subcontracted, no_of_shifts):
|
||||
if subcontracted:
|
||||
return max(cint(lead_time.purchase_time) + cint(lead_time.buffer_time), 1) * 1440.0
|
||||
|
||||
days = 0
|
||||
buffer_mins = cint(lead_time.buffer_time) * 1440.0
|
||||
days_needed = get_days_needed(lead_time, qty, no_of_shifts)
|
||||
if not days_needed:
|
||||
return max(buffer_mins, 1440.0)
|
||||
|
||||
full_days = math.ceil(days_needed) - 1
|
||||
partial_day_mins = (days_needed - full_days) * get_daily_working_mins(lead_time, no_of_shifts)
|
||||
return full_days * 1440.0 + partial_day_mins + buffer_mins
|
||||
|
||||
|
||||
def get_days_needed(lead_time, qty, no_of_shifts):
|
||||
capacity = get_daily_capacity(lead_time, no_of_shifts)
|
||||
if capacity:
|
||||
days = math.ceil(qty / capacity)
|
||||
elif lead_time.manufacturing_time_in_mins:
|
||||
minutes_per_day = (
|
||||
(no_of_shifts or cint(lead_time.no_of_shift) or 1)
|
||||
* (cint(lead_time.shift_time_in_hours) or 8)
|
||||
* 60
|
||||
* (cint(lead_time.no_of_workstations) or 1)
|
||||
)
|
||||
days = math.ceil(cint(lead_time.manufacturing_time_in_mins) * qty / minutes_per_day)
|
||||
return qty / capacity
|
||||
|
||||
return max(days + cint(lead_time.buffer_time), 1) * 1440.0
|
||||
if lead_time.manufacturing_time_in_mins:
|
||||
minutes_per_day = get_daily_working_mins(lead_time, no_of_shifts) * (
|
||||
cint(lead_time.no_of_workstations) or 1
|
||||
)
|
||||
return cint(lead_time.manufacturing_time_in_mins) * qty / minutes_per_day
|
||||
|
||||
return 0
|
||||
|
||||
|
||||
def get_daily_working_mins(lead_time, no_of_shifts):
|
||||
return (
|
||||
(no_of_shifts or cint(lead_time.no_of_shift) or 1) * (cint(lead_time.shift_time_in_hours) or 8) * 60.0
|
||||
)
|
||||
|
||||
|
||||
def get_daily_capacity(lead_time, no_of_shifts):
|
||||
@@ -400,6 +498,7 @@ def build_proposal(plan, result, task_info):
|
||||
"row_type": info["row_type"],
|
||||
"item_code": info["item_code"],
|
||||
"parent_row": info.get("parent_row"),
|
||||
"supplier": info.get("supplier"),
|
||||
"consumers": info.get("consumers") or [],
|
||||
}
|
||||
)
|
||||
@@ -466,6 +565,7 @@ def make_schedule_entry(plan, row_name, row, block):
|
||||
"item_code": row["item_code"],
|
||||
"operation": block.get("operation") if block.get("workstation") else None,
|
||||
"workstation": block.get("workstation"),
|
||||
"supplier": row.get("supplier"),
|
||||
"from_time": block["from_time"],
|
||||
"to_time": block["to_time"],
|
||||
"duration_mins": block["duration_mins"],
|
||||
@@ -500,6 +600,57 @@ def update_plan_row_dates(plan, proposal, use_item_dates=0, item_dates=None):
|
||||
row.db_set("schedule_date", rows[row.name]["start"], update_modified=False)
|
||||
row.db_set("schedule_end_date", rows[row.name]["end"], update_modified=False)
|
||||
|
||||
update_material_request_row_dates(plan, rows)
|
||||
|
||||
|
||||
def update_material_request_row_dates(plan, rows):
|
||||
material_rows = {row["item_code"]: row for row in rows.values() if row.get("row_type") == "Raw Material"}
|
||||
supplier_lead_times = get_supplier_lead_times(set(material_rows))
|
||||
fallback_lead_days = get_fallback_lead_days(plan, set(material_rows))
|
||||
for row in plan.get("mr_items") or []:
|
||||
material = material_rows.get(row.item_code)
|
||||
if material:
|
||||
row.db_set(
|
||||
"schedule_date",
|
||||
get_material_row_schedule_date(row, material, supplier_lead_times, fallback_lead_days),
|
||||
update_modified=False,
|
||||
)
|
||||
|
||||
|
||||
def get_fallback_lead_days(plan, item_codes):
|
||||
lead_times = get_lead_time_details(plan, item_codes)
|
||||
missing = [item for item in item_codes if not lead_times.get(item)]
|
||||
master_days = {}
|
||||
if missing:
|
||||
master_days = dict(
|
||||
frappe.get_all(
|
||||
"Item", filters={"name": ("in", missing)}, fields=["name", "lead_time_days"], as_list=True
|
||||
)
|
||||
)
|
||||
|
||||
days = {}
|
||||
for item in item_codes:
|
||||
lead_time = lead_times.get(item)
|
||||
if lead_time:
|
||||
days[item] = cint(lead_time.purchase_time) + cint(lead_time.buffer_time)
|
||||
else:
|
||||
days[item] = cint(master_days.get(item)) or None
|
||||
return days
|
||||
|
||||
|
||||
def get_material_row_schedule_date(row, material, supplier_lead_times, fallback_lead_days):
|
||||
supplier = row.get("supplier")
|
||||
lead_row = (supplier_lead_times.get(row.item_code) or {}).get(supplier)
|
||||
days = None
|
||||
if lead_row:
|
||||
days = cint(lead_row.purchase_time) + cint(lead_row.buffer_time)
|
||||
elif supplier:
|
||||
days = fallback_lead_days.get(row.item_code)
|
||||
|
||||
if days is None:
|
||||
return getdate(material["end"])
|
||||
return getdate(add_to_date(get_datetime(material["start"]), days=days))
|
||||
|
||||
|
||||
def set_finished_good_start_date(fg_row, rows, use_item_dates, item_dates):
|
||||
if use_item_dates and (item_dates or {}).get(fg_row.name):
|
||||
|
||||
@@ -3,7 +3,7 @@
|
||||
|
||||
import frappe
|
||||
from frappe.tests.utils import change_settings
|
||||
from frappe.utils import add_to_date, get_datetime
|
||||
from frappe.utils import add_to_date, flt, get_datetime, getdate
|
||||
|
||||
from erpnext.manufacturing.doctype.job_card.job_card import OverlapError
|
||||
from erpnext.manufacturing.doctype.production_plan.test_production_plan import (
|
||||
@@ -12,7 +12,11 @@ from erpnext.manufacturing.doctype.production_plan.test_production_plan import (
|
||||
)
|
||||
from erpnext.manufacturing.doctype.work_order.test_work_order import make_operation, make_workstation
|
||||
from erpnext.manufacturing.scheduling import loaders
|
||||
from erpnext.manufacturing.scheduling.plan_adapter import apply_schedule, get_schedule_preview
|
||||
from erpnext.manufacturing.scheduling.plan_adapter import (
|
||||
apply_schedule,
|
||||
build_plan_tasks,
|
||||
get_schedule_preview,
|
||||
)
|
||||
from erpnext.stock.doctype.item.test_item import create_item
|
||||
from erpnext.tests.utils import ERPNextTestSuite
|
||||
|
||||
@@ -441,6 +445,106 @@ class TestPlanAdapter(ERPNextTestSuite):
|
||||
|
||||
self.assertRaises(frappe.ValidationError, entry.insert)
|
||||
|
||||
def test_cancelled_plan_clears_computed_rows(self):
|
||||
plan = self.make_plan()
|
||||
plan.cancel()
|
||||
|
||||
self.assertFalse(frappe.get_all("Production Plan Sub Assembly Item", filters={"parent": plan.name}))
|
||||
self.assertFalse(frappe.get_all("Material Request Plan Item", filters={"parent": plan.name}))
|
||||
|
||||
amended = frappe.copy_doc(frappe.get_doc("Production Plan", plan.name))
|
||||
amended.amended_from = plan.name
|
||||
amended.docstatus = 0
|
||||
amended.insert()
|
||||
self.assertFalse(amended.sub_assembly_items)
|
||||
|
||||
amended.get_sub_assembly_items()
|
||||
amended.submit()
|
||||
|
||||
self.assertTrue(amended.sub_assembly_items)
|
||||
for row in amended.sub_assembly_items:
|
||||
self.assertEqual(row.production_plan_item, amended.po_items[0].name)
|
||||
|
||||
tasks, task_info = build_plan_tasks(amended)
|
||||
scheduled_items = {info["item_code"] for info in task_info.values()}
|
||||
self.assertIn(amended.sub_assembly_items[0].production_item, scheduled_items)
|
||||
|
||||
def test_material_row_schedule_date_fallbacks(self):
|
||||
from erpnext.manufacturing.scheduling.plan_adapter import get_material_row_schedule_date
|
||||
|
||||
material = {
|
||||
"start": get_datetime("2026-11-16 09:00:00"),
|
||||
"end": get_datetime("2026-11-22 09:00:00"),
|
||||
}
|
||||
row = frappe._dict(item_code="Test PPS RM", supplier="Test PPS Supplier C")
|
||||
|
||||
self.assertEqual(
|
||||
get_material_row_schedule_date(row, material, {}, {"Test PPS RM": 0}), getdate("2026-11-16")
|
||||
)
|
||||
self.assertEqual(
|
||||
get_material_row_schedule_date(row, material, {}, {"Test PPS RM": None}), getdate("2026-11-22")
|
||||
)
|
||||
self.assertEqual(
|
||||
get_material_row_schedule_date(
|
||||
frappe._dict(item_code="Test PPS RM"), material, {}, {"Test PPS RM": 4}
|
||||
),
|
||||
getdate("2026-11-22"),
|
||||
)
|
||||
|
||||
@change_settings("Manufacturing Settings", {"mins_between_operations": 10, "allow_overtime": 0})
|
||||
def test_split_supplier_rows_keep_own_schedule_dates(self):
|
||||
suppliers = ["Test PPS Supplier A", "Test PPS Supplier B", "Test PPS Supplier C"]
|
||||
self.make_supplier_lead_time("Test PPS RM", suppliers)
|
||||
|
||||
plan = create_production_plan(
|
||||
item_code="Test PPS FG",
|
||||
planned_qty=2,
|
||||
use_multi_level_bom=1,
|
||||
do_not_submit=True,
|
||||
skip_getting_mr_items=True,
|
||||
)
|
||||
plan.get_sub_assembly_items()
|
||||
for supplier in suppliers:
|
||||
plan.append(
|
||||
"mr_items",
|
||||
{
|
||||
"item_code": "Test PPS RM",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"quantity": 2,
|
||||
"material_request_type": "Purchase",
|
||||
"supplier": supplier,
|
||||
},
|
||||
)
|
||||
plan.submit()
|
||||
|
||||
start_date = get_datetime("2026-11-09 09:00:00")
|
||||
preview = get_schedule_preview(plan.name, start_date)
|
||||
material_row = preview["rows"]["material:Test PPS RM"]
|
||||
self.assertEqual(material_row["supplier"], suppliers[1])
|
||||
self.assertEqual(material_row["end"], add_to_date(start_date, days=6))
|
||||
|
||||
apply_schedule(plan.name, start_date)
|
||||
schedule_dates = dict(
|
||||
frappe.get_all(
|
||||
"Material Request Plan Item",
|
||||
filters={"parent": plan.name, "item_code": "Test PPS RM"},
|
||||
fields=["supplier", "schedule_date"],
|
||||
as_list=True,
|
||||
)
|
||||
)
|
||||
self.assertEqual(schedule_dates[suppliers[0]], getdate(add_to_date(start_date, days=3)))
|
||||
self.assertEqual(schedule_dates[suppliers[1]], getdate(add_to_date(start_date, days=6)))
|
||||
self.assertEqual(schedule_dates[suppliers[2]], getdate(add_to_date(start_date, days=4)))
|
||||
|
||||
def test_plan_cancel_deletes_schedule_entries(self):
|
||||
plan = self.make_plan()
|
||||
apply_schedule(plan.name, "2026-11-02 09:00:00")
|
||||
self.assertTrue(frappe.db.exists("Production Plan Schedule", {"production_plan": plan.name}))
|
||||
|
||||
plan.reload()
|
||||
plan.cancel()
|
||||
self.assertFalse(frappe.db.exists("Production Plan Schedule", {"production_plan": plan.name}))
|
||||
|
||||
def test_incomplete_proposal_is_not_applied(self):
|
||||
from unittest.mock import patch
|
||||
|
||||
@@ -481,6 +585,131 @@ class TestPlanAdapter(ERPNextTestSuite):
|
||||
)
|
||||
self.assertEqual(sub_starts, [material_arrival, add_to_date(material_arrival, minutes=120)])
|
||||
|
||||
def test_purchase_lead_time_supplier_resolution(self):
|
||||
from erpnext.manufacturing.scheduling.plan_adapter import resolve_purchase_lead_time
|
||||
|
||||
lead_time = frappe._dict(purchase_time=4, buffer_time=0)
|
||||
supplier_rows = {
|
||||
"Supplier A": frappe._dict(supplier="Supplier A", purchase_time=3, buffer_time=0, is_default=1),
|
||||
"Supplier B": frappe._dict(supplier="Supplier B", purchase_time=6, buffer_time=1, is_default=0),
|
||||
}
|
||||
|
||||
self.assertEqual(
|
||||
resolve_purchase_lead_time(lead_time, supplier_rows, {"Supplier B"}), (7, "Supplier B")
|
||||
)
|
||||
self.assertEqual(
|
||||
resolve_purchase_lead_time(lead_time, supplier_rows, {"Supplier A", "Supplier B"}),
|
||||
(7, "Supplier B"),
|
||||
)
|
||||
self.assertEqual(resolve_purchase_lead_time(lead_time, supplier_rows), (3, "Supplier A"))
|
||||
self.assertEqual(resolve_purchase_lead_time(lead_time, None), (4, None))
|
||||
self.assertEqual(resolve_purchase_lead_time(None, None), (None, None))
|
||||
self.assertEqual(
|
||||
resolve_purchase_lead_time(lead_time, supplier_rows, {"Supplier C"}), (4, "Supplier C")
|
||||
)
|
||||
self.assertEqual(
|
||||
resolve_purchase_lead_time(lead_time, supplier_rows, {"Supplier A", "Supplier C"}),
|
||||
(4, "Supplier C"),
|
||||
)
|
||||
self.assertEqual(resolve_purchase_lead_time(None, supplier_rows, {"Supplier C"}), (3, "Supplier A"))
|
||||
|
||||
def make_supplier_lead_time(self, item_code, suppliers):
|
||||
for supplier in suppliers:
|
||||
if not frappe.db.exists("Supplier", supplier):
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Supplier",
|
||||
"supplier_name": supplier,
|
||||
"supplier_group": "All Supplier Groups",
|
||||
}
|
||||
).insert()
|
||||
|
||||
frappe.delete_doc("Item Lead Time", item_code, force=True)
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "Item Lead Time",
|
||||
"item_code": item_code,
|
||||
"purchase_time": 4,
|
||||
"supplier_lead_times": [
|
||||
{"supplier": suppliers[0], "purchase_time": 3, "is_default": 1},
|
||||
{"supplier": suppliers[1], "purchase_time": 6},
|
||||
],
|
||||
}
|
||||
).insert()
|
||||
self.addCleanup(frappe.delete_doc, "Item Lead Time", item_code, force=True)
|
||||
|
||||
@change_settings("Manufacturing Settings", {"mins_between_operations": 10, "allow_overtime": 0})
|
||||
def test_schedule_uses_supplier_wise_lead_time(self):
|
||||
suppliers = ["Test PPS Supplier A", "Test PPS Supplier B"]
|
||||
self.make_supplier_lead_time("Test PPS RM", suppliers)
|
||||
|
||||
plan = create_production_plan(
|
||||
item_code="Test PPS FG",
|
||||
planned_qty=2,
|
||||
use_multi_level_bom=1,
|
||||
do_not_submit=True,
|
||||
skip_getting_mr_items=True,
|
||||
)
|
||||
plan.get_sub_assembly_items()
|
||||
plan.save()
|
||||
start_date = get_datetime("2026-11-02 09:00:00")
|
||||
|
||||
preview = get_schedule_preview(plan.name, start_date)
|
||||
material_row = preview["rows"]["material:Test PPS RM"]
|
||||
self.assertEqual(material_row["supplier"], suppliers[0])
|
||||
self.assertEqual(material_row["end"], add_to_date(start_date, days=3))
|
||||
|
||||
plan.append(
|
||||
"mr_items",
|
||||
{
|
||||
"item_code": "Test PPS RM",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"quantity": 4,
|
||||
"material_request_type": "Purchase",
|
||||
"supplier": suppliers[1],
|
||||
},
|
||||
)
|
||||
plan.save()
|
||||
|
||||
preview = get_schedule_preview(plan.name, start_date)
|
||||
material_row = preview["rows"]["material:Test PPS RM"]
|
||||
self.assertEqual(material_row["supplier"], suppliers[1])
|
||||
self.assertEqual(material_row["end"], add_to_date(start_date, days=6))
|
||||
|
||||
plan.submit()
|
||||
apply_schedule(plan.name, start_date)
|
||||
entry = frappe.get_value(
|
||||
"Production Plan Schedule",
|
||||
{"production_plan": plan.name, "row_type": "Raw Material", "item_code": "Test PPS RM"},
|
||||
["supplier", "to_time"],
|
||||
as_dict=True,
|
||||
)
|
||||
self.assertEqual(entry.supplier, suppliers[1])
|
||||
self.assertEqual(
|
||||
frappe.db.get_value(
|
||||
"Material Request Plan Item",
|
||||
{"parent": plan.name, "item_code": "Test PPS RM"},
|
||||
"schedule_date",
|
||||
),
|
||||
getdate(add_to_date(start_date, days=6)),
|
||||
)
|
||||
|
||||
def test_lead_time_duration_counts_partial_day_as_working_hours(self):
|
||||
from erpnext.manufacturing.scheduling.plan_adapter import get_lead_time_duration_mins
|
||||
|
||||
lead_time = frappe._dict(
|
||||
capacity_per_day=8, daily_yield=100, no_of_shift=2, shift_time_in_hours=8, buffer_time=0
|
||||
)
|
||||
|
||||
self.assertEqual(get_lead_time_duration_mins(lead_time, 10, False, 2), 1680.0)
|
||||
self.assertEqual(get_lead_time_duration_mins(lead_time, 16, False, 2), 2400.0)
|
||||
self.assertEqual(get_lead_time_duration_mins(lead_time, 4, False, 2), 480.0)
|
||||
|
||||
mfg_lead_time = frappe._dict(
|
||||
manufacturing_time_in_mins=120, no_of_shift=2, shift_time_in_hours=8, buffer_time=0
|
||||
)
|
||||
self.assertEqual(get_lead_time_duration_mins(mfg_lead_time, 10, False, 2), 1680.0)
|
||||
|
||||
@change_settings("Manufacturing Settings", {"mins_between_operations": 10, "allow_overtime": 0})
|
||||
def test_preview_and_apply_schedule(self):
|
||||
plan = self.make_plan()
|
||||
|
||||
@@ -47,7 +47,7 @@
|
||||
"icon": "icon-flag",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2026-04-17 15:24:16.754519",
|
||||
"modified": "2026-08-21 23:11:38.223497",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Activity Type",
|
||||
@@ -91,6 +91,18 @@
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "HR User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -484,7 +484,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"max_attachments": 4,
|
||||
"modified": "2026-07-21 11:23:22.000000",
|
||||
"modified": "2026-08-21 23:11:46.332012",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Project",
|
||||
@@ -548,6 +548,78 @@
|
||||
{
|
||||
"role": "HR Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Support Team",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -34,7 +34,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2025-03-12 14:20:57.301906",
|
||||
"modified": "2026-08-21 23:11:46.618525",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Project Template",
|
||||
@@ -52,6 +52,14 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
@@ -60,4 +68,4 @@
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -423,7 +423,7 @@
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"max_attachments": 5,
|
||||
"modified": "2026-04-09 19:12:27.153143",
|
||||
"modified": "2026-08-21 23:11:50.547292",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Projects",
|
||||
"name": "Task",
|
||||
@@ -455,6 +455,18 @@
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Employee",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -730,7 +730,7 @@
|
||||
"link_fieldname": "party"
|
||||
}
|
||||
],
|
||||
"modified": "2026-08-14 16:10:58.600553",
|
||||
"modified": "2026-08-21 23:11:41.175219",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Customer",
|
||||
@@ -800,6 +800,62 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager"
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Employee",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Fulfillment User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "HR Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "HR User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Support Team",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Website Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -104,7 +104,7 @@
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-06-10 12:00:00.000000",
|
||||
"modified": "2026-08-21 23:11:46.161457",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Product Bundle",
|
||||
@@ -144,8 +144,33 @@
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"search_fields": "new_item_code,description",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "ASC",
|
||||
|
||||
@@ -1826,7 +1826,7 @@
|
||||
"idx": 105,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-08-14 12:43:19.480555",
|
||||
"modified": "2026-08-21 23:11:48.053347",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order",
|
||||
@@ -1893,6 +1893,14 @@
|
||||
"read": 1,
|
||||
"role": "Sales Manager",
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -19,7 +19,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:37.773308",
|
||||
"modified": "2026-08-21 23:11:48.555976",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Partner Type",
|
||||
@@ -37,11 +37,16 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"translated_doctype": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -56,7 +56,7 @@
|
||||
"idx": 1,
|
||||
"image_field": "image",
|
||||
"links": [],
|
||||
"modified": "2024-08-20 14:10:21.377962",
|
||||
"modified": "2026-08-21 23:11:40.278512",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Brand",
|
||||
@@ -103,11 +103,16 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts User"
|
||||
},
|
||||
{
|
||||
"role": "Website Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "ASC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1159,7 +1159,7 @@
|
||||
"image_field": "company_logo",
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2026-07-26 21:14:52.739814",
|
||||
"modified": "2026-08-21 23:11:40.429841",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Company",
|
||||
@@ -1229,6 +1229,10 @@
|
||||
"report": 1,
|
||||
"role": "HR Manager",
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Desk User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -140,7 +140,7 @@
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2025-12-02 13:58:03.378607",
|
||||
"modified": "2026-08-21 23:11:41.519748",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Customer Group",
|
||||
@@ -207,6 +207,26 @@
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"role": "Item Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Website Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -90,7 +90,7 @@
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2024-06-12 16:10:31.451257",
|
||||
"modified": "2026-08-21 23:11:41.697649",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Department",
|
||||
@@ -136,10 +136,27 @@
|
||||
{
|
||||
"role": "Employee",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "ASC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -130,7 +130,7 @@
|
||||
],
|
||||
"icon": "fa fa-user",
|
||||
"links": [],
|
||||
"modified": "2026-06-16 16:04:12.762960",
|
||||
"modified": "2026-08-21 23:11:41.847540",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Driver",
|
||||
@@ -173,6 +173,22 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Fulfillment User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -834,7 +834,7 @@
|
||||
"image_field": "image",
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2026-03-23 15:26:05.149280",
|
||||
"modified": "2026-08-21 23:11:42.091886",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Employee",
|
||||
@@ -874,6 +874,46 @@
|
||||
"role": "HR Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Fleet Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -153,7 +153,7 @@
|
||||
"icon": "fa fa-calendar",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2026-04-14 18:21:08.018741",
|
||||
"modified": "2026-08-21 23:11:42.675539",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Holiday List",
|
||||
@@ -174,6 +174,26 @@
|
||||
{
|
||||
"role": "HR User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -87,7 +87,7 @@
|
||||
"link_fieldname": "incoterm"
|
||||
}
|
||||
],
|
||||
"modified": "2022-11-17 22:35:52.084553",
|
||||
"modified": "2026-08-21 23:11:42.839127",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Incoterm",
|
||||
@@ -157,12 +157,29 @@
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Stock User"
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"show_title_field_in_link": 1,
|
||||
"sort_field": "name",
|
||||
"sort_order": "ASC",
|
||||
"states": [],
|
||||
"title_field": "title",
|
||||
"translated_doctype": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -192,7 +192,7 @@
|
||||
"icon": "fa fa-user",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:37.455664",
|
||||
"modified": "2026-08-21 23:11:48.371608",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Sales Partner",
|
||||
@@ -221,10 +221,47 @@
|
||||
"role": "Sales Master Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Website Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "ASC",
|
||||
"states": []
|
||||
}
|
||||
}
|
||||
|
||||
@@ -145,7 +145,7 @@
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2026-06-21 12:52:33.742603",
|
||||
"modified": "2026-08-21 23:11:48.642478",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Sales Person",
|
||||
@@ -177,8 +177,37 @@
|
||||
"role": "Sales Master Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"search_fields": "parent_sales_person",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "creation",
|
||||
|
||||
@@ -109,7 +109,7 @@
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2025-12-02 13:57:57.814686",
|
||||
"modified": "2026-08-21 23:11:50.079034",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Supplier Group",
|
||||
@@ -167,6 +167,14 @@
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Website Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -89,7 +89,7 @@
|
||||
"icon": "icon-legal",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2026-06-06 16:35:34.394675",
|
||||
"modified": "2026-08-21 23:11:51.312054",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Terms and Conditions",
|
||||
@@ -161,6 +161,22 @@
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -124,7 +124,7 @@
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2025-12-02 13:58:55.190485",
|
||||
"modified": "2026-08-21 23:11:51.487537",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Territory",
|
||||
@@ -183,6 +183,22 @@
|
||||
"report": 1,
|
||||
"role": "Accounts User",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Website Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -75,7 +75,7 @@
|
||||
"icon": "fa fa-compass",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2026-04-14 21:20:16.983514",
|
||||
"modified": "2026-08-21 23:11:51.629905",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "UOM",
|
||||
@@ -126,6 +126,10 @@
|
||||
"report": 1,
|
||||
"role": "Sales Manager",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"role": "Desk User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -204,7 +204,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2025-01-24 06:22:33.129805",
|
||||
"modified": "2026-08-21 23:11:51.754251",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Setup",
|
||||
"name": "Vehicle",
|
||||
@@ -238,9 +238,18 @@
|
||||
"role": "Delivery Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Fulfillment User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"search_fields": "license_plate,location,model",
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC",
|
||||
|
||||
@@ -215,7 +215,7 @@
|
||||
"image_field": "image",
|
||||
"links": [],
|
||||
"max_attachments": 5,
|
||||
"modified": "2026-06-17 16:01:26.556324",
|
||||
"modified": "2026-08-21 23:11:39.905227",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Batch",
|
||||
@@ -234,6 +234,58 @@
|
||||
"role": "Item Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales Master Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -28,6 +28,8 @@
|
||||
"purchase_time",
|
||||
"column_break_lsfp",
|
||||
"buffer_time",
|
||||
"supplier_lead_time_section",
|
||||
"supplier_lead_times",
|
||||
"item_details_tab",
|
||||
"item_name",
|
||||
"stock_uom"
|
||||
@@ -168,6 +170,18 @@
|
||||
"fieldtype": "Tab Break",
|
||||
"label": "Purchase Time"
|
||||
},
|
||||
{
|
||||
"fieldname": "supplier_lead_time_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Supplier Wise Purchase Time"
|
||||
},
|
||||
{
|
||||
"description": "Overrides the Purchase Time above for the selected supplier. The row marked as default is used when no supplier is selected.",
|
||||
"fieldname": "supplier_lead_times",
|
||||
"fieldtype": "Table",
|
||||
"label": "Supplier Lead Times",
|
||||
"options": "Item Lead Time Supplier"
|
||||
},
|
||||
{
|
||||
"fieldname": "manufacturing_time_tab",
|
||||
"fieldtype": "Tab Break",
|
||||
@@ -177,7 +191,7 @@
|
||||
"grid_page_length": 50,
|
||||
"index_web_pages_for_search": 1,
|
||||
"links": [],
|
||||
"modified": "2025-10-30 11:45:03.602345",
|
||||
"modified": "2026-08-22 11:00:00.000000",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Item Lead Time",
|
||||
|
||||
@@ -1,8 +1,10 @@
|
||||
# Copyright (c) 2025, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
# import frappe
|
||||
import frappe
|
||||
from frappe import _
|
||||
from frappe.model.document import Document
|
||||
from frappe.utils import cint
|
||||
|
||||
|
||||
class ItemLeadTime(Document):
|
||||
@@ -14,6 +16,10 @@ class ItemLeadTime(Document):
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
from erpnext.stock.doctype.item_lead_time_supplier.item_lead_time_supplier import (
|
||||
ItemLeadTimeSupplier,
|
||||
)
|
||||
|
||||
buffer_time: DF.Int
|
||||
capacity_per_day: DF.Int
|
||||
daily_yield: DF.Percent
|
||||
@@ -26,7 +32,25 @@ class ItemLeadTime(Document):
|
||||
purchase_time: DF.Int
|
||||
shift_time_in_hours: DF.Int
|
||||
stock_uom: DF.Link | None
|
||||
supplier_lead_times: DF.Table[ItemLeadTimeSupplier]
|
||||
total_workstation_time: DF.Int
|
||||
# end: auto-generated types
|
||||
|
||||
pass
|
||||
def validate(self):
|
||||
self.validate_supplier_lead_times()
|
||||
|
||||
def validate_supplier_lead_times(self):
|
||||
suppliers = set()
|
||||
default_rows = 0
|
||||
for row in self.supplier_lead_times:
|
||||
if row.supplier in suppliers:
|
||||
frappe.throw(
|
||||
_("Row #{0}: Supplier {1} is already added in the Supplier Lead Times table").format(
|
||||
row.idx, frappe.bold(row.supplier)
|
||||
)
|
||||
)
|
||||
suppliers.add(row.supplier)
|
||||
default_rows += cint(row.is_default)
|
||||
|
||||
if default_rows > 1:
|
||||
frappe.throw(_("Only one supplier can be marked as default in the Supplier Lead Times table"))
|
||||
|
||||
@@ -0,0 +1,58 @@
|
||||
{
|
||||
"actions": [],
|
||||
"creation": "2026-08-22 11:00:00.000000",
|
||||
"doctype": "DocType",
|
||||
"editable_grid": 1,
|
||||
"engine": "InnoDB",
|
||||
"field_order": [
|
||||
"supplier",
|
||||
"purchase_time",
|
||||
"buffer_time",
|
||||
"is_default"
|
||||
],
|
||||
"fields": [
|
||||
{
|
||||
"columns": 4,
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Supplier",
|
||||
"options": "Supplier",
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "purchase_time",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Purchase Time (Days)"
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"fieldname": "buffer_time",
|
||||
"fieldtype": "Int",
|
||||
"in_list_view": 1,
|
||||
"label": "Buffer Time (Days)"
|
||||
},
|
||||
{
|
||||
"columns": 2,
|
||||
"default": "0",
|
||||
"fieldname": "is_default",
|
||||
"fieldtype": "Check",
|
||||
"in_list_view": 1,
|
||||
"label": "Is Default"
|
||||
}
|
||||
],
|
||||
"index_web_pages_for_search": 1,
|
||||
"istable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-08-22 11:00:00.000000",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Item Lead Time Supplier",
|
||||
"owner": "Administrator",
|
||||
"permissions": [],
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": []
|
||||
}
|
||||
@@ -0,0 +1,25 @@
|
||||
# Copyright (c) 2026, Frappe Technologies Pvt. Ltd. and contributors
|
||||
# For license information, please see license.txt
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class ItemLeadTimeSupplier(Document):
|
||||
# begin: auto-generated types
|
||||
# This code is auto-generated. Do not modify anything in this block.
|
||||
|
||||
from typing import TYPE_CHECKING
|
||||
|
||||
if TYPE_CHECKING:
|
||||
from frappe.types import DF
|
||||
|
||||
buffer_time: DF.Int
|
||||
is_default: DF.Check
|
||||
parent: DF.Data
|
||||
parentfield: DF.Data
|
||||
parenttype: DF.Data
|
||||
purchase_time: DF.Int
|
||||
supplier: DF.Link
|
||||
# end: auto-generated types
|
||||
|
||||
pass
|
||||
@@ -87,7 +87,7 @@
|
||||
],
|
||||
"icon": "fa fa-certificate",
|
||||
"links": [],
|
||||
"modified": "2024-03-27 13:10:04.558108",
|
||||
"modified": "2026-08-21 23:11:44.296381",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Manufacturer",
|
||||
@@ -113,12 +113,21 @@
|
||||
"report": 1,
|
||||
"role": "Stock User",
|
||||
"share": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"search_fields": "short_name, full_name",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"title_field": "short_name"
|
||||
}
|
||||
}
|
||||
|
||||
@@ -377,7 +377,7 @@
|
||||
"idx": 70,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-08-07 10:30:00.000000",
|
||||
"modified": "2026-08-21 23:11:44.554719",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Material Request",
|
||||
@@ -441,6 +441,18 @@
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -944,6 +944,33 @@ class TestMaterialRequest(ERPNextTestSuite):
|
||||
for perm in permissions:
|
||||
perm.delete()
|
||||
|
||||
def test_auto_email_single_company_without_user_permission(self):
|
||||
from unittest.mock import patch
|
||||
|
||||
from erpnext.stock.reorder_item import get_email_list
|
||||
|
||||
users = ["test_reorder_single_1@example.com", "test_reorder_single_2@example.com"]
|
||||
for user in users:
|
||||
if not frappe.db.exists("User", user):
|
||||
frappe.get_doc(
|
||||
{
|
||||
"doctype": "User",
|
||||
"email": user,
|
||||
"first_name": user,
|
||||
"send_notifications": 0,
|
||||
"enabled": 1,
|
||||
"user_type": "System User",
|
||||
"roles": [{"role": "Purchase Manager"}],
|
||||
}
|
||||
).insert(ignore_permissions=True)
|
||||
|
||||
# single company: managers without any Company User Permission must still be emailed
|
||||
with patch("frappe.db.count", return_value=1):
|
||||
emails = get_email_list("_Test Company")
|
||||
|
||||
for user in users:
|
||||
self.assertIn(user, emails)
|
||||
|
||||
def test_manufacture_type_status_over_wo(self):
|
||||
from erpnext.stock.doctype.material_request.material_request import raise_work_orders
|
||||
|
||||
|
||||
@@ -84,7 +84,7 @@
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"max_attachments": 1,
|
||||
"modified": "2024-08-16 19:41:19.591111",
|
||||
"modified": "2026-08-21 23:11:45.985667",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Price List",
|
||||
@@ -124,12 +124,45 @@
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Manufacturing User"
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Website Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
"search_fields": "currency",
|
||||
"show_name_in_global_search": 1,
|
||||
"sort_field": "creation",
|
||||
"sort_order": "ASC",
|
||||
"states": [],
|
||||
"translated_doctype": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1294,7 +1294,7 @@
|
||||
"idx": 261,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2026-08-12 12:00:00.000000",
|
||||
"modified": "2026-08-21 23:11:47.160738",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt",
|
||||
@@ -1353,6 +1353,18 @@
|
||||
"read": 1,
|
||||
"role": "Stock Manager",
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -278,7 +278,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-12-24 15:21:03.240008",
|
||||
"modified": "2026-08-21 23:11:47.694751",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Quality Inspection",
|
||||
@@ -298,6 +298,46 @@
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Manufacturing User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Purchase User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Sales User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -252,7 +252,7 @@
|
||||
"index_web_pages_for_search": 1,
|
||||
"is_submittable": 1,
|
||||
"links": [],
|
||||
"modified": "2025-09-24 16:24:48.154853",
|
||||
"modified": "2026-08-21 23:11:49.103080",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Serial and Batch Bundle",
|
||||
@@ -384,6 +384,26 @@
|
||||
"share": 1,
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Accounts User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -312,7 +312,7 @@
|
||||
"icon": "fa fa-barcode",
|
||||
"idx": 1,
|
||||
"links": [],
|
||||
"modified": "2025-12-24 20:14:52.942251",
|
||||
"modified": "2026-08-21 23:11:48.936205",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Serial No",
|
||||
@@ -348,6 +348,22 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Stock User"
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -52,7 +52,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2026-03-29 00:00:00.000000",
|
||||
"modified": "2026-08-21 23:11:49.416348",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Shipment Parcel Template",
|
||||
@@ -69,11 +69,16 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Stock Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "DESC",
|
||||
"states": [],
|
||||
"track_changes": 1
|
||||
}
|
||||
}
|
||||
|
||||
@@ -286,7 +286,7 @@
|
||||
"idx": 1,
|
||||
"is_tree": 1,
|
||||
"links": [],
|
||||
"modified": "2026-02-05 18:17:11.035097",
|
||||
"modified": "2026-08-21 23:11:51.906705",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Warehouse",
|
||||
@@ -337,6 +337,34 @@
|
||||
{
|
||||
"read": 1,
|
||||
"role": "Manufacturing User"
|
||||
},
|
||||
{
|
||||
"role": "Delivery Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Delivery User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "HR Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Maintenance User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Quality Manager",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Website Manager",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"row_format": "Dynamic",
|
||||
|
||||
@@ -350,6 +350,10 @@ def get_email_list(company):
|
||||
|
||||
|
||||
def get_comapny_wise_users(company):
|
||||
# single company: no explicit permission needed, everyone has access
|
||||
if frappe.db.count("Company") == 1:
|
||||
return []
|
||||
|
||||
companies = [company]
|
||||
|
||||
if parent_company := frappe.db.get_value("Company", company, "parent_company"):
|
||||
|
||||
@@ -393,7 +393,7 @@
|
||||
"icon": "fa fa-ticket",
|
||||
"idx": 7,
|
||||
"links": [],
|
||||
"modified": "2026-04-09 19:14:57.692236",
|
||||
"modified": "2026-08-21 23:11:43.274229",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Support",
|
||||
"name": "Issue",
|
||||
@@ -418,6 +418,10 @@
|
||||
{
|
||||
"role": "HR User",
|
||||
"select": 1
|
||||
},
|
||||
{
|
||||
"role": "Projects User",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
|
||||
@@ -15,7 +15,7 @@
|
||||
}
|
||||
],
|
||||
"links": [],
|
||||
"modified": "2024-08-16 19:23:40.697426",
|
||||
"modified": "2026-08-21 23:11:43.457613",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Support",
|
||||
"name": "Issue Priority",
|
||||
@@ -32,12 +32,17 @@
|
||||
"role": "System Manager",
|
||||
"share": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"role": "Support Team",
|
||||
"select": 1
|
||||
}
|
||||
],
|
||||
"quick_entry": 1,
|
||||
"row_format": "Dynamic",
|
||||
"sort_field": "creation",
|
||||
"sort_order": "ASC",
|
||||
"states": [],
|
||||
"track_changes": 1,
|
||||
"translated_doctype": 1
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user