Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,7 @@ repos:
additional_dependencies: ['flake8-bugbear']

- repo: https://github.com/agritheory/test_utils
rev: v1.20.3
rev: v1.25.1
hooks:
- id: update_pre_commit_config
- id: validate_frappe_project
Expand Down
31 changes: 31 additions & 0 deletions inventory_tools/docs/uom_conversion_semantics.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
<!-- Copyright (c) 2026, AgriTheory and contributors
For license information, please see license.txt-->

# UOM conversion semantics (Inventory Tools)

## Purpose

ERPNext **[UOM Conversion Factor](https://docs.erpnext.com/)** requires a numeric **Value**. Some real-world ratios (for example pallet vs weight) are intentionally **not** a single global constant. Inventory Tools adds **Conversion basis (Inventory Tools)** (`it_conversion_basis`) on **UOM Conversion Factor**:

| Value stored | Meaning for strict tooling |
| --- | --- |
| unset / empty | Same as **fixed** (backward compatible default). |
| **fixed** | Row participates in naive fixed-ratio / ambiguity suspicion. |
| **contextual** | Row is intentionally non-universal; suspicion reports should **skip** naive 1:1 / fixed-ratio checks for this row or show an informational “marked variable” state. |

## What this does **not** change

- **`get_uom_conv_factor`** and core stock qty resolution continue to use the numeric **Value** when a row matches. **`contextual` is metadata for Inventory Tools tooling**, not a change to ERPNext resolver behavior.
- For item-specific ratios, rely on **[Item UOM Conversion Detail](https://docs.erpnext.com/)** and transaction-level UOMs as ERPNext intends.

## Python helpers

Module `inventory_tools.inventory_tools.uom_conversion_semantics` (`inventory_tools/inventory_tools/uom_conversion_semantics.py`) exposes:

- `is_contextual_conversion_factor(doc)` — carve-out predicate.
- `participates_in_strict_conversion_checks(doc)` — inverse for validators.
- `qb_uom_conversion_factor_strict_rows(ucf)` / `qb_uom_conversion_factor_contextual_rows(ucf)` — Query Builder filters for reports.

## UX copy (future reports)

When listing excluded contextual rows, prefer short notes such as: **“Marked contextual — global factor not validated”** or **“Intentionally variable (per item/shipment); not checked for fixed ratio.”**
47 changes: 47 additions & 0 deletions inventory_tools/inventory_tools/custom/uom_conversion_factor.json
Original file line number Diff line number Diff line change
@@ -0,0 +1,47 @@
{
"custom_fields": [
{
"allow_in_quick_entry": 0,
"allow_on_submit": 0,
"bold": 0,
"collapsible": 0,
"columns": 0,
"default": "fixed",
"description": "Fixed: global scalar is meaningful for strict ambiguity checks. Contextual: relationship is SKU- or shipment-dependent; strict/suspicion tooling should skip naive fixed-ratio assumptions (ERPNext qty resolution unchanged—use Item UOM Conversion Detail where needed).",
"dt": "UOM Conversion Factor",
"fetch_if_empty": 0,
"fieldname": "it_conversion_basis",
"fieldtype": "Select",
"hidden": 0,
"hide_border": 0,
"hide_days": 0,
"hide_seconds": 0,
"ignore_user_permissions": 0,
"ignore_xss_filter": 0,
"in_global_search": 0,
"in_list_view": 1,
"in_preview": 0,
"in_standard_filter": 1,
"insert_after": "value",
"is_system_generated": 0,
"is_virtual": 0,
"label": "Conversion basis (Inventory Tools)",
"length": 0,
"module": "Inventory Tools",
"name": "UOM Conversion Factor-it_conversion_basis",
"no_copy": 0,
"non_negative": 0,
"options": "\nfixed\ncontextual",
"permlevel": 0,
"print_hide": 0,
"print_hide_if_no_value": 0,
"read_only": 0,
"report_hide": 0,
"reqd": 0,
"search_index": 0,
"sort_options": 0,
"translatable": 0,
"unique": 0
}
]
}
2 changes: 1 addition & 1 deletion inventory_tools/inventory_tools/overrides/stock_entry.py
Original file line number Diff line number Diff line change
Expand Up @@ -183,7 +183,7 @@ def get_pending_raw_materials(self, backflush_based_on=None):
@frappe.whitelist()
def get_items(self):
"""
HASH: 279cf6fe007528f624f8f1e5ef7d169124584756
HASH: 4dd9f0b25545a034ae3cc2012dc5a1049449c5b7
REPO: https://github.com/frappe/erpnext/
PATH: erpnext/stock/doctype/stock_entry/stock_entry.py
METHOD: get_items
Expand Down
2 changes: 1 addition & 1 deletion inventory_tools/inventory_tools/overrides/work_order.py
Original file line number Diff line number Diff line change
Expand Up @@ -17,7 +17,7 @@
class InventoryToolsWorkOrder(WorkOrder):
def onload(self):
"""
HASH: 46a2b7a07e5326ad5fde89d030460a5e9f2b67b0
HASH: 4dd9f0b25545a034ae3cc2012dc5a1049449c5b7
REPO: https://github.com/frappe/erpnext/
PATH: erpnext/manufacturing/doctype/work_order/work_order.py
METHOD: onload
Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# Copyright (c) 2026, AgriTheory and contributors
# For license information, please see license.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,48 @@
// Copyright (c) 2026, AgriTheory and contributors
// For license information, please see license.txt

frappe.query_reports['UOM Conversion Exceptions'] = {
filters: [
{
fieldname: 'company',
label: __('Company'),
fieldtype: 'Link',
options: 'Company',
default: frappe.defaults.get_default('company'),
},
{
fieldname: 'from_date',
label: __('From Date'),
fieldtype: 'Date',
},
{
fieldname: 'to_date',
label: __('To Date'),
fieldtype: 'Date',
},
{
fieldname: 'uom',
label: __('UOM'),
fieldtype: 'MultiSelectList',
options: 'UOM',
get_data: function (txt) {
return frappe.db.get_link_options('UOM', txt)
},
},
{
fieldname: 'uom_category',
label: __('UOM Category'),
fieldtype: 'MultiSelectList',
options: 'UOM Category',
get_data: function (txt) {
return frappe
.call({
method: 'inventory_tools.inventory_tools.uom_conversion_exceptions.category_filter_multiselect_data',
args: { txt: txt || '' },
type: 'POST',
})
.then(r => r.message || [])
},
},
],
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,46 @@
{
"actions": [],
"add_total_row": 0,
"add_translate_data": 1,
"creation": "2026-05-01 12:00:00",
"disabled": 0,
"docstatus": 0,
"doctype": "Report",
"filters": [],
"idx": 0,
"is_standard": "Yes",
"letterhead": null,
"modified": "2026-05-01 12:00:00",
"modified_by": "Administrator",
"module": "Inventory Tools",
"name": "UOM Conversion Exceptions",
"owner": "Administrator",
"prepared_report": 0,
"ref_doctype": "Item",
"report_name": "UOM Conversion Exceptions",
"report_type": "Script Report",
"roles": [
{
"role": "Stock Manager"
},
{
"role": "Stock User"
},
{
"role": "Item Manager"
},
{
"role": "Purchase Manager"
},
{
"role": "Purchase User"
},
{
"role": "Sales User"
},
{
"role": "System Manager"
}
],
"timeout": 0
}
Loading
Loading