diff --git a/erpnext/__init__.py b/erpnext/__init__.py index b9e3cfcaf7..83c6069e52 100644 --- a/erpnext/__init__.py +++ b/erpnext/__init__.py @@ -5,7 +5,7 @@ import frappe from erpnext.hooks import regional_overrides from frappe.utils import getdate -__version__ = '10.1.36' +__version__ = '10.1.37' def get_default_company(user=None): '''Get default company for user''' diff --git a/erpnext/controllers/buying_controller.py b/erpnext/controllers/buying_controller.py index bbe1a1288d..c1df2b5b79 100644 --- a/erpnext/controllers/buying_controller.py +++ b/erpnext/controllers/buying_controller.py @@ -38,6 +38,7 @@ class BuyingController(StockController): if getattr(self, "supplier", None) and not self.supplier_name: self.supplier_name = frappe.db.get_value("Supplier", self.supplier, "supplier_name") + self.validate_items() self.set_qty_as_per_stock_uom() self.validate_stock_or_nonstock_items() self.validate_warehouse() @@ -660,6 +661,14 @@ class BuyingController(StockController): else: frappe.throw(_("Please enter Reqd by Date")) + def validate_items(self): + # validate items to see if they have is_purchase_item or is_subcontracted_item enabled + + if hasattr(self, "is_subcontracted") and self.is_subcontracted == 'Yes': + validate_item_type(self, "is_sub_contracted_item", "subcontracted") + else: + validate_item_type(self, "is_purchase_item", "purchase") + def get_items_from_bom(item_code, bom, exploded_item=1): doctype = "BOM Item" if not exploded_item else "BOM Explosion Item" @@ -709,3 +718,24 @@ def get_asset_item_details(asset_items): asset_items_data.setdefault(d.name, d) return asset_items_data + +def validate_item_type(doc, fieldname, message): + # iterate through items and check if they are valid sales or purchase items + items = [d.item_code for d in doc.items if d.item_code] + + # No validation check inase of creating transaction using 'Opening Invoice Creation Tool' + if not items: + return + + item_list = ", ".join(["'%s'" % frappe.db.escape(d) for d in items]) + + invalid_items = [d[0] for d in frappe.db.sql(""" + select item_code from tabItem where name in ({0}) and {1}=0 + """.format(item_list, fieldname), as_list=True)] + + if invalid_items: + frappe.throw(_("Following item {items} {verb} not marked as {message} item.\ + You can enable them as {message} item from its Item master".format( + items = ", ".join([d for d in invalid_items]), + verb = "are" if len(invalid_items) > 1 else "is", + message = message))) diff --git a/erpnext/controllers/selling_controller.py b/erpnext/controllers/selling_controller.py index 4a358a42f5..1fcd11dd60 100644 --- a/erpnext/controllers/selling_controller.py +++ b/erpnext/controllers/selling_controller.py @@ -35,6 +35,7 @@ class SellingController(StockController): def validate(self): super(SellingController, self).validate() + self.validate_items() self.validate_max_discount() self.validate_selling_price() self.set_qty_as_per_stock_uom() @@ -337,6 +338,11 @@ class SellingController(StockController): po_nos = frappe.get_all('Sales Order', 'po_no', filters = {'name': ('in', sales_orders)}) self.po_no = ', '.join(list(set([d.po_no for d in po_nos if d.po_no]))) + def validate_items(self): + # validate items to see if they have is_sales_item enabled + from erpnext.controllers.buying_controller import validate_item_type + validate_item_type(self, "is_sales_item", "sales") + def check_active_sales_items(obj): for d in obj.get("items"): if d.item_code: diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index 3a4d3609ba..801a0ef5fa 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -41,8 +41,9 @@ class ExpenseClaim(AccountsController): }[cstr(self.docstatus or 0)] paid_amount = flt(self.total_amount_reimbursed) + flt(self.total_advance_amount) + precision = self.precision("total_sanctioned_amount") if (self.is_paid or (flt(self.total_sanctioned_amount) > 0 - and flt(self.total_sanctioned_amount) == paid_amount)) \ + and flt(self.total_sanctioned_amount, precision) == flt(paid_amount, precision))) \ and self.docstatus == 1 and self.approval_status == 'Approved': self.status = "Paid" elif flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and self.approval_status == 'Approved': diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 5480aed559..378a8033bb 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -170,21 +170,25 @@ erpnext.utils.validate_mandatory = function(frm, label, value, trigger_on) { } erpnext.utils.get_shipping_address = function(frm, callback){ - frappe.call({ - method: "frappe.contacts.doctype.address.address.get_shipping_address", - args: { - company: frm.doc.company, - address: frm.doc.shipping_address - }, - callback: function(r){ - if(r.message){ - frm.set_value("shipping_address", r.message[0]) //Address title or name - frm.set_value("shipping_address_display", r.message[1]) //Address to be displayed on the page - } + if (frm.doc.company) { + frappe.call({ + method: "frappe.contacts.doctype.address.address.get_shipping_address", + args: { + company: frm.doc.company, + address: frm.doc.shipping_address + }, + callback: function(r){ + if(r.message){ + frm.set_value("shipping_address", r.message[0]) //Address title or name + frm.set_value("shipping_address_display", r.message[1]) //Address to be displayed on the page + } - if(callback){ - return callback(); + if(callback){ + return callback(); + } } - } - }); + }); + } else { + frappe.msgprint(__("Select company first")); + } } \ No newline at end of file diff --git a/erpnext/selling/doctype/customer/customer.py b/erpnext/selling/doctype/customer/customer.py index 5a95b55d65..b5961a9ab8 100644 --- a/erpnext/selling/doctype/customer/customer.py +++ b/erpnext/selling/doctype/customer/customer.py @@ -76,7 +76,7 @@ class Customer(TransactionBase): def update_customer_groups(self): ignore_doctypes = ["Lead", "Opportunity", "POS Profile", "Tax Rule", "Pricing Rule"] if frappe.flags.customer_group_changed: - update_linked_doctypes('Customer', self.name, 'Customer Group', + update_linked_doctypes('Customer', frappe.db.escape(self.name), 'Customer Group', self.customer_group, ignore_doctypes) def create_primary_contact(self): diff --git a/erpnext/setup/doctype/authorization_control/authorization_control.py b/erpnext/setup/doctype/authorization_control/authorization_control.py index 7d5e80b8f2..2240e0c28b 100644 --- a/erpnext/setup/doctype/authorization_control/authorization_control.py +++ b/erpnext/setup/doctype/authorization_control/authorization_control.py @@ -40,7 +40,7 @@ class AuthorizationControl(TransactionBase): chk = 1 add_cond1,add_cond2 = '','' if based_on == 'Itemwise Discount': - add_cond1 += " and master_name = '"+cstr(item).replace("'", "\\'")+"'" + add_cond1 += " and master_name = '"+cstr(frappe.db.escape(item)).replace("'", "\\'")+"'" itemwise_exists = frappe.db.sql("""select value from `tabAuthorization Rule` where transaction = %s and value <= %s and based_on = %s and company = %s and docstatus != 2 %s %s""" % diff --git a/erpnext/stock/doctype/packing_slip_item/packing_slip_item.json b/erpnext/stock/doctype/packing_slip_item/packing_slip_item.json index 1b22f13891..29c4193f9e 100644 --- a/erpnext/stock/doctype/packing_slip_item/packing_slip_item.json +++ b/erpnext/stock/doctype/packing_slip_item/packing_slip_item.json @@ -88,6 +88,7 @@ "label": "Item Name", "length": 0, "no_copy": 0, + "options": "item_code.item_name", "permlevel": 0, "print_hide": 0, "print_hide_if_no_value": 0, @@ -435,7 +436,7 @@ "issingle": 0, "istable": 1, "max_attachments": 0, - "modified": "2017-02-20 13:30:26.818408", + "modified": "2018-06-01 07:21:58.220980", "modified_by": "Administrator", "module": "Stock", "name": "Packing Slip Item",