Merge pull request #3822 from neilLasrado/item-uom

Changed UOM validation for Item Master
This commit is contained in:
Anand Doshi 2015-08-13 14:36:37 +05:30
commit cb4784c940
2 changed files with 109 additions and 96 deletions

View File

@ -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))

View File

@ -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')) }