From 9a73b7a3194109dacbd3906bec288f38f35d2993 Mon Sep 17 00:00:00 2001 From: Neil Trini Lasrado Date: Fri, 7 Aug 2015 16:40:12 +0530 Subject: [PATCH] Changed UOM validation for Item Master --- erpnext/stock/doctype/item/item.py | 69 +++++---- .../stock_uom_replace_utility.py | 136 +++++++++--------- 2 files changed, 109 insertions(+), 96 deletions(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 089c067bf6..eaf904d1a8 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -48,7 +48,7 @@ class Item(WebsiteGenerator): self.website_image = self.image self.check_warehouse_is_set_for_stock_item() - self.check_stock_uom_with_bin() + self.validate_uom() self.add_default_uom_in_conversion_factor_table() self.validate_conversion_factor() self.validate_item_type() @@ -105,35 +105,6 @@ class Item(WebsiteGenerator): [self.remove(d) for d in to_remove] - - def check_stock_uom_with_bin(self): - if not self.get("__islocal"): - if self.stock_uom == frappe.db.get_value("Item", self.name, "stock_uom"): - return - - matched=True - ref_uom = frappe.db.get_value("Stock Ledger Entry", - {"item_code": self.name}, "stock_uom") - - if ref_uom: - if cstr(ref_uom) != cstr(self.stock_uom): - matched = False - else: - bin_list = frappe.db.sql("select * from tabBin where item_code=%s", - self.item_code, as_dict=1) - for bin in bin_list: - if (bin.reserved_qty > 0 or bin.ordered_qty > 0 or bin.indented_qty > 0 \ - or bin.planned_qty > 0) and cstr(bin.stock_uom) != cstr(self.stock_uom): - matched = False - break - - if matched and bin_list: - frappe.db.sql("""update tabBin set stock_uom=%s where item_code=%s""", - (self.stock_uom, self.name)) - - if not matched: - frappe.throw(_("Default Unit of Measure for Item {0} cannot be changed directly because you have already made some transaction(s) with another UOM. To change default UOM, use 'UOM Replace Utility' tool under Stock module.").format(self.name)) - def update_template_tables(self): template = frappe.get_doc("Item", self.variant_of) @@ -344,6 +315,17 @@ class Item(WebsiteGenerator): or ifnull(reserved_qty, 0) > 0 or ifnull(indented_qty, 0) > 0 or ifnull(planned_qty, 0) > 0)""", self.name) if stock_in: frappe.throw(_("Item Template cannot have stock or Open Sales/Purchase/Production Orders."), ItemTemplateCannotHaveStock) + + def validate_uom(self): + if not self.get("__islocal"): + check_stock_uom_with_bin(self.name, self.stock_uom) + if self.has_variants: + for d in frappe.db.get_all("Item", filters= {"variant_of": self.name}): + check_stock_uom_with_bin(d.name, self.stock_uom) + if self.variant_of: + template_uom = frappe.db.get_value("Item", self.variant_of, "stock_uom") + if template_uom != self.stock_uom: + frappe.throw(_("Default Unit of Measure for Variant must be same as Template")) def validate_end_of_life(item_code, end_of_life=None, verbose=1): if not end_of_life: @@ -449,3 +431,30 @@ def invalidate_cache_for_item(doc): if doc.get("old_item_group") and doc.get("old_item_group") != doc.item_group: invalidate_cache_for(doc, doc.old_item_group) + +def check_stock_uom_with_bin(item, stock_uom): + if stock_uom == frappe.db.get_value("Item", item, "stock_uom"): + return + + matched=True + ref_uom = frappe.db.get_value("Stock Ledger Entry", + {"item_code": item}, "stock_uom") + + if ref_uom: + if cstr(ref_uom) != cstr(stock_uom): + matched = False + else: + bin_list = frappe.db.sql("select * from tabBin where item_code=%s", item, as_dict=1) + for bin in bin_list: + if (bin.reserved_qty > 0 or bin.ordered_qty > 0 or bin.indented_qty > 0 \ + or bin.planned_qty > 0) and cstr(bin.stock_uom) != cstr(stock_uom): + matched = False + break + + if matched and bin_list: + frappe.db.sql("""update tabBin set stock_uom=%s where item_code=%s""", (stock_uom, item)) + + if not matched: + frappe.throw(_("Default Unit of Measure for Item {0} cannot be changed directly because \ + you have already made some transaction(s) with another UOM. To change default UOM, \ + use 'UOM Replace Utility' tool under Stock module.").format(item)) diff --git a/erpnext/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py b/erpnext/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py index c3f530a2c2..5b5419dc59 100644 --- a/erpnext/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py +++ b/erpnext/stock/doctype/stock_uom_replace_utility/stock_uom_replace_utility.py @@ -10,6 +10,28 @@ from frappe import _ from frappe.model.document import Document class StockUOMReplaceUtility(Document): + + # Update Stock UOM + def update_stock_uom(self): + self.validate_item() + self.validate_mandatory() + self.validate_uom_integer_type() + + update_stock_ledger_entry(self.item_code, self.new_stock_uom, self.conversion_factor) + update_bin(self.item_code, self.new_stock_uom, self.conversion_factor) + update_item_master(self.item_code, self.new_stock_uom, self.conversion_factor) + + #if item is template change UOM for all associated variants + if frappe.db.get_value("Item", self.item_code, "has_variants"): + for d in frappe.db.get_all("Item", filters= {"variant_of": self.item_code}): + update_stock_ledger_entry(d.name, self.new_stock_uom, self.conversion_factor) + update_bin(d.name, self.new_stock_uom, self.conversion_factor) + update_item_master(d.name, self.new_stock_uom, self.conversion_factor) + + def validate_item(self): + if frappe.db.get_value("Item", self.item_code, "variant_of"): + frappe.throw(_("You cannot change default UOM of Variant. To change default UOM for Variant change default UOM of the Template")) + def validate_mandatory(self): if not cstr(self.item_code): frappe.throw(_("Item is required")) @@ -27,72 +49,7 @@ class StockUOMReplaceUtility(Document): stock_uom = frappe.db.get_value("Item", self.item_code, "stock_uom") if cstr(self.new_stock_uom) == cstr(stock_uom): frappe.throw(_("Item is updated")) - - def update_item_master(self): - item_doc = frappe.get_doc("Item", self.item_code) - item_doc.stock_uom = self.new_stock_uom - item_doc.save() - - frappe.msgprint(_("Stock UOM updated for Item {0}").format(self.item_code)) - - def update_bin(self): - # update bin - if flt(self.conversion_factor) != flt(1): - frappe.db.sql("""update `tabBin` - set stock_uom = %s, - indented_qty = ifnull(indented_qty,0) * %s, - ordered_qty = ifnull(ordered_qty,0) * %s, - reserved_qty = ifnull(reserved_qty,0) * %s, - planned_qty = ifnull(planned_qty,0) * %s, - projected_qty = actual_qty + ordered_qty + indented_qty + - planned_qty - reserved_qty - where item_code = %s""", (self.new_stock_uom, self.conversion_factor, - self.conversion_factor, self.conversion_factor, - self.conversion_factor, self.item_code)) - else: - frappe.db.sql("update `tabBin` set stock_uom = %s where item_code = %s", - (self.new_stock_uom, self.item_code) ) - - # acknowledge user - frappe.msgprint(_("Stock balances updated")) - - def update_stock_ledger_entry(self): - # update stock ledger entry - from erpnext.stock.stock_ledger import update_entries_after - - if flt(self.conversion_factor) != flt(1): - frappe.db.sql("""update `tabStock Ledger Entry` - set stock_uom = %s, actual_qty = ifnull(actual_qty,0) * %s - where item_code = %s""", - (self.new_stock_uom, self.conversion_factor, self.item_code)) - else: - frappe.db.sql("""update `tabStock Ledger Entry` set stock_uom=%s - where item_code=%s""", (self.new_stock_uom, self.item_code)) - - # acknowledge user - frappe.msgprint(_("Stock Ledger entries balances updated")) - - # update item valuation - if flt(self.conversion_factor) != flt(1): - wh = frappe.db.sql("select name from `tabWarehouse`") - for w in wh: - update_entries_after({"item_code": self.item_code, "warehouse": w[0]}) - - # acknowledge user - frappe.msgprint(_("Item valuation updated")) - - # Update Stock UOM - def update_stock_uom(self): - self.validate_mandatory() - self.validate_uom_integer_type() - - self.update_stock_ledger_entry() - - self.update_bin() - - self.update_item_master() - - + def validate_uom_integer_type(self): current_is_integer = frappe.db.get_value("UOM", self.current_stock_uom, "must_be_whole_number") new_is_integer = frappe.db.get_value("UOM", self.new_stock_uom, "must_be_whole_number") @@ -103,6 +60,53 @@ class StockUOMReplaceUtility(Document): if current_is_integer and new_is_integer and cint(self.conversion_factor)!=self.conversion_factor: frappe.throw(_("Conversion factor cannot be in fractions")) +def update_item_master(item_code, new_stock_uom, conversion_factor): + frappe.db.set_value("Item", item_code, "stock_uom", new_stock_uom) + frappe.msgprint(_("Stock UOM updated for Item {0}").format(item_code)) + +def update_bin(item_code, new_stock_uom, conversion_factor): + # update bin + if flt(conversion_factor) != flt(1): + frappe.db.sql("""update `tabBin` + set stock_uom = %s, + indented_qty = ifnull(indented_qty,0) * %s, + ordered_qty = ifnull(ordered_qty,0) * %s, + reserved_qty = ifnull(reserved_qty,0) * %s, + planned_qty = ifnull(planned_qty,0) * %s, + projected_qty = actual_qty + ordered_qty + indented_qty + + planned_qty - reserved_qty + where item_code = %s""", (new_stock_uom, conversion_factor, + conversion_factor, conversion_factor, + conversion_factor, item_code)) + else: + frappe.db.sql("update `tabBin` set stock_uom = %s where item_code = %s", + (new_stock_uom, item_code) ) + +def update_stock_ledger_entry(item_code, new_stock_uom, conversion_factor): + # update stock ledger entry + from erpnext.stock.stock_ledger import update_entries_after + + if flt(conversion_factor) != flt(1): + frappe.db.sql("""update `tabStock Ledger Entry` + set stock_uom = %s, actual_qty = ifnull(actual_qty,0) * %s + where item_code = %s""", + (new_stock_uom, conversion_factor, item_code)) + else: + frappe.db.sql("""update `tabStock Ledger Entry` set stock_uom=%s + where item_code=%s""", (new_stock_uom, item_code)) + + # acknowledge user + frappe.msgprint(_("Stock Ledger entries balances updated")) + + # update item valuation + if flt(conversion_factor) != flt(1): + wh = frappe.db.sql("select name from `tabWarehouse`") + for w in wh: + update_entries_after({"item_code": item_code, "warehouse": w[0]}) + + # acknowledge user + frappe.msgprint(_("Item valuation updated")) + @frappe.whitelist() def get_stock_uom(item_code): return { 'current_stock_uom': cstr(frappe.db.get_value('Item', item_code, 'stock_uom')) }