From bd67e879211002343bf1126325acbdf54b1613b9 Mon Sep 17 00:00:00 2001 From: Anand Doshi Date: Fri, 11 Apr 2014 16:51:27 +0530 Subject: [PATCH] Fixes saving of Sales Order and fetching Prices frappe/frappe#478 --- .../doctype/sales_invoice/sales_invoice.py | 3 +- erpnext/controllers/accounts_controller.py | 2 +- erpnext/controllers/queries.py | 218 +++++++++--------- .../doctype/sales_order/sales_order.py | 2 +- erpnext/selling/sales_common.js | 208 ++++++++--------- erpnext/stock/doctype/item/item.js | 23 +- erpnext/stock/doctype/item/item.py | 2 +- .../stock/doctype/stock_entry/stock_entry.py | 4 +- erpnext/stock/get_item_details.py | 164 ++++++------- 9 files changed, 319 insertions(+), 307 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index fb36484c71..3b09090bbe 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -260,8 +260,7 @@ class SalesInvoice(SellingController): """Validate Fixed Asset and whether Income Account Entered Exists""" for d in self.get('entries'): item = frappe.db.sql("""select name,is_asset_item,is_sales_item from `tabItem` - where name = %s and (ifnull(end_of_life,'')='' or end_of_life = '0000-00-00' - or end_of_life > now())""", d.item_code) + where name = %s and (ifnull(end_of_life,'')='' or end_of_life > now())""", d.item_code) acc = frappe.db.sql("""select account_type from `tabAccount` where name = %s and docstatus != 2""", d.income_account) if not acc: diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index a0eb85dba5..3caed03f35 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -87,7 +87,7 @@ class AccountsController(TransactionBase): """set missing item values""" from erpnext.stock.get_item_details import get_item_details if hasattr(self, "fname"): - parent_dict = {} + parent_dict = {"doctype": self.doctype} for fieldname in self.meta.get_valid_columns(): parent_dict[fieldname] = self.get(fieldname) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index e8cdc80f93..408f434ee0 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -16,47 +16,47 @@ def get_filters_cond(doctype, filters, conditions): flt.append([doctype, f[0], '!=', f[1][1:]]) else: flt.append([doctype, f[0], '=', f[1]]) - + query = DatabaseQuery(doctype) query.filters = flt query.conditions = conditions query.build_filter_conditions() - - cond = ' and ' + ' and '.join(query.conditions) + + cond = ' and ' + ' and '.join(query.conditions) else: cond = '' return cond # searches for active employees def employee_query(doctype, txt, searchfield, start, page_len, filters): - return frappe.db.sql("""select name, employee_name from `tabEmployee` - where status = 'Active' - and docstatus < 2 - and (%(key)s like "%(txt)s" - or employee_name like "%(txt)s") + return frappe.db.sql("""select name, employee_name from `tabEmployee` + where status = 'Active' + and docstatus < 2 + and (%(key)s like "%(txt)s" + or employee_name like "%(txt)s") %(mcond)s - order by - case when name like "%(txt)s" then 0 else 1 end, - case when employee_name like "%(txt)s" then 0 else 1 end, - name - limit %(start)s, %(page_len)s""" % {'key': searchfield, 'txt': "%%%s%%" % txt, + order by + case when name like "%(txt)s" then 0 else 1 end, + case when employee_name like "%(txt)s" then 0 else 1 end, + name + limit %(start)s, %(page_len)s""" % {'key': searchfield, 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len}) # searches for leads which are not converted -def lead_query(doctype, txt, searchfield, start, page_len, filters): +def lead_query(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select name, lead_name, company_name from `tabLead` - where docstatus < 2 - and ifnull(status, '') != 'Converted' - and (%(key)s like "%(txt)s" - or lead_name like "%(txt)s" - or company_name like "%(txt)s") + where docstatus < 2 + and ifnull(status, '') != 'Converted' + and (%(key)s like "%(txt)s" + or lead_name like "%(txt)s" + or company_name like "%(txt)s") %(mcond)s - order by - case when name like "%(txt)s" then 0 else 1 end, - case when lead_name like "%(txt)s" then 0 else 1 end, - case when company_name like "%(txt)s" then 0 else 1 end, - lead_name asc - limit %(start)s, %(page_len)s""" % {'key': searchfield, 'txt': "%%%s%%" % txt, + order by + case when name like "%(txt)s" then 0 else 1 end, + case when lead_name like "%(txt)s" then 0 else 1 end, + case when company_name like "%(txt)s" then 0 else 1 end, + lead_name asc + limit %(start)s, %(page_len)s""" % {'key': searchfield, 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len}) # searches for customer @@ -68,82 +68,82 @@ def customer_query(doctype, txt, searchfield, start, page_len, filters): else: fields = ["name", "customer_name", "customer_group", "territory"] - fields = ", ".join(fields) + fields = ", ".join(fields) - return frappe.db.sql("""select %(field)s from `tabCustomer` - where docstatus < 2 - and (%(key)s like "%(txt)s" - or customer_name like "%(txt)s") + return frappe.db.sql("""select %(field)s from `tabCustomer` + where docstatus < 2 + and (%(key)s like "%(txt)s" + or customer_name like "%(txt)s") %(mcond)s - order by - case when name like "%(txt)s" then 0 else 1 end, - case when customer_name like "%(txt)s" then 0 else 1 end, - name, customer_name - limit %(start)s, %(page_len)s""" % {'field': fields,'key': searchfield, - 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype), + order by + case when name like "%(txt)s" then 0 else 1 end, + case when customer_name like "%(txt)s" then 0 else 1 end, + name, customer_name + limit %(start)s, %(page_len)s""" % {'field': fields,'key': searchfield, + 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len}) # searches for supplier def supplier_query(doctype, txt, searchfield, start, page_len, filters): supp_master_name = frappe.defaults.get_user_default("supp_master_name") - if supp_master_name == "Supplier Name": + if supp_master_name == "Supplier Name": fields = ["name", "supplier_type"] - else: + else: fields = ["name", "supplier_name", "supplier_type"] - fields = ", ".join(fields) + fields = ", ".join(fields) - return frappe.db.sql("""select %(field)s from `tabSupplier` - where docstatus < 2 - and (%(key)s like "%(txt)s" - or supplier_name like "%(txt)s") + return frappe.db.sql("""select %(field)s from `tabSupplier` + where docstatus < 2 + and (%(key)s like "%(txt)s" + or supplier_name like "%(txt)s") %(mcond)s - order by - case when name like "%(txt)s" then 0 else 1 end, - case when supplier_name like "%(txt)s" then 0 else 1 end, - name, supplier_name - limit %(start)s, %(page_len)s """ % {'field': fields,'key': searchfield, - 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype), 'start': start, + order by + case when name like "%(txt)s" then 0 else 1 end, + case when supplier_name like "%(txt)s" then 0 else 1 end, + name, supplier_name + limit %(start)s, %(page_len)s """ % {'field': fields,'key': searchfield, + 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len}) - + def tax_account_query(doctype, txt, searchfield, start, page_len, filters): - tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount - where tabAccount.docstatus!=2 + tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount + where tabAccount.docstatus!=2 and account_type in (%s) and group_or_ledger = 'Ledger' and company = %s and `%s` LIKE %s - limit %s, %s""" % - (", ".join(['%s']*len(filters.get("account_type"))), "%s", searchfield, "%s", "%s", "%s"), - tuple(filters.get("account_type") + [filters.get("company"), "%%%s%%" % txt, + limit %s, %s""" % + (", ".join(['%s']*len(filters.get("account_type"))), "%s", searchfield, "%s", "%s", "%s"), + tuple(filters.get("account_type") + [filters.get("company"), "%%%s%%" % txt, start, page_len])) if not tax_accounts: - tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount - where tabAccount.docstatus!=2 and group_or_ledger = 'Ledger' - and company = %s and `%s` LIKE %s limit %s, %s""" - % ("%s", searchfield, "%s", "%s", "%s"), + tax_accounts = frappe.db.sql("""select name, parent_account from tabAccount + where tabAccount.docstatus!=2 and group_or_ledger = 'Ledger' + and company = %s and `%s` LIKE %s limit %s, %s""" + % ("%s", searchfield, "%s", "%s", "%s"), (filters.get("company"), "%%%s%%" % txt, start, page_len)) - + return tax_accounts def item_query(doctype, txt, searchfield, start, page_len, filters): from frappe.utils import nowdate - + conditions = [] - return frappe.db.sql("""select tabItem.name, - if(length(tabItem.item_name) > 40, - concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name, + return frappe.db.sql("""select tabItem.name, + if(length(tabItem.item_name) > 40, + concat(substr(tabItem.item_name, 1, 40), "..."), item_name) as item_name, if(length(tabItem.description) > 40, \ concat(substr(tabItem.description, 1, 40), "..."), description) as decription - from tabItem + from tabItem where tabItem.docstatus < 2 and (ifnull(tabItem.end_of_life, '') = '' or tabItem.end_of_life > %(today)s) and (tabItem.`{key}` LIKE %(txt)s - or tabItem.item_name LIKE %(txt)s) + or tabItem.item_name LIKE %(txt)s) {fcond} {mcond} limit %(start)s, %(page_len)s """.format(key=searchfield, fcond=get_filters_cond(doctype, filters, conditions), - mcond=get_match_cond(doctype)), + mcond=get_match_cond(doctype)), { "today": nowdate(), "txt": "%%%s%%" % txt, @@ -152,38 +152,38 @@ def item_query(doctype, txt, searchfield, start, page_len, filters): }) def bom(doctype, txt, searchfield, start, page_len, filters): - conditions = [] + conditions = [] - return frappe.db.sql("""select tabBOM.name, tabBOM.item - from tabBOM - where tabBOM.docstatus=1 - and tabBOM.is_active=1 - and tabBOM.%(key)s like "%(txt)s" - %(fcond)s %(mcond)s - limit %(start)s, %(page_len)s """ % {'key': searchfield, 'txt': "%%%s%%" % txt, - 'fcond': get_filters_cond(doctype, filters, conditions), + return frappe.db.sql("""select tabBOM.name, tabBOM.item + from tabBOM + where tabBOM.docstatus=1 + and tabBOM.is_active=1 + and tabBOM.%(key)s like "%(txt)s" + %(fcond)s %(mcond)s + limit %(start)s, %(page_len)s """ % {'key': searchfield, 'txt': "%%%s%%" % txt, + 'fcond': get_filters_cond(doctype, filters, conditions), 'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len}) def get_project_name(doctype, txt, searchfield, start, page_len, filters): cond = '' if filters['customer']: cond = '(`tabProject`.customer = "' + filters['customer'] + '" or ifnull(`tabProject`.customer,"")="") and' - - return frappe.db.sql("""select `tabProject`.name from `tabProject` - where `tabProject`.status not in ("Completed", "Cancelled") - and %(cond)s `tabProject`.name like "%(txt)s" %(mcond)s - order by `tabProject`.name asc - limit %(start)s, %(page_len)s """ % {'cond': cond,'txt': "%%%s%%" % txt, + + return frappe.db.sql("""select `tabProject`.name from `tabProject` + where `tabProject`.status not in ("Completed", "Cancelled") + and %(cond)s `tabProject`.name like "%(txt)s" %(mcond)s + order by `tabProject`.name asc + limit %(start)s, %(page_len)s """ % {'cond': cond,'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype),'start': start, 'page_len': page_len}) - + def get_delivery_notes_to_be_billed(doctype, txt, searchfield, start, page_len, filters): return frappe.db.sql("""select `tabDelivery Note`.name, `tabDelivery Note`.customer_name - from `tabDelivery Note` - where `tabDelivery Note`.`%(key)s` like %(txt)s and + from `tabDelivery Note` + where `tabDelivery Note`.`%(key)s` like %(txt)s and `tabDelivery Note`.docstatus = 1 %(fcond)s and - (ifnull((select sum(qty) from `tabDelivery Note Item` where + (ifnull((select sum(qty) from `tabDelivery Note Item` where `tabDelivery Note Item`.parent=`tabDelivery Note`.name), 0) > - ifnull((select sum(qty) from `tabSales Invoice Item` where + ifnull((select sum(qty) from `tabSales Invoice Item` where `tabSales Invoice Item`.docstatus = 1 and `tabSales Invoice Item`.delivery_note=`tabDelivery Note`.name), 0)) %(mcond)s order by `tabDelivery Note`.`%(key)s` asc @@ -198,30 +198,30 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters): from erpnext.controllers.queries import get_match_cond if filters.has_key('warehouse'): - return frappe.db.sql("""select batch_no from `tabStock Ledger Entry` sle - where item_code = '%(item_code)s' - and warehouse = '%(warehouse)s' - and batch_no like '%(txt)s' - and exists(select * from `tabBatch` - where name = sle.batch_no - and (ifnull(expiry_date, '')='' or expiry_date >= '%(posting_date)s') - and docstatus != 2) + return frappe.db.sql("""select batch_no from `tabStock Ledger Entry` sle + where item_code = '%(item_code)s' + and warehouse = '%(warehouse)s' + and batch_no like '%(txt)s' + and exists(select * from `tabBatch` + where name = sle.batch_no + and (ifnull(expiry_date, '')='' or expiry_date >= '%(posting_date)s') + and docstatus != 2) %(mcond)s - group by batch_no having sum(actual_qty) > 0 - order by batch_no desc - limit %(start)s, %(page_len)s """ % {'item_code': filters['item_code'], - 'warehouse': filters['warehouse'], 'posting_date': filters['posting_date'], - 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype), + group by batch_no having sum(actual_qty) > 0 + order by batch_no desc + limit %(start)s, %(page_len)s """ % {'item_code': filters['item_code'], + 'warehouse': filters['warehouse'], 'posting_date': filters['posting_date'], + 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype), 'start': start, 'page_len': page_len}) else: - return frappe.db.sql("""select name from tabBatch - where docstatus != 2 - and item = '%(item_code)s' + return frappe.db.sql("""select name from tabBatch + where docstatus != 2 + and item = '%(item_code)s' and (ifnull(expiry_date, '')='' or expiry_date >= '%(posting_date)s') - and name like '%(txt)s' - %(mcond)s - order by name desc - limit %(start)s, %(page_len)s""" % {'item_code': filters['item_code'], - 'posting_date': filters['posting_date'], 'txt': "%%%s%%" % txt, - 'mcond':get_match_cond(doctype),'start': start, + and name like '%(txt)s' + %(mcond)s + order by name desc + limit %(start)s, %(page_len)s""" % {'item_code': filters['item_code'], + 'posting_date': filters['posting_date'], 'txt': "%%%s%%" % txt, + 'mcond':get_match_cond(doctype),'start': start, 'page_len': page_len}) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index b302c7c218..103144ff16 100644 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -329,7 +329,7 @@ def make_sales_invoice(source_name, target_doc=None): def update_item(source, target, source_parent): target.amount = flt(source.amount) - flt(source.billed_amt) target.base_amount = target.amount * flt(source_parent.conversion_rate) - target.qty = source.rate and target.amount / flt(source.rate) or obj.qty + target.qty = source.rate and target.amount / flt(source.rate) or source.qty doclist = get_mapped_doc("Sales Order", source_name, { "Sales Order": { diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index ce2a7988f5..e5d6cec207 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -20,22 +20,22 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ this.setup_queries(); this.toggle_editable_price_list_rate(); }, - + setup_queries: function() { var me = this; - + this.frm.add_fetch("sales_partner", "commission_rate", "commission_rate"); - - $.each([["customer_address", "customer_filter"], + + $.each([["customer_address", "customer_filter"], ["shipping_address_name", "customer_filter"], - ["contact_person", "customer_filter"], - ["customer", "customer"], - ["lead", "lead"]], + ["contact_person", "customer_filter"], + ["customer", "customer"], + ["lead", "lead"]], function(i, opts) { - if(me.frm.fields_dict[opts[0]]) + if(me.frm.fields_dict[opts[0]]) me.frm.set_query(opts[0], erpnext.queries[opts[1]]); }); - + if(this.frm.fields_dict.taxes_and_charges) { this.frm.set_query("taxes_and_charges", function() { return { @@ -52,11 +52,11 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ return { filters: { selling: 1 } }; }); } - + if(!this.fname) { return; } - + if(this.frm.fields_dict[this.fname].grid.get_field('item_code')) { this.frm.set_query("item_code", this.fname, function() { return { @@ -67,7 +67,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ } }); } - + if(this.frm.fields_dict[this.fname].grid.get_field('batch_no')) { this.frm.set_query("batch_no", this.fname, function(doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); @@ -79,7 +79,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ 'posting_date': me.frm.doc.posting_date, } if(item.warehouse) filters["warehouse"] = item.warehouse - + return { query : "erpnext.controllers.queries.get_batch_no", filters: filters @@ -87,56 +87,56 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ } }); } - + if(this.frm.fields_dict.sales_team && this.frm.fields_dict.sales_team.grid.get_field("sales_person")) { this.frm.set_query("sales_person", "sales_team", erpnext.queries.not_a_group_filter); } }, - + refresh: function() { this._super(); - this.frm.toggle_display("customer_name", + this.frm.toggle_display("customer_name", (this.frm.doc.customer_name && this.frm.doc.customer_name!==this.frm.doc.customer)); if(this.frm.fields_dict.packing_details) { var packing_list_exists = (this.frm.doc.packing_details || []).length; this.frm.toggle_display("packing_list", packing_list_exists ? true : false); } }, - + customer: function() { erpnext.utils.get_party_details(this.frm); }, - + customer_address: function() { erpnext.utils.get_address_display(this.frm, "customer_address"); }, - + shipping_address_name: function() { erpnext.utils.get_address_display(this.frm, "shipping_address_name", "shipping_address"); }, - + contact_person: function() { erpnext.utils.get_contact_details(this.frm); }, - + barcode: function(doc, cdt, cdn) { this.item_code(doc, cdt, cdn); }, - + selling_price_list: function() { this.get_price_list_currency("Selling"); }, - + price_list_rate: function(doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); frappe.model.round_floats_in(item, ["price_list_rate", "discount_percentage"]); - + item.rate = flt(item.price_list_rate * (1 - item.discount_percentage / 100.0), precision("rate", item)); - + this.calculate_taxes_and_totals(); }, - + discount_percentage: function(doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); if(!item.price_list_rate) { @@ -145,63 +145,63 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ this.price_list_rate(doc, cdt, cdn); } }, - + rate: function(doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); frappe.model.round_floats_in(item, ["rate", "price_list_rate"]); - + if(item.price_list_rate) { item.discount_percentage = flt((1 - item.rate / item.price_list_rate) * 100.0, precision("discount_percentage", item)); } else { item.discount_percentage = 0.0; } - + this.calculate_taxes_and_totals(); }, discount_amount: function() { this.calculate_taxes_and_totals(); }, - + commission_rate: function() { this.calculate_commission(); refresh_field("total_commission"); }, - + total_commission: function() { if(this.frm.doc.net_total) { frappe.model.round_floats_in(this.frm.doc, ["net_total", "total_commission"]); - + if(this.frm.doc.net_total < this.frm.doc.total_commission) { - var msg = (frappe._("[Error]") + " " + - frappe._(frappe.meta.get_label(this.frm.doc.doctype, "total_commission", - this.frm.doc.name)) + " > " + + var msg = (frappe._("[Error]") + " " + + frappe._(frappe.meta.get_label(this.frm.doc.doctype, "total_commission", + this.frm.doc.name)) + " > " + frappe._(frappe.meta.get_label(this.frm.doc.doctype, "net_total", this.frm.doc.name))); msgprint(msg); throw msg; } - - this.frm.set_value("commission_rate", + + this.frm.set_value("commission_rate", flt(this.frm.doc.total_commission * 100.0 / this.frm.doc.net_total)); } }, - + allocated_percentage: function(doc, cdt, cdn) { var sales_person = frappe.get_doc(cdt, cdn); - + if(sales_person.allocated_percentage) { sales_person.allocated_percentage = flt(sales_person.allocated_percentage, precision("allocated_percentage", sales_person)); sales_person.allocated_amount = flt(this.frm.doc.net_total * - sales_person.allocated_percentage / 100.0, + sales_person.allocated_percentage / 100.0, precision("allocated_amount", sales_person)); refresh_field(["allocated_percentage", "allocated_amount"], sales_person.name, sales_person.parentfield); } }, - + warehouse: function(doc, cdt, cdn) { var item = frappe.get_doc(cdt, cdn); if(item.item_code && item.warehouse) { @@ -215,7 +215,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ }); } }, - + toggle_rounded_total: function() { var me = this; if(cint(frappe.defaults.get_global_default("disable_rounded_total"))) { @@ -225,16 +225,16 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ }); } }, - + toggle_editable_price_list_rate: function() { var df = frappe.meta.get_docfield(this.tname, "price_list_rate", this.frm.doc.name); var editable_price_list_rate = cint(frappe.defaults.get_default("editable_price_list_rate")); - + if(df && editable_price_list_rate) { df.read_only = 0; } }, - + calculate_taxes_and_totals: function() { this._super(); this.calculate_total_advance("Sales Invoice", "advance_adjustment_details"); @@ -242,13 +242,13 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ this.calculate_contribution(); // TODO check for custom_recalc in custom scripts of server - + this.frm.refresh_fields(); }, - + calculate_item_values: function() { var me = this; - + if (!this.discount_amount_applied) { $.each(this.frm.item_doclist, function(i, item) { frappe.model.round_floats_in(item); @@ -260,34 +260,34 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ }); } }, - + determine_exclusive_rate: function() { var me = this; $.each(me.frm.item_doclist, function(n, item) { var item_tax_map = me._load_item_tax_rate(item.item_tax_rate); var cumulated_tax_fraction = 0.0; - + $.each(me.frm.tax_doclist, function(i, tax) { tax.tax_fraction_for_current_item = me.get_current_tax_fraction(tax, item_tax_map); - + if(i==0) { tax.grand_total_fraction_for_current_item = 1 + tax.tax_fraction_for_current_item; } else { - tax.grand_total_fraction_for_current_item = + tax.grand_total_fraction_for_current_item = me.frm.tax_doclist[i-1].grand_total_fraction_for_current_item + tax.tax_fraction_for_current_item; } - + cumulated_tax_fraction += tax.tax_fraction_for_current_item; }); - + if(cumulated_tax_fraction && !me.discount_amount_applied) { item.base_amount = flt( (item.amount * me.frm.doc.conversion_rate) / (1 + cumulated_tax_fraction), precision("base_amount", item)); item.base_rate = flt(item.base_amount / item.qty, precision("base_rate", item)); - + if(item.discount_percentage == 100) { item.base_price_list_rate = item.base_rate; item.base_rate = 0.0; @@ -298,31 +298,31 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ } }); }, - + get_current_tax_fraction: function(tax, item_tax_map) { // Get tax fraction for calculating tax exclusive amount // from tax inclusive amount var current_tax_fraction = 0.0; - + if(cint(tax.included_in_print_rate)) { var tax_rate = this._get_tax_rate(tax, item_tax_map); - + if(tax.charge_type == "On Net Total") { current_tax_fraction = (tax_rate / 100.0); - + } else if(tax.charge_type == "On Previous Row Amount") { current_tax_fraction = (tax_rate / 100.0) * this.frm.tax_doclist[cint(tax.row_id) - 1].tax_fraction_for_current_item; - + } else if(tax.charge_type == "On Previous Row Total") { current_tax_fraction = (tax_rate / 100.0) * this.frm.tax_doclist[cint(tax.row_id) - 1].grand_total_fraction_for_current_item; } } - + return current_tax_fraction; }, - + calculate_net_total: function() { var me = this; this.frm.doc.net_total = this.frm.doc.net_total_export = 0.0; @@ -334,7 +334,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ frappe.model.round_floats_in(this.frm.doc, ["net_total", "net_total_export"]); }, - + calculate_totals: function() { var me = this; var tax_count = this.frm.tax_doclist.length; @@ -344,13 +344,13 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ precision("grand_total")); this.frm.doc.grand_total_export = flt(this.frm.doc.grand_total / this.frm.doc.conversion_rate, precision("grand_total_export")); - + this.frm.doc.other_charges_total = flt(this.frm.doc.grand_total - this.frm.doc.net_total, precision("other_charges_total")); - this.frm.doc.other_charges_total_export = flt(this.frm.doc.grand_total_export - + this.frm.doc.other_charges_total_export = flt(this.frm.doc.grand_total_export - this.frm.doc.net_total_export + flt(this.frm.doc.discount_amount), precision("other_charges_total_export")); - + this.frm.doc.rounded_total = Math.round(this.frm.doc.grand_total); this.frm.doc.rounded_total_export = Math.round(this.frm.doc.grand_total_export); }, @@ -393,19 +393,19 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ total_actual_tax += value; }); - grand_total_for_discount_amount = flt(this.frm.doc.grand_total - total_actual_tax, + grand_total_for_discount_amount = flt(this.frm.doc.grand_total - total_actual_tax, precision("grand_total")); return grand_total_for_discount_amount; }, - + calculate_outstanding_amount: function() { - // NOTE: + // NOTE: // paid_amount and write_off_amount is only for POS Invoice // total_advance is only for non POS Invoice if(this.frm.doc.doctype == "Sales Invoice" && this.frm.doc.docstatus==0) { frappe.model.round_floats_in(this.frm.doc, ["grand_total", "total_advance", "write_off_amount", "paid_amount"]); - var total_amount_to_pay = this.frm.doc.grand_total - this.frm.doc.write_off_amount + var total_amount_to_pay = this.frm.doc.grand_total - this.frm.doc.write_off_amount - this.frm.doc.total_advance; if(this.frm.doc.is_pos) { if(!this.frm.doc.paid_amount) this.frm.doc.paid_amount = flt(total_amount_to_pay); @@ -413,11 +413,11 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ this.frm.doc.paid_amount = 0 } - this.frm.set_value("outstanding_amount", flt(total_amount_to_pay + this.frm.set_value("outstanding_amount", flt(total_amount_to_pay - this.frm.doc.paid_amount, precision("outstanding_amount"))); } }, - + calculate_commission: function() { if(this.frm.fields_dict.commission_rate) { if(this.frm.doc.commission_rate > 100) { @@ -426,12 +426,12 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ msgprint(msg); throw msg; } - + this.frm.doc.total_commission = flt(this.frm.doc.net_total * this.frm.doc.commission_rate / 100.0, precision("total_commission")); } }, - + calculate_contribution: function() { var me = this; $.each(this.frm.doc.doctype.sales_team || [], function(i, sales_person) { @@ -443,7 +443,7 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ } }); }, - + _cleanup: function() { this._super(); this.frm.doc.in_words = this.frm.doc.in_words_export = ""; @@ -463,16 +463,16 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ }) } }, - + set_dynamic_labels: function() { this._super(); set_sales_bom_help(this.frm.doc); }, - + change_form_labels: function(company_currency) { var me = this; var field_label_map = {}; - + var setup_field_label_map = function(fields_list, currency) { $.each(fields_list, function(i, fname) { var docfield = frappe.meta.docfield_map[me.frm.doc.doctype][fname]; @@ -482,76 +482,76 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ } }); }; - setup_field_label_map(["net_total", "other_charges_total", "grand_total", + setup_field_label_map(["net_total", "other_charges_total", "grand_total", "rounded_total", "in_words", "outstanding_amount", "total_advance", "paid_amount", "write_off_amount"], company_currency); - - setup_field_label_map(["net_total_export", "other_charges_total_export", "grand_total_export", + + setup_field_label_map(["net_total_export", "other_charges_total_export", "grand_total_export", "rounded_total_export", "in_words_export"], this.frm.doc.currency); - - cur_frm.set_df_property("conversion_rate", "description", "1 " + this.frm.doc.currency + + cur_frm.set_df_property("conversion_rate", "description", "1 " + this.frm.doc.currency + " = [?] " + company_currency) - + if(this.frm.doc.price_list_currency && this.frm.doc.price_list_currency!=company_currency) { - cur_frm.set_df_property("plc_conversion_rate", "description", "1 " + this.frm.doc.price_list_currency + cur_frm.set_df_property("plc_conversion_rate", "description", "1 " + this.frm.doc.price_list_currency + " = [?] " + company_currency) } - + // toggle fields - this.frm.toggle_display(["conversion_rate", "net_total", "other_charges_total", + this.frm.toggle_display(["conversion_rate", "net_total", "other_charges_total", "grand_total", "rounded_total", "in_words"], this.frm.doc.currency != company_currency); - - this.frm.toggle_display(["plc_conversion_rate", "price_list_currency"], + + this.frm.toggle_display(["plc_conversion_rate", "price_list_currency"], this.frm.doc.price_list_currency != company_currency); - + // set labels $.each(field_label_map, function(fname, label) { me.frm.fields_dict[fname].set_label(label); }); }, - + change_grid_labels: function(company_currency) { var me = this; var field_label_map = {}; - + var setup_field_label_map = function(fields_list, currency, parentfield) { var grid_doctype = me.frm.fields_dict[parentfield].grid.doctype; $.each(fields_list, function(i, fname) { var docfield = frappe.meta.docfield_map[grid_doctype][fname]; if(docfield) { var label = frappe._(docfield.label || "").replace(/\([^\)]*\)/g, ""); - field_label_map[grid_doctype + "-" + fname] = + field_label_map[grid_doctype + "-" + fname] = label.trim() + " (" + currency + ")"; } }); } - + setup_field_label_map(["base_rate", "base_price_list_rate", "base_amount"], company_currency, this.fname); - + setup_field_label_map(["rate", "price_list_rate", "amount"], this.frm.doc.currency, this.fname); - + setup_field_label_map(["tax_amount", "total"], company_currency, "other_charges"); - + if(this.frm.fields_dict["advance_allocation_details"]) { setup_field_label_map(["advance_amount", "allocated_amount"], company_currency, "advance_allocation_details"); } - + // toggle columns var item_grid = this.frm.fields_dict[this.fname].grid; - var show = (this.frm.doc.currency != company_currency) || - (cur_frm.doc.other_charges.filter( + var show = (this.frm.doc.currency != company_currency) || + ((cur_frm.doc.other_charges || []).filter( function(d) { return d.included_in_print_rate===1}).length); - + $.each(["base_rate", "base_price_list_rate", "base_amount"], function(i, fname) { if(frappe.meta.get_docfield(item_grid.doctype, fname)) item_grid.set_column_disp(fname, show); }); - + // set labels var $wrapper = $(this.frm.wrapper); $.each(field_label_map, function(fname, label) { @@ -567,7 +567,7 @@ var set_sales_bom_help = function(doc) { if(!cur_frm.fields_dict.packing_list) return; if ((doc.packing_details || []).length) { $(cur_frm.fields_dict.packing_list.row.wrapper).toggle(true); - + if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) { help_msg = "
" + frappe._("For 'Sales BOM' items, warehouse, serial no and batch no \ @@ -576,7 +576,7 @@ var set_sales_bom_help = function(doc) { those values can be entered in the main item table, values will be copied to 'Packing List' table.")+ "
"; frappe.meta.get_docfield(doc.doctype, 'sales_bom_help', doc.name).options = help_msg; - } + } } else { $(cur_frm.fields_dict.packing_list.row.wrapper).toggle(false); if (inList(['Delivery Note', 'Sales Invoice'], doc.doctype)) { diff --git a/erpnext/stock/doctype/item/item.js b/erpnext/stock/doctype/item/item.js index b797420bdb..78bdcb08b5 100644 --- a/erpnext/stock/doctype/item/item.js +++ b/erpnext/stock/doctype/item/item.js @@ -1,13 +1,15 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt +frappe.provide("erpnext.item"); + cur_frm.cscript.refresh = function(doc) { // make sensitive fields(has_serial_no, is_stock_item, valuation_method) // read only if any stock ledger entry exists cur_frm.cscript.make_dashboard() erpnext.hide_naming_series(); - + if(!doc.__islocal && doc.show_in_website) { cur_frm.appframe.add_button("View In Website", function() { window.open(doc.page_name); @@ -19,8 +21,19 @@ cur_frm.cscript.refresh = function(doc) { cur_frm.toggle_enable(['has_serial_no', 'is_stock_item', 'valuation_method'], doc.__sle_exists=="exists" ? false : true); } + + erpnext.item.toggle_reqd(cur_frm); } +erpnext.item.toggle_reqd = function(frm) { + frm.toggle_reqd("default_warehouse", frm.doc.is_stock_item==="Yes"); +}; + +frappe.ui.form.on("Item", "is_stock_item", function(frm) { + erpnext.item.toggle_reqd(frm); +}); + + cur_frm.cscript.make_dashboard = function() { cur_frm.dashboard.reset(); if(cur_frm.doc.__islocal) @@ -152,7 +165,7 @@ cur_frm.fields_dict.item_supplier_details.grid.get_field("supplier").get_query = cur_frm.cscript.copy_from_item_group = function(doc) { frappe.model.with_doc("Item Group", doc.item_group, function() { $.each((doc.item_website_specifications || []), function(i, d) { - var n = frappe.model.add_child(doc, "Item Website Specification", + var n = frappe.model.add_child(doc, "Item Website Specification", "item_website_specifications"); n.label = d.label; n.description = d.description; @@ -164,11 +177,11 @@ cur_frm.cscript.copy_from_item_group = function(doc) { cur_frm.cscript.image = function() { refresh_field("image_view"); - + if(!cur_frm.doc.description_html) cur_frm.cscript.add_image(cur_frm.doc); else { - msgprint(frappe._("You may need to update: ") + + msgprint(frappe._("You may need to update: ") + frappe.meta.get_docfield(cur_frm.doc.doctype, "description_html").label); } -} \ No newline at end of file +} diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index dd364ff518..1bdab9e5cd 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -7,7 +7,7 @@ from frappe import msgprint, _ from frappe.utils import cstr, flt, getdate, now_datetime, formatdate from frappe.website.website_generator import WebsiteGenerator -class WarehouseNotSet(Exception): pass +class WarehouseNotSet(frappe.ValidationError): pass class Item(WebsiteGenerator): def onload(self): diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index b6ffb83227..cb130b2e3e 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -369,8 +369,8 @@ class StockEntry(StockController): arg = json.loads(arg) item = frappe.db.sql("""select stock_uom, description, item_name, expense_account, buying_cost_center from `tabItem` - where name = %s and (ifnull(end_of_life,'')='' or end_of_life ='0000-00-00' - or end_of_life > now())""", (arg.get('item_code')), as_dict = 1) + where name = %s and (ifnull(end_of_life,'')='' or end_of_life > now())""", + (arg.get('item_code')), as_dict = 1) if not item: msgprint("Item is not active", raise_exception=1) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index eeff2750ef..85d7e12e50 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -31,49 +31,49 @@ def get_item_details(args): if isinstance(args, basestring): args = json.loads(args) - + args = frappe._dict(args) if not args.get("transaction_type"): args.transaction_type = "buying" if frappe.get_meta(args.get("doctype")).get_field("supplier") \ else "selling" - + if not args.get("price_list"): args.price_list = args.get("selling_price_list") or args.get("buying_price_list") - + if args.barcode: args.item_code = get_item_code(barcode=args.barcode) elif not args.item_code and args.serial_no: args.item_code = get_item_code(serial_no=args.serial_no) - + item_doc = frappe.get_doc("Item", args.item_code) item = item_doc validate_item_details(args, item) - + out = get_basic_details(args, item_doc) - + get_party_item_code(args, item_doc, out) if out.get("warehouse"): out.update(get_available_qty(args.item_code, out.warehouse)) out.update(get_projected_qty(item.name, out.warehouse)) - + get_price_list_rate(args, item_doc, out) if args.transaction_type == "selling" and cint(args.is_pos): out.update(get_pos_settings_item_details(args.company, args)) - + apply_pricing_rule(out, args) - + if args.get("doctype") in ("Sales Invoice", "Delivery Note"): if item_doc.has_serial_no == "Yes" and not args.serial_no: out.serial_no = get_serial_nos_by_fifo(args, item_doc) - + if args.transaction_date and item.lead_time_days: out.schedule_date = out.lead_time_date = add_days(args.transaction_date, item.lead_time_days) - + return out def get_item_code(barcode=None, serial_no=None): @@ -83,26 +83,26 @@ def get_item_code(barcode=None, serial_no=None): item_code = frappe.db.get_value("Serial No", serial_no, "item_code") if not item_code: - throw(_("No Item found with ") + _("Barcode") if barcode else _("Serial No") + + throw(_("No Item found with ") + _("Barcode") if barcode else _("Serial No") + ": %s" % (barcode or serial_no)) - + return item_code - + def validate_item_details(args, item): if not args.company: throw(_("Please specify Company")) - + from erpnext.stock.doctype.item.item import validate_end_of_life validate_end_of_life(item.name, item.end_of_life) - + if args.transaction_type == "selling": # validate if sales item or service item if args.get("order_type") == "Maintenance": if item.is_service_item != "Yes": - throw(_("Item") + (" %s: " % item.name) + + throw(_("Item") + (" %s: " % item.name) + _("is not a service item.") + _("Please select a service item or change the order type to Sales.")) - + elif item.is_sales_item != "Yes": throw(_("Item") + (" %s: " % item.name) + _("is not a sales item")) @@ -110,15 +110,15 @@ def validate_item_details(args, item): # validate if purchase item or subcontracted item if item.is_purchase_item != "Yes": throw(_("Item") + (" %s: " % item.name) + _("is not a purchase item")) - + if args.get("is_subcontracted") == "Yes" and item.is_sub_contracted_item != "Yes": - throw(_("Item") + (" %s: " % item.name) + + throw(_("Item") + (" %s: " % item.name) + _("not a sub-contracted item.") + _("Please select a sub-contracted item or do not sub-contract the transaction.")) - + def get_basic_details(args, item_doc): item = item_doc - + from frappe.defaults import get_user_default_as_list user_default_warehouse_list = get_user_default_as_list('warehouse') user_default_warehouse = user_default_warehouse_list[0] \ @@ -136,7 +136,7 @@ def get_basic_details(args, item_doc): "cost_center": item.selling_cost_center \ if args.transaction_type == "selling" else item.buying_cost_center, "batch_no": None, - "item_tax_rate": json.dumps(dict(([d.tax_type, d.tax_rate] for d in + "item_tax_rate": json.dumps(dict(([d.tax_type, d.tax_rate] for d in item_doc.get("item_tax")))), "uom": item.stock_uom, "min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "", @@ -150,12 +150,12 @@ def get_basic_details(args, item_doc): "base_amount": 0.0, "discount_percentage": 0.0 }) - + for fieldname in ("item_name", "item_group", "barcode", "brand", "stock_uom"): out[fieldname] = item.get(fieldname) - + return out - + def get_price_list_rate(args, item_doc, out): meta = frappe.get_meta(args.doctype) @@ -163,50 +163,50 @@ def get_price_list_rate(args, item_doc, out): validate_price_list(args) validate_conversion_rate(args, meta) - price_list_rate = frappe.db.get_value("Item Price", + price_list_rate = frappe.db.get_value("Item Price", {"price_list": args.price_list, "item_code": args.item_code}, "price_list_rate") - + if not price_list_rate: return {} - + out.price_list_rate = flt(price_list_rate) * flt(args.plc_conversion_rate) \ / flt(args.conversion_rate) - + if not out.price_list_rate and args.transaction_type == "buying": from erpnext.stock.doctype.item.item import get_last_purchase_details - out.update(get_last_purchase_details(item_doc.name, + out.update(get_last_purchase_details(item_doc.name, args.docname, args.conversion_rate)) - + def validate_price_list(args): if args.get("price_list"): - if not frappe.db.get_value("Price List", + if not frappe.db.get_value("Price List", {"name": args.price_list, args.transaction_type: 1, "enabled": 1}): throw(_("Price List is either disabled or for not ") + _(args.transaction_type)) else: throw(_("Price List not selected")) - + def validate_conversion_rate(args, meta): from erpnext.setup.doctype.currency.currency import validate_conversion_rate from frappe.model.meta import get_field_precision - + # validate currency conversion rate - validate_conversion_rate(args.currency, args.conversion_rate, + validate_conversion_rate(args.currency, args.conversion_rate, meta.get_label("conversion_rate"), args.company) - - args.conversion_rate = flt(args.conversion_rate, - get_field_precision(meta.get_field("conversion_rate"), + + args.conversion_rate = flt(args.conversion_rate, + get_field_precision(meta.get_field("conversion_rate"), frappe._dict({"fields": args}))) - + # validate price list currency conversion rate if not args.get("price_list_currency"): throw(_("Price List Currency not selected")) else: - validate_conversion_rate(args.price_list_currency, args.plc_conversion_rate, + validate_conversion_rate(args.price_list_currency, args.plc_conversion_rate, meta.get_label("plc_conversion_rate"), args.company) - - args.plc_conversion_rate = flt(args.plc_conversion_rate, - get_field_precision(meta.get_field("plc_conversion_rate"), + + args.plc_conversion_rate = flt(args.plc_conversion_rate, + get_field_precision(meta.get_field("plc_conversion_rate"), frappe._dict({"fields": args}))) - + def get_party_item_code(args, item_doc, out): if args.transaction_type == "selling": customer_item_code = item_doc.get("item_customer_details", {"customer_name": args.customer}) @@ -214,35 +214,35 @@ def get_party_item_code(args, item_doc, out): else: item_supplier = item_doc.get("item_supplier_details", {"supplier": args.supplier}) out.supplier_part_no = item_supplier[0].supplier_part_no if item_supplier else None - + def get_pos_settings_item_details(company, args, pos_settings=None): res = frappe._dict() - + if not pos_settings: pos_settings = get_pos_settings(company) - + if pos_settings: for fieldname in ("income_account", "cost_center", "warehouse", "expense_account"): if not args.get(fieldname): res[fieldname] = pos_settings.get(fieldname) - + if res.get("warehouse"): - res.actual_qty = get_available_qty(args.item_code, + res.actual_qty = get_available_qty(args.item_code, res.warehouse).get("actual_qty") - + return res def get_pos_settings(company): - pos_settings = frappe.db.sql("""select * from `tabPOS Setting` where user = %s + pos_settings = frappe.db.sql("""select * from `tabPOS Setting` where user = %s and company = %s""", (frappe.session['user'], company), as_dict=1) - + if not pos_settings: - pos_settings = frappe.db.sql("""select * from `tabPOS Setting` + pos_settings = frappe.db.sql("""select * from `tabPOS Setting` where ifnull(user,'') = '' and company = %s""", company, as_dict=1) - + return pos_settings and pos_settings[0] or None - + def apply_pricing_rule(out, args): args_dict = frappe._dict().update(args) args_dict.update(out) @@ -260,67 +260,67 @@ def apply_pricing_rule(out, args): out["price_list_rate"] = pricing_rules[0]["price"] * \ flt(args_dict.plc_conversion_rate) / flt(args_dict.conversion_rate) out["pricing_rule_for_price"] = pricing_rules[-1]["name"] - + def get_pricing_rules(args_dict): def _get_tree_conditions(doctype, allow_blank=True): field = frappe.scrub(doctype) condition = "" if args_dict.get(field): lft, rgt = frappe.db.get_value(doctype, args_dict[field], ["lft", "rgt"]) - parent_groups = frappe.db.sql_list("""select name from `tab%s` + parent_groups = frappe.db.sql_list("""select name from `tab%s` where lft<=%s and rgt>=%s""" % (doctype, '%s', '%s'), (lft, rgt)) - + if parent_groups: if allow_blank: parent_groups.append('') condition = " ifnull("+field+", '') in ('" + "', '".join(parent_groups)+"')" return condition - - + + conditions = "" for field in ["customer", "supplier", "supplier_type", "campaign", "sales_partner"]: if args_dict.get(field): conditions += " and ifnull("+field+", '') in (%("+field+")s, '')" else: conditions += " and ifnull("+field+", '') = ''" - + for doctype in ["Customer Group", "Territory"]: group_condition = _get_tree_conditions(doctype) if group_condition: conditions += " and " + group_condition - + conditions += " and ifnull(for_price_list, '') in (%(price_list)s, '')" - + if args_dict.get("transaction_date"): - conditions += """ and %(transaction_date)s between ifnull(valid_from, '2000-01-01') + conditions += """ and %(transaction_date)s between ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')""" - - return frappe.db.sql("""select * from `tabPricing Rule` - where (item_code=%(item_code)s or {item_group_condition} or brand=%(brand)s) + + return frappe.db.sql("""select * from `tabPricing Rule` + where (item_code=%(item_code)s or {item_group_condition} or brand=%(brand)s) and docstatus < 2 and ifnull(disable, 0) = 0 {conditions} order by priority desc, name desc""".format( - item_group_condition=_get_tree_conditions("Item Group", False), conditions=conditions), + item_group_condition=_get_tree_conditions("Item Group", False), conditions=conditions), args_dict, as_dict=1) def filter_pricing_rules(args_dict, pricing_rules, price_or_discount): # filter for qty if pricing_rules and args_dict.get("qty"): - pricing_rules = filter(lambda x: (args_dict.qty>=flt(x.min_qty) + pricing_rules = filter(lambda x: (args_dict.qty>=flt(x.min_qty) and (args_dict.qty<=x.max_qty if x.max_qty else True)), pricing_rules) - + # find pricing rule with highest priority if pricing_rules: max_priority = max([cint(p.priority) for p in pricing_rules]) if max_priority: pricing_rules = filter(lambda x: cint(x.priority)==max_priority, pricing_rules) - + # apply internal priority - all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory", + all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory", "supplier", "supplier_type", "campaign", "for_price_list", "sales_partner"] - + if len(pricing_rules) > 1: - for field_set in [["item_code", "item_group", "brand"], + for field_set in [["item_code", "item_group", "brand"], ["customer", "customer_group", "territory"], ["supplier", "supplier_type"]]: remaining_fields = list(set(all_fields) - set(field_set)) if if_all_rules_same(pricing_rules, remaining_fields): @@ -329,7 +329,7 @@ def filter_pricing_rules(args_dict, pricing_rules, price_or_discount): if len(pricing_rules) > 1: pricing_rules = sorted(pricing_rules, key=lambda x: x[price_or_discount]) - + return pricing_rules def if_all_rules_same(pricing_rules, fields): @@ -339,7 +339,7 @@ def if_all_rules_same(pricing_rules, fields): if val != [p[k] for k in fields]: all_rules_same = False break - + return all_rules_same def apply_internal_priority(pricing_rules, field_set, args_dict): @@ -352,8 +352,8 @@ def apply_internal_priority(pricing_rules, field_set, args_dict): return filtered_rules or pricing_rules def get_serial_nos_by_fifo(args, item_doc): - return "\n".join(frappe.db.sql_list("""select name from `tabSerial No` - where item_code=%(item_code)s and warehouse=%(warehouse)s and status='Available' + return "\n".join(frappe.db.sql_list("""select name from `tabSerial No` + where item_code=%(item_code)s and warehouse=%(warehouse)s and status='Available' order by timestamp(purchase_date, purchase_time) asc limit %(qty)s""", { "item_code": args.item_code, "warehouse": args.warehouse, @@ -367,10 +367,10 @@ def get_conversion_factor(item_code, uom): @frappe.whitelist() def get_projected_qty(item_code, warehouse): - return {"projected_qty": frappe.db.get_value("Bin", + return {"projected_qty": frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, "projected_qty")} @frappe.whitelist() def get_available_qty(item_code, warehouse): - return frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, - ["projected_qty", "actual_qty"], as_dict=True) or {} \ No newline at end of file + return frappe.db.get_value("Bin", {"item_code": item_code, "warehouse": warehouse}, + ["projected_qty", "actual_qty"], as_dict=True) or {}