Skip to content

Commit

Permalink
Manufacturing capacity report (#57)
Browse files Browse the repository at this point in the history
* ci: update app in str(file path) code to more exact matching

* chore: remove unused code

* feat: add manufacturing capacity report

* tests: start manufacturing capacity report tests

* chore: uncomment formatting code

* docs: add manufacturing capacity report documentation

* fix: div by zero in parts can build calc

* docs: update for calculation differences

* fix: in stock qty to zero if none from query
  • Loading branch information
HKuz authored Mar 8, 2024
1 parent db5a742 commit 2936cde
Show file tree
Hide file tree
Showing 13 changed files with 762 additions and 37 deletions.
4 changes: 2 additions & 2 deletions .github/validate_customizations.py
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ def validate_module(customized_doctypes, set_module=False):
this_app = app_dir.stem
for doctype, customize_files in customized_doctypes.items():
for customize_file in customize_files:
if not this_app in str(customize_file):
if not this_app == customize_file.parent.parent.parent.parent.stem:
continue
module = customize_file.parent.parent.stem
file_contents = json.loads(customize_file.read_text())
Expand Down Expand Up @@ -85,7 +85,7 @@ def validate_no_custom_perms(customized_doctypes):
this_app = pathlib.Path(__file__).resolve().parent.parent.stem
for doctype, customize_files in customized_doctypes.items():
for customize_file in customize_files:
if not this_app in str(customize_file):
if not this_app == customize_file.parent.parent.parent.parent.stem:
continue
file_contents = json.loads(customize_file.read_text())
if file_contents.get("custom_perms"):
Expand Down
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
1 change: 1 addition & 0 deletions inventory_tools/docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@ The Inventory Tools application enhances and extends inventory-related functiona
- **[Warehouse Path](./warehouse_path.md)**: for any warehouse selection field, this features helps clearly identify warehouses by creating a warehouse path and adding a human-readable string under the warehouse name in the format "parent warehouse(s)->warehouse"
- **[Subcontracting Workflow via Work Order](./wo_subcontracting.md)**: an alternative to ERPNext's subcontracting workflow that enables a user to employ Work Orders, subcontracting Purchase Orders, and manufacturing Stock Entries in lieu of Purchase Receipts or Subcontracting Orders/Receipts. Enhancements to the subcontracting Purchase Invoice allow a user to quickly reconcile what Items have been received with what is being invoiced
- **[Inline Landed Costing](./landed_costing.md)**: Coming soon! This features enables a user to include any additional costs to be capitalized into an Item's valuation directly in a Purchase Receipt or Purchase Invoice without needing to create a separate Landed Cost Voucher
- **[Manufacturing Capacity](./manufacturing_capacity.md)**: a report-based interface to show, for a given BOM, the entire hierarchy of any BOM tree containing that BOM with demand and in-stock quantities for all levels

## Configuration
Any feature in Inventory Tools may be toggled on or off via the Inventory Tools Settings document. The only exception to this is the Material Demand report, which is generally available upon installation of the app. There may be one settings document for each company in ERPNext to enable features on a per-company basis. Follow the links above for further details around feature-specific configuration.
Expand Down
11 changes: 11 additions & 0 deletions inventory_tools/docs/manufacturing_capacity.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
# Manufacturing Capacity Report

Manufacturing Capacity is a report-based interface that, given a BOM and Warehouse, displays the demand and in-stock quantities for the entire hierarchy of any BOM tree containing that BOM.

Once the filters are set, the report traverses the BOM tree to find the top-level parents of the given BOM. From there, it finds total demand based on outstanding Sales Orders, Material Requests (of type "Manufacture"), and Work Orders, adjusting for any overlap. In stock quantities for each level are determined based on the selected Warehouse. The Parts Can Build quantity is based on what is in stock (for non-BOM/raw material rows) or the minimum Parts can Build of sub-levels for BOM rows.

The Parts Can Build Qty is slightly different for non-BOM vs BOM rows. For non-BOM (raw material) rows, it's the In Stock Qty divided by the Qty per Parent BOM. For BOM rows, it's the minimum of the Parts Can Build for all sub-assemblies. So if a BOM row requires a raw material that isn't in stock, it will show 0 Parts Can Build Qty, even if there are other sub assemblies in stock.

The Difference Qty calculation is also different for non-BOM and BOM rows. Since non-BOM rows account for the In Stock Qty in the Parts Can Build Qty number, the Difference Qty is the Parts Can Build less the Demanded Qty. For BOM rows, since the Parts Can Build Qty is based off available sub-assembly item quantities (and doesn't use the In Stock Qty in that calculation), the Difference Qty is the In Stock Qty plus Parts Can Build Qty less the Demanded Qty.

![Screen shot showing the Manufacturing Capacity report output for the Ambrosia Pie BOM and all Warehouses. There are rows for all levels of the BOM hierarchy - the Pie itself, sub-level rows for each sub-assembly of the Pie Crust and Pie Filling, with rows below each of those for the raw materials comprising each BOM. Columns include the BOM, Item, Description, Quantity per Parent BOM, BOM UoM, Demanded Quantity, In Stock Quantity, Parts Can Build quantity, and the Difference Quantity (demanded quantity less parts can build quantity).](./assets/manufacturing_capacity_report.png)
28 changes: 0 additions & 28 deletions inventory_tools/inventory_tools/overrides/work_order.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,4 @@
import frappe
from erpnext.manufacturing.doctype.bom.bom import get_children as get_bom_children
from erpnext.manufacturing.doctype.work_order.work_order import (
OverProductionError,
StockOverProductionError,
Expand Down Expand Up @@ -426,33 +425,6 @@ def add_to_existing_purchase_order(wo_name, po_name):
return


def get_sub_assembly_items(bom_no, bom_data, to_produce_qty, company, indent=0):
"""
Recursively collects sub-assembly item BOM data for a given 'parent' BOM (`bom_no`)
"""
data = get_bom_children(parent=bom_no)
for d in data:
if d.expandable:
parent_item_code = frappe.get_cached_value("BOM", bom_no, "item")
stock_qty = (d.stock_qty / d.parent_bom_qty) * flt(to_produce_qty)

bom_data.append(
frappe._dict(
{
"parent_item_code": parent_item_code,
"production_item": d.item_code,
"bom_no": d.value,
"is_sub_contracted_item": d.is_sub_contracted_item,
"bom_level": indent,
"indent": indent,
}
)
)

if d.value:
get_sub_assembly_items(d.value, bom_data, stock_qty, company, indent=indent + 1)


@frappe.whitelist()
def make_stock_entry(work_order_id, purpose, qty=None):
se = _make_stock_entry(work_order_id, purpose, qty)
Expand Down
Empty file.
Empty file.
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
// Copyright (c) 2024, AgriTheory and contributors
// For license information, please see license.txt
/* eslint-disable */

frappe.query_reports['Manufacturing Capacity'] = {
filters: [
{
fieldname: 'bom',
label: __('BOM'),
fieldtype: 'Link',
options: 'BOM',
reqd: 1,
},
{
fieldname: 'warehouse',
label: __('Warehouse'),
fieldtype: 'Link',
options: 'Warehouse',
reqd: 1,
},
],
formatter: function (value, row, column, data, default_formatter) {
value = default_formatter(value, row, column, data)

if (data && data.is_selected_bom) {
value = value.bold()
}
return value
},
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
{
"add_total_row": 0,
"columns": [],
"creation": "2024-02-16 12:17:16.951700",
"disable_prepared_report": 0,
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"modified": "2024-02-16 12:17:16.951700",
"modified_by": "Administrator",
"module": "Inventory Tools",
"name": "Manufacturing Capacity",
"owner": "Administrator",
"prepared_report": 0,
"query": "",
"ref_doctype": "BOM",
"report_name": "Manufacturing Capacity",
"report_type": "Script Report",
"roles": [
{
"role": "Manufacturing Manager"
},
{
"role": "Manufacturing User"
}
]
}
Loading

0 comments on commit 2936cde

Please sign in to comment.