feat: company wise default warehouses

This commit is contained in:
Mihir Kandoi
2025-11-13 12:51:07 +05:30
parent 9b303a2272
commit 84af60da7f
15 changed files with 70 additions and 65 deletions

View File

@@ -1085,7 +1085,7 @@ class JobCard(Document):
def set_wip_warehouse(self): def set_wip_warehouse(self):
if not self.wip_warehouse: if not self.wip_warehouse:
self.wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse") self.wip_warehouse = frappe.get_cached_value("Company", self.company, "default_wip_warehouse")
def validate_operation_id(self): def validate_operation_id(self):
if ( if (

View File

@@ -18,18 +18,6 @@ frappe.tour["Manufacturing Settings"] = [
"The Stock Entry of type 'Manufacture' is known as backflush. Raw materials being consumed to manufacture finished goods is known as backflushing. <br><br> When creating Manufacture Entry, raw-material items are backflushed based on BOM of production item. If you want raw-material items to be backflushed based on Material Transfer entry made against that Work Order instead, then you can set it under this field." "The Stock Entry of type 'Manufacture' is known as backflush. Raw materials being consumed to manufacture finished goods is known as backflushing. <br><br> When creating Manufacture Entry, raw-material items are backflushed based on BOM of production item. If you want raw-material items to be backflushed based on Material Transfer entry made against that Work Order instead, then you can set it under this field."
), ),
}, },
{
fieldname: "default_wip_warehouse",
title: __("Work In Progress Warehouse"),
description: __(
"This Warehouse will be auto-updated in the Work In Progress Warehouse field of Work Orders."
),
},
{
fieldname: "default_fg_warehouse",
title: __("Finished Goods Warehouse"),
description: __("This Warehouse will be auto-updated in the Target Warehouse field of Work Order."),
},
{ {
fieldname: "update_bom_costs_automatically", fieldname: "update_bom_costs_automatically",
title: __("Update BOM Cost Automatically"), title: __("Update BOM Cost Automatically"),

View File

@@ -16,11 +16,6 @@
"update_bom_costs_automatically", "update_bom_costs_automatically",
"column_break_lhyt", "column_break_lhyt",
"allow_editing_of_items_and_quantities_in_work_order", "allow_editing_of_items_and_quantities_in_work_order",
"section_break_6",
"default_wip_warehouse",
"default_fg_warehouse",
"column_break_11",
"default_scrap_warehouse",
"over_production_for_sales_and_work_order_section", "over_production_for_sales_and_work_order_section",
"overproduction_percentage_for_sales_order", "overproduction_percentage_for_sales_order",
"column_break_16", "column_break_16",
@@ -86,11 +81,6 @@
"fieldtype": "Int", "fieldtype": "Int",
"label": "Time Between Operations (Mins)" "label": "Time Between Operations (Mins)"
}, },
{
"fieldname": "section_break_6",
"fieldtype": "Section Break",
"label": "Default Warehouses for Production"
},
{ {
"fieldname": "overproduction_percentage_for_sales_order", "fieldname": "overproduction_percentage_for_sales_order",
"fieldtype": "Percent", "fieldtype": "Percent",
@@ -122,34 +112,12 @@
"fieldtype": "Check", "fieldtype": "Check",
"label": "Update BOM Cost Automatically" "label": "Update BOM Cost Automatically"
}, },
{
"fieldname": "column_break_11",
"fieldtype": "Column Break"
},
{
"fieldname": "default_wip_warehouse",
"fieldtype": "Link",
"label": "Default Work In Progress Warehouse",
"options": "Warehouse"
},
{
"fieldname": "default_fg_warehouse",
"fieldtype": "Link",
"label": "Default Finished Goods Warehouse",
"options": "Warehouse"
},
{ {
"default": "0", "default": "0",
"fieldname": "disable_capacity_planning", "fieldname": "disable_capacity_planning",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Disable Capacity Planning" "label": "Disable Capacity Planning"
}, },
{
"fieldname": "default_scrap_warehouse",
"fieldtype": "Link",
"label": "Default Scrap Warehouse",
"options": "Warehouse"
},
{ {
"fieldname": "over_production_for_sales_and_work_order_section", "fieldname": "over_production_for_sales_and_work_order_section",
"fieldtype": "Section Break", "fieldtype": "Section Break",
@@ -275,7 +243,7 @@
"index_web_pages_for_search": 1, "index_web_pages_for_search": 1,
"issingle": 1, "issingle": 1,
"links": [], "links": [],
"modified": "2025-11-07 14:52:56.241459", "modified": "2025-11-13 12:30:29.006822",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Manufacturing", "module": "Manufacturing",
"name": "Manufacturing Settings", "name": "Manufacturing Settings",

View File

@@ -23,9 +23,6 @@ class ManufacturingSettings(Document):
allow_production_on_holidays: DF.Check allow_production_on_holidays: DF.Check
backflush_raw_materials_based_on: DF.Literal["BOM", "Material Transferred for Manufacture"] backflush_raw_materials_based_on: DF.Literal["BOM", "Material Transferred for Manufacture"]
capacity_planning_for_days: DF.Int capacity_planning_for_days: DF.Int
default_fg_warehouse: DF.Link | None
default_scrap_warehouse: DF.Link | None
default_wip_warehouse: DF.Link | None
disable_capacity_planning: DF.Check disable_capacity_planning: DF.Check
enforce_time_logs: DF.Check enforce_time_logs: DF.Check
get_rm_cost_from_consumption_entry: DF.Check get_rm_cost_from_consumption_entry: DF.Check

View File

@@ -756,7 +756,7 @@ class ProductionPlan(Document):
wo_list, po_list = [], [] wo_list, po_list = [], []
subcontracted_po = {} subcontracted_po = {}
default_warehouses = get_default_warehouse() default_warehouses = get_default_warehouse(self.company)
self.make_work_order_for_finished_goods(wo_list, default_warehouses) self.make_work_order_for_finished_goods(wo_list, default_warehouses)
self.make_work_order_for_subassembly_items(wo_list, subcontracted_po, default_warehouses) self.make_work_order_for_subassembly_items(wo_list, subcontracted_po, default_warehouses)

View File

@@ -932,6 +932,9 @@ erpnext.work_order = {
if (!(frm.doc.wip_warehouse || frm.doc.fg_warehouse)) { if (!(frm.doc.wip_warehouse || frm.doc.fg_warehouse)) {
frappe.call({ frappe.call({
method: "erpnext.manufacturing.doctype.work_order.work_order.get_default_warehouse", method: "erpnext.manufacturing.doctype.work_order.work_order.get_default_warehouse",
args: {
company: frm.doc.company,
},
callback: function (r) { callback: function (r) {
if (!r.exe) { if (!r.exe) {
frm.set_value("wip_warehouse", r.message.wip_warehouse); frm.set_value("wip_warehouse", r.message.wip_warehouse);

View File

@@ -453,9 +453,9 @@ class WorkOrder(Document):
def set_default_warehouse(self): def set_default_warehouse(self):
if not self.wip_warehouse and not self.skip_transfer: if not self.wip_warehouse and not self.skip_transfer:
self.wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse") self.wip_warehouse = frappe.get_cached_value("Company", self.company, "default_wip_warehouse")
if not self.fg_warehouse: if not self.fg_warehouse:
self.fg_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_fg_warehouse") self.fg_warehouse = frappe.get_cached_value("Company", self.company, "default_fg_warehouse")
def check_wip_warehouse_skip(self): def check_wip_warehouse_skip(self):
if self.skip_transfer and not self.from_wip_warehouse: if self.skip_transfer and not self.from_wip_warehouse:
@@ -2318,13 +2318,14 @@ def make_stock_entry(
@frappe.whitelist() @frappe.whitelist()
def get_default_warehouse(): def get_default_warehouse(company):
doc = frappe.get_cached_doc("Manufacturing Settings") wip, fg, scrap = frappe.get_cached_value(
"Company", company, ["default_wip_warehouse", "default_fg_warehouse", "default_scrap_warehouse"]
)
return { return {
"wip_warehouse": doc.default_wip_warehouse, "wip_warehouse": wip,
"fg_warehouse": doc.default_fg_warehouse, "fg_warehouse": fg,
"scrap_warehouse": doc.default_scrap_warehouse, "scrap_warehouse": scrap,
} }

View File

@@ -446,3 +446,4 @@ erpnext.patches.v16_0.add_new_stock_entry_types
erpnext.patches.v15_0.set_asset_status_if_not_already_set erpnext.patches.v15_0.set_asset_status_if_not_already_set
erpnext.patches.v15_0.toggle_legacy_controller_for_period_closing erpnext.patches.v15_0.toggle_legacy_controller_for_period_closing
erpnext.patches.v16_0.update_serial_batch_entries erpnext.patches.v16_0.update_serial_batch_entries
erpnext.patches.v16_0.set_company_wise_warehouses

View File

@@ -0,0 +1,14 @@
import frappe
def execute():
warehouses = frappe.get_single_value(
"Manufacturing Settings",
["default_wip_warehouse", "default_fg_warehouse", "default_scrap_warehouse"],
as_dict=True,
)
for name, warehouse in warehouses.items():
if warehouse:
company = frappe.get_value("Warehouse", warehouse, "company")
frappe.db.set_value("Company", company, name, warehouse)

View File

@@ -1796,7 +1796,7 @@ class TestSalesOrder(AccountsTestMixin, IntegrationTestCase):
mr.submit() mr.submit()
# WO from MR # WO from MR
wo_name = raise_work_orders(mr.name)[0] wo_name = raise_work_orders(mr.name, mr.company)[0]
wo = frappe.get_doc("Work Order", wo_name) wo = frappe.get_doc("Work Order", wo_name)
wo.wip_warehouse = "Work In Progress - _TC" wo.wip_warehouse = "Work In Progress - _TC"
wo.skip_transfer = True wo.skip_transfer = True

View File

@@ -124,6 +124,10 @@
"default_in_transit_warehouse", "default_in_transit_warehouse",
"manufacturing_section", "manufacturing_section",
"default_operating_cost_account", "default_operating_cost_account",
"column_break_9prc",
"default_wip_warehouse",
"default_fg_warehouse",
"default_scrap_warehouse",
"dashboard_tab" "dashboard_tab"
], ],
"fields": [ "fields": [
@@ -885,6 +889,31 @@
"fieldname": "enable_item_wise_inventory_account", "fieldname": "enable_item_wise_inventory_account",
"fieldtype": "Check", "fieldtype": "Check",
"label": "Enable Item-wise Inventory Account" "label": "Enable Item-wise Inventory Account"
},
{
"fieldname": "default_wip_warehouse",
"fieldtype": "Link",
"label": " Default Work In Progress Warehouse ",
"link_filters": "[[\"Warehouse\",\"disabled\",\"=\",0]]",
"options": "Warehouse"
},
{
"fieldname": "default_fg_warehouse",
"fieldtype": "Link",
"label": "Default Finished Goods Warehouse",
"link_filters": "[[\"Warehouse\",\"disabled\",\"=\",0]]",
"options": "Warehouse"
},
{
"fieldname": "default_scrap_warehouse",
"fieldtype": "Link",
"label": "Default Scrap Warehouse",
"link_filters": "[[\"Warehouse\",\"disabled\",\"=\",0]]",
"options": "Warehouse"
},
{
"fieldname": "column_break_9prc",
"fieldtype": "Column Break"
} }
], ],
"icon": "fa fa-building", "icon": "fa fa-building",
@@ -892,7 +921,7 @@
"image_field": "company_logo", "image_field": "company_logo",
"is_tree": 1, "is_tree": 1,
"links": [], "links": [],
"modified": "2025-10-23 13:15:52.411984", "modified": "2025-11-16 16:50:27.624096",
"modified_by": "Administrator", "modified_by": "Administrator",
"module": "Setup", "module": "Setup",
"name": "Company", "name": "Company",

View File

@@ -59,6 +59,7 @@ class Company(NestedSet):
default_deferred_revenue_account: DF.Link | None default_deferred_revenue_account: DF.Link | None
default_discount_account: DF.Link | None default_discount_account: DF.Link | None
default_expense_account: DF.Link | None default_expense_account: DF.Link | None
default_fg_warehouse: DF.Link | None
default_finance_book: DF.Link | None default_finance_book: DF.Link | None
default_holiday_list: DF.Link | None default_holiday_list: DF.Link | None
default_in_transit_warehouse: DF.Link | None default_in_transit_warehouse: DF.Link | None
@@ -69,8 +70,10 @@ class Company(NestedSet):
default_payable_account: DF.Link | None default_payable_account: DF.Link | None
default_provisional_account: DF.Link | None default_provisional_account: DF.Link | None
default_receivable_account: DF.Link | None default_receivable_account: DF.Link | None
default_scrap_warehouse: DF.Link | None
default_selling_terms: DF.Link | None default_selling_terms: DF.Link | None
default_warehouse_for_sales_return: DF.Link | None default_warehouse_for_sales_return: DF.Link | None
default_wip_warehouse: DF.Link | None
depreciation_cost_center: DF.Link | None depreciation_cost_center: DF.Link | None
depreciation_expense_account: DF.Link | None depreciation_expense_account: DF.Link | None
disposal_account: DF.Link | None disposal_account: DF.Link | None

View File

@@ -495,6 +495,7 @@ frappe.ui.form.on("Material Request", {
method: "erpnext.stock.doctype.material_request.material_request.raise_work_orders", method: "erpnext.stock.doctype.material_request.material_request.raise_work_orders",
args: { args: {
material_request: frm.doc.name, material_request: frm.doc.name,
company: frm.doc.company,
}, },
freeze: true, freeze: true,
callback: function (r) { callback: function (r) {

View File

@@ -833,11 +833,11 @@ def make_stock_entry(source_name, target_doc=None):
@frappe.whitelist() @frappe.whitelist()
def raise_work_orders(material_request): def raise_work_orders(material_request, company):
mr = frappe.get_doc("Material Request", material_request) mr = frappe.get_doc("Material Request", material_request)
errors = [] errors = []
work_orders = [] work_orders = []
default_wip_warehouse = frappe.db.get_single_value("Manufacturing Settings", "default_wip_warehouse") default_wip_warehouse = frappe.get_cached_value("Company", company, "default_wip_warehouse")
for d in mr.items: for d in mr.items:
if (d.stock_qty - d.ordered_qty) > 0: if (d.stock_qty - d.ordered_qty) > 0:

View File

@@ -747,7 +747,7 @@ class TestMaterialRequest(IntegrationTestCase):
(mr.items[0].item_code, mr.items[0].warehouse), (mr.items[0].item_code, mr.items[0].warehouse),
)[0][0] )[0][0]
prod_order = raise_work_orders(mr.name) prod_order = raise_work_orders(mr.name, mr.company)
po = frappe.get_doc("Work Order", prod_order[0]) po = frappe.get_doc("Work Order", prod_order[0])
po.wip_warehouse = "_Test Warehouse 1 - _TC" po.wip_warehouse = "_Test Warehouse 1 - _TC"
po.submit() po.submit()
@@ -789,7 +789,7 @@ class TestMaterialRequest(IntegrationTestCase):
self.assertEqual(requested_qty, existing_requested_qty + 120) self.assertEqual(requested_qty, existing_requested_qty + 120)
work_order = raise_work_orders(mr.name) work_order = raise_work_orders(mr.name, mr.company)
wo = frappe.get_doc("Work Order", work_order[0]) wo = frappe.get_doc("Work Order", work_order[0])
wo.qty = 50 wo.qty = 50
wo.wip_warehouse = "_Test Warehouse 1 - _TC" wo.wip_warehouse = "_Test Warehouse 1 - _TC"
@@ -924,7 +924,7 @@ class TestMaterialRequest(IntegrationTestCase):
item_code="_Test FG Item", material_request_type="Manufacture", do_not_submit=False item_code="_Test FG Item", material_request_type="Manufacture", do_not_submit=False
) )
work_order = raise_work_orders(mr.name) work_order = raise_work_orders(mr.name, mr.company)
wo = frappe.get_doc("Work Order", work_order[0]) wo = frappe.get_doc("Work Order", work_order[0])
wo.wip_warehouse = "_Test Warehouse 1 - _TC" wo.wip_warehouse = "_Test Warehouse 1 - _TC"
wo.submit() wo.submit()