From 62ec60188b8ca7ebe431f43ca875897ec406a9fa Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Mon, 26 May 2014 17:44:24 +0530 Subject: [PATCH 01/21] use build_filter_conditions from db_query. Fixes #1679 --- erpnext/accounts/doctype/c_form/c_form.py | 10 ------ .../bank_reconciliation_statement.js | 4 +-- .../bank_reconciliation_statement.py | 33 ++++++++--------- erpnext/accounts/utils.py | 35 ++++++++++--------- erpnext/utilities/__init__.py | 9 ----- 5 files changed, 37 insertions(+), 54 deletions(-) diff --git a/erpnext/accounts/doctype/c_form/c_form.py b/erpnext/accounts/doctype/c_form/c_form.py index 11d05470aa..e0f008f8ad 100644 --- a/erpnext/accounts/doctype/c_form/c_form.py +++ b/erpnext/accounts/doctype/c_form/c_form.py @@ -64,13 +64,3 @@ class CForm(Document): 'net_total' : inv.net_total, 'grand_total' : inv.grand_total } - -def get_invoice_nos(doctype, txt, searchfield, start, page_len, filters): - from erpnext.utilities import build_filter_conditions - conditions, filter_values = build_filter_conditions(filters) - - return frappe.db.sql("""select name from `tabSales Invoice` where docstatus = 1 - and c_form_applicable = 'Yes' and ifnull(c_form_no, '') = '' %s - and %s like %s order by name limit %s, %s""" % - (conditions, searchfield, "%s", "%s", "%s"), - tuple(filter_values + ["%%%s%%" % txt, start, page_len])) diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js index 5316b587e1..4bdcd9e0c7 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js @@ -11,7 +11,7 @@ frappe.query_reports["Bank Reconciliation Statement"] = { "reqd": 1, "get_query": function() { return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.accounts.utils.get_account_list", "filters": [ ['Account', 'account_type', 'in', 'Bank, Cash'], ['Account', 'group_or_ledger', '=', 'Ledger'], @@ -27,4 +27,4 @@ frappe.query_reports["Bank Reconciliation Statement"] = { "reqd": 1 }, ] -} \ No newline at end of file +} diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py index 2b1923b11f..05cde6aab0 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py @@ -7,10 +7,11 @@ from frappe.utils import flt def execute(filters=None): if not filters: filters = {} - + if not filters.get("account"): return + columns = get_columns() data = get_entries(filters) - + from erpnext.accounts.utils import get_balance_on balance_as_per_company = get_balance_on(filters["account"], filters["report_date"]) @@ -20,33 +21,33 @@ def execute(filters=None): total_credit += flt(d[5]) bank_bal = flt(balance_as_per_company) + flt(total_debit) - flt(total_credit) - + data += [ get_balance_row("Balance as per company books", balance_as_per_company), - ["", "", "", "Amounts not reflected in bank", total_debit, total_credit], + ["", "", "", "Amounts not reflected in bank", total_debit, total_credit], get_balance_row("Balance as per bank", bank_bal) ] - + return columns, data - + def get_columns(): - return ["Journal Voucher:Link/Journal Voucher:140", "Posting Date:Date:100", - "Clearance Date:Date:110", "Against Account:Link/Account:200", + return ["Journal Voucher:Link/Journal Voucher:140", "Posting Date:Date:100", + "Clearance Date:Date:110", "Against Account:Link/Account:200", "Debit:Currency:120", "Credit:Currency:120" ] - + def get_entries(filters): - entries = frappe.db.sql("""select + entries = frappe.db.sql("""select jv.name, jv.posting_date, jv.clearance_date, jvd.against_account, jvd.debit, jvd.credit - from - `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv - where jvd.parent = jv.name and jv.docstatus=1 - and jvd.account = %(account)s and jv.posting_date <= %(report_date)s + from + `tabJournal Voucher Detail` jvd, `tabJournal Voucher` jv + where jvd.parent = jv.name and jv.docstatus=1 + and jvd.account = %(account)s and jv.posting_date <= %(report_date)s and ifnull(jv.clearance_date, '4000-01-01') > %(report_date)s order by jv.name DESC""", filters, as_list=1) - + return entries - + def get_balance_row(label, amount): if amount > 0: return ["", "", "", label, amount, 0] diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 1a09d38bf7..75825fcb7e 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -7,8 +7,7 @@ import frappe from frappe.utils import nowdate, cstr, flt, now, getdate, add_months from frappe import throw, _ from frappe.utils import formatdate -from erpnext.utilities import build_filter_conditions - +import frappe.widgets.reportview class FiscalYearError(frappe.ValidationError): pass class BudgetError(frappe.ValidationError): pass @@ -197,26 +196,28 @@ def update_against_doc(d, jv_obj): jv_obj.save() def get_account_list(doctype, txt, searchfield, start, page_len, filters): - if not filters.get("group_or_ledger"): - filters["group_or_ledger"] = "Ledger" + filters = add_group_or_ledger_filter("Account", filters) - conditions, filter_values = build_filter_conditions(filters) - - return frappe.db.sql("""select name, parent_account from `tabAccount` - where docstatus < 2 %s and %s like %s order by name limit %s, %s""" % - (conditions, searchfield, "%s", "%s", "%s"), - tuple(filter_values + ["%%%s%%" % txt, start, page_len])) + return frappe.widgets.reportview.execute("Account", filters = filters, + fields = ["name", "parent_account"], + limit_start=start, limit_page_length=page_len, as_list=True) def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters): - if not filters.get("group_or_ledger"): - filters["group_or_ledger"] = "Ledger" + filters = add_group_or_ledger_filter("Cost Center", filters) - conditions, filter_values = build_filter_conditions(filters) + return frappe.widgets.reportview.execute("Cost Center", filters = filters, + fields = ["name", "parent_cost_center"], + limit_start=start, limit_page_length=page_len, as_list=True) - return frappe.db.sql("""select name, parent_cost_center from `tabCost Center` - where docstatus < 2 %s and %s like %s order by name limit %s, %s""" % - (conditions, searchfield, "%s", "%s", "%s"), - tuple(filter_values + ["%%%s%%" % txt, start, page_len])) +def add_group_or_ledger_filter(doctype, filters): + if isinstance(filters, dict): + if not filters.get("group_or_ledger"): + filters["group_or_ledger"] = "Ledger" + elif isinstance(filters, list): + if "group_or_ledger" not in [d[0] for d in filters]: + filters.append([doctype, "group_or_ledger", "=", "Ledger"]) + + return filters def remove_against_link_from_jv(ref_type, ref_no, against_field): linked_jv = frappe.db.sql_list("""select parent from `tabJournal Voucher Detail` diff --git a/erpnext/utilities/__init__.py b/erpnext/utilities/__init__.py index e96ae83c8a..bfb3fe4bdf 100644 --- a/erpnext/utilities/__init__.py +++ b/erpnext/utilities/__init__.py @@ -22,12 +22,3 @@ from frappe.utils import cint, comma_or def validate_status(status, options): if status not in options: frappe.throw(_("Status must be one of {0}").format(comma_or(options))) - -def build_filter_conditions(filters): - conditions, filter_values = [], [] - for key in filters: - conditions.append('`' + key + '` = %s') - filter_values.append(filters[key]) - - conditions = conditions and " and " + " and ".join(conditions) or "" - return conditions, filter_values From a3dd72a7596c64b0a33cce07c15af8075747a133 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 28 May 2014 12:49:20 +0530 Subject: [PATCH 02/21] Pricing Rule --- .../doctype/pricing_rule/pricing_rule.js | 64 ++++++++++++ .../doctype/pricing_rule/pricing_rule.json | 22 ++++- .../doctype/pricing_rule/pricing_rule.py | 2 - .../purchase_invoice/purchase_invoice.js | 9 +- .../purchase_invoice_item.json | 21 ++-- .../doctype/sales_invoice/sales_invoice.js | 9 +- .../sales_invoice_item.json | 21 ++-- .../bank_reconciliation_statement.py | 4 +- .../purchase_common/purchase_common.js | 3 +- .../purchase_order_item.json | 21 ++-- .../supplier_quotation_item.json | 21 ++-- erpnext/controllers/accounts_controller.py | 6 ++ erpnext/public/js/transaction.js | 55 ++++++++++- erpnext/public/js/utils/party.js | 3 +- .../quotation_item/quotation_item.json | 21 ++-- .../sales_order_item/sales_order_item.json | 21 ++-- erpnext/selling/sales_common.js | 11 ++- .../delivery_note_item.json | 21 ++-- .../purchase_receipt_item.json | 21 ++-- erpnext/stock/get_item_details.py | 98 ++++++++++++------- 20 files changed, 296 insertions(+), 158 deletions(-) create mode 100644 erpnext/accounts/doctype/pricing_rule/pricing_rule.js diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.js b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js new file mode 100644 index 0000000000..356cc0de9c --- /dev/null +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.js @@ -0,0 +1,64 @@ +// Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +// License: GNU General Public License v3. See license.txt + +frappe.ui.form.on("Pricing Rule", "refresh", function(frm) { + var help_content = ['', + '', + '', + '
', + '

', + __('Notes'), + ':

', + '
    ', + '
  • ', + __("Pricing Rule is made to overwrite Price List / define discount percentage, based on some criteria."), + '
  • ', + '
  • ', + __("If selected Pricing Rule is made for 'Price', it will overwrite Price List. Pricing Rule price is the final price, so no further discount should be applied. Hence, in transactions like Sales Order, Purchase Order etc, it will be fetched in 'Rate' field, rather than 'Price List Rate' field."), + '
  • ', + '
  • ', + __('Discount Percentage can be applied either against a Price List or for all Price List.'), + '
  • ', + '
  • ', + __('To not apply Pricing Rule in a particular transaction, all applicable Pricing Rules should be disabled.'), + '
  • ', + '
', + '
', + '

', + __('How Pricing Rule is applied?'), + '

', + '
    ', + '
  1. ', + __("Pricing Rule is first selected based on 'Apply On' field, which can be Item, Item Group or Brand."), + '
  2. ', + '
  3. ', + __("Then Pricing Rules are filtered out based on Customer, Customer Group, Territory, Supplier, Supplier Type, Campaign, Sales Partner etc."), + '
  4. ', + '
  5. ', + __('Pricing Rules are further filtered based on quantity.'), + '
  6. ', + '
  7. ', + __('If two or more Pricing Rules are found based on the above conditions, Priority is applied. Priority is a number between 0 to 20 while default value is zero (blank). Higher number means it will take precedence if there are multiple Pricing Rules with same conditions.'), + '
  8. ', + '
  9. ', + __('Even if there are multiple Pricing Rules with highest priority, then following internal priorities are applied:'), + '
      ', + '
    • ', + __('Item Code > Item Group > Brand'), + '
    • ', + '
    • ', + __('Customer > Customer Group > Territory'), + '
    • ', + '
    • ', + __('Supplier > Supplier Type'), + '
    • ', + '
    ', + '
  10. ', + '
  11. ', + __('If multiple Pricing Rules continue to prevail, users are asked to set Priority manually to resolve conflict.'), + '
  12. ', + '
', + '
'].join("\n"); + + set_field_options("pricing_rule_help", help_content); +}); diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index baefde26ef..5fbb08f1cf 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -131,6 +131,13 @@ "fieldtype": "Column Break", "permlevel": 0 }, + { + "fieldname": "company", + "fieldtype": "Link", + "label": "Company", + "options": "Company", + "permlevel": 0 + }, { "default": "Today", "fieldname": "valid_from", @@ -198,12 +205,25 @@ "label": "For Price List", "options": "Price List", "permlevel": 0 + }, + { + "fieldname": "help_section", + "fieldtype": "Section Break", + "label": "", + "options": "Simple", + "permlevel": 0 + }, + { + "fieldname": "pricing_rule_help", + "fieldtype": "HTML", + "label": "Pricing Rule Help", + "permlevel": 0 } ], "icon": "icon-gift", "idx": 1, "istable": 0, - "modified": "2014-05-12 16:24:52.005162", + "modified": "2014-05-27 15:14:34.849671", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py index 39260a2e9e..61e7ade441 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.py @@ -15,7 +15,6 @@ class PricingRule(Document): self.validate_min_max_qty() self.cleanup_fields_value() - def validate_mandatory(self): for field in ["apply_on", "applicable_for", "price_or_discount"]: tocheck = frappe.scrub(self.get(field) or "") @@ -26,7 +25,6 @@ class PricingRule(Document): if self.min_qty and self.max_qty and flt(self.min_qty) > flt(self.max_qty): throw(_("Min Qty can not be greater than Max Qty")) - def cleanup_fields_value(self): for logic_field in ["apply_on", "applicable_for", "price_or_discount"]: fieldname = frappe.scrub(self.get(logic_field) or "") diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index 158dec2046..d87456d260 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -77,16 +77,19 @@ erpnext.accounts.PurchaseInvoice = erpnext.buying.BuyingController.extend({ }, supplier: function() { + var me = this; if(this.frm.updating_party_details) return; - erpnext.utils.get_party_details(this.frm, - "erpnext.accounts.party.get_party_details", { + erpnext.utils.get_party_details(this.frm, "erpnext.accounts.party.get_party_details", + { posting_date: this.frm.doc.posting_date, party: this.frm.doc.supplier, party_type: "Supplier", account: this.frm.doc.debit_to, price_list: this.frm.doc.buying_price_list, - }) + }, function() { + me.apply_pricing_rule(); + }) }, credit_to: function() { diff --git a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json index 26f3be7889..d3b4606034 100755 --- a/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json +++ b/erpnext/accounts/doctype/purchase_invoice_item/purchase_invoice_item.json @@ -1,6 +1,6 @@ { "autoname": "EVD.######", - "creation": "2013-05-22 12:43:10.000000", + "creation": "2013-05-22 12:43:10", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -193,17 +193,9 @@ "reqd": 1 }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -429,9 +421,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:27:53.000000", + "modified": "2014-05-28 12:43:40.647183", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js index a5707bb222..21b42a5f3f 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.js +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.js @@ -155,8 +155,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte }, customer: function() { - if(this.frm.updating_party_details) - return; + var me = this; + if(this.frm.updating_party_details) return; + erpnext.utils.get_party_details(this.frm, "erpnext.accounts.party.get_party_details", { posting_date: this.frm.doc.posting_date, @@ -164,7 +165,9 @@ erpnext.accounts.SalesInvoiceController = erpnext.selling.SellingController.exte party_type: "Customer", account: this.frm.doc.debit_to, price_list: this.frm.doc.selling_price_list, - }) + }, function() { + me.apply_pricing_rule(); + }) }, debit_to: function() { diff --git a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json index 527213be01..5b3bd9d888 100644 --- a/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json +++ b/erpnext/accounts/doctype/sales_invoice_item/sales_invoice_item.json @@ -1,6 +1,6 @@ { "autoname": "INVD.######", - "creation": "2013-06-04 11:02:19.000000", + "creation": "2013-06-04 11:02:19", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -201,17 +201,9 @@ "reqd": 1 }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -456,9 +448,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:04:19.000000", + "modified": "2014-05-28 12:42:28.209942", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py index 05cde6aab0..c1072a30ff 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.py @@ -7,9 +7,11 @@ from frappe.utils import flt def execute(filters=None): if not filters: filters = {} - if not filters.get("account"): return columns = get_columns() + + if not filters.get("account"): return columns, [] + data = get_entries(filters) from erpnext.accounts.utils import get_balance_on diff --git a/erpnext/buying/doctype/purchase_common/purchase_common.js b/erpnext/buying/doctype/purchase_common/purchase_common.js index c50dc3b664..032448f79f 100644 --- a/erpnext/buying/doctype/purchase_common/purchase_common.js +++ b/erpnext/buying/doctype/purchase_common/purchase_common.js @@ -62,7 +62,8 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({ }, supplier: function() { - erpnext.utils.get_party_details(this.frm); + var me = this; + erpnext.utils.get_party_details(this.frm, null, null, function(){me.apply_pricing_rule()}); }, supplier_address: function() { diff --git a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json index 23fb1c0e95..224f784c69 100755 --- a/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json +++ b/erpnext/buying/doctype/purchase_order_item/purchase_order_item.json @@ -1,6 +1,6 @@ { "autoname": "POD/.#####", - "creation": "2013-05-24 19:29:06.000000", + "creation": "2013-05-24 19:29:06", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -252,17 +252,9 @@ "reqd": 1 }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -474,9 +466,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:26:25.000000", + "modified": "2014-05-28 12:42:53.018610", "modified_by": "Administrator", "module": "Buying", "name": "Purchase Order Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json index 11cb9d9627..65dfe97af8 100644 --- a/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json +++ b/erpnext/buying/doctype/supplier_quotation_item/supplier_quotation_item.json @@ -1,6 +1,6 @@ { "autoname": "SQI-.#####", - "creation": "2013-05-22 12:43:10.000000", + "creation": "2013-05-22 12:43:10", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -195,17 +195,9 @@ "reqd": 1 }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -354,9 +346,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:25:38.000000", + "modified": "2014-05-28 12:44:17.347236", "modified_by": "Administrator", "module": "Buying", "name": "Supplier Quotation Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 9033065bd9..683f72b0f2 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -97,11 +97,17 @@ class AccountsController(TransactionBase): args = item.as_dict() args.update(parent_dict) ret = get_item_details(args) + for fieldname, value in ret.items(): if item.meta.get_field(fieldname) and \ item.get(fieldname) is None and value is not None: item.set(fieldname, value) + if ret.get("pricing_rule"): + for field in ["base_price_list_rate", "price_list_rate", + "discount_percentage", "base_rate", "rate"]: + item.set(field, ret.get(field)) + def set_taxes(self, tax_parentfield, tax_master_field): if not self.meta.get_field(tax_parentfield): return diff --git a/erpnext/public/js/transaction.js b/erpnext/public/js/transaction.js index e12a30e14e..b336637f0a 100644 --- a/erpnext/public/js/transaction.js +++ b/erpnext/public/js/transaction.js @@ -194,6 +194,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ } this.frm.script_manager.trigger("currency"); + this.apply_pricing_rule() } }, @@ -225,7 +226,9 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ this.frm.doc.plc_conversion_rate !== this.frm.doc.conversion_rate) { this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate); } - if(flt(this.frm.doc.conversion_rate)>0.0) this.calculate_taxes_and_totals(); + if(flt(this.frm.doc.conversion_rate)>0.0) { + this.apply_pricing_rule(); + } }, get_price_list_currency: function(buying_or_selling) { @@ -278,12 +281,12 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ } if(this.frm.doc.price_list_currency === this.frm.doc.currency) { this.frm.set_value("conversion_rate", this.frm.doc.plc_conversion_rate); - this.calculate_taxes_and_totals(); + this.apply_pricing_rule(); } }, qty: function(doc, cdt, cdn) { - this.calculate_taxes_and_totals(); + this.apply_pricing_rule(frappe.get_doc(cdt, cdn)); }, // tax rate @@ -326,6 +329,52 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ this.calculate_taxes_and_totals(); }, + apply_pricing_rule: function(item) { + var me = this; + + var _apply_pricing_rule = function(item) { + return me.frm.call({ + method: "erpnext.stock.get_item_details.apply_pricing_rule", + child: item, + args: { + args: { + item_code: item.item_code, + item_group: item.item_group, + brand: item.brand, + qty: item.qty, + customer: me.frm.doc.customer, + customer_group: me.frm.doc.customer_group, + territory: me.frm.doc.territory, + supplier: me.frm.doc.supplier, + supplier_type: me.frm.doc.supplier_type, + currency: me.frm.doc.currency, + conversion_rate: me.frm.doc.conversion_rate, + price_list: me.frm.doc.selling_price_list || + me.frm.doc.buying_price_list, + plc_conversion_rate: me.frm.doc.plc_conversion_rate, + company: me.frm.doc.company, + transaction_date: me.frm.doc.transaction_date || me.frm.doc.posting_date, + campaign: me.frm.doc.campaign, + sales_partner: me.frm.doc.sales_partner + } + }, + callback: function(r) { + if(!r.exc) { + me.frm.script_manager.trigger("price_list_rate", item.doctype, item.name); + } + } + }); + } + + + if(item) _apply_pricing_rule(item); + else { + $.each(this.get_item_doclist(), function(n, item) { + _apply_pricing_rule(item); + }); + } + }, + included_in_print_rate: function(doc, cdt, cdn) { var tax = frappe.get_doc(cdt, cdn); try { diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 31abbb304f..9da0353dbb 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -2,7 +2,7 @@ // License: GNU General Public License v3. See license.txt frappe.provide("erpnext.utils"); -erpnext.utils.get_party_details = function(frm, method, args) { +erpnext.utils.get_party_details = function(frm, method, args, callback) { if(!method) { method = "erpnext.accounts.party.get_party_details"; } @@ -33,6 +33,7 @@ erpnext.utils.get_party_details = function(frm, method, args) { frm.updating_party_details = true; frm.set_value(r.message); frm.updating_party_details = false; + if(callback) callback() } } }); diff --git a/erpnext/selling/doctype/quotation_item/quotation_item.json b/erpnext/selling/doctype/quotation_item/quotation_item.json index 4e19ee7970..a1807dd9ad 100644 --- a/erpnext/selling/doctype/quotation_item/quotation_item.json +++ b/erpnext/selling/doctype/quotation_item/quotation_item.json @@ -1,6 +1,6 @@ { "autoname": "QUOD/.#####", - "creation": "2013-03-07 11:42:57.000000", + "creation": "2013-03-07 11:42:57", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -231,17 +231,9 @@ "width": "100px" }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -353,9 +345,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:20:34.000000", + "modified": "2014-05-28 12:41:40.811916", "modified_by": "Administrator", "module": "Selling", "name": "Quotation Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/selling/doctype/sales_order_item/sales_order_item.json b/erpnext/selling/doctype/sales_order_item/sales_order_item.json index 9d0ae0e031..13ee085eef 100644 --- a/erpnext/selling/doctype/sales_order_item/sales_order_item.json +++ b/erpnext/selling/doctype/sales_order_item/sales_order_item.json @@ -1,6 +1,6 @@ { "autoname": "SOD/.#####", - "creation": "2013-03-07 11:42:58.000000", + "creation": "2013-03-07 11:42:58", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -217,17 +217,9 @@ "width": "100px" }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -439,9 +431,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:20:05.000000", + "modified": "2014-05-27 14:41:14.996650", "modified_by": "Administrator", "module": "Selling", "name": "Sales Order Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/selling/sales_common.js b/erpnext/selling/sales_common.js index 1e9643aeb8..b4841006e2 100644 --- a/erpnext/selling/sales_common.js +++ b/erpnext/selling/sales_common.js @@ -104,7 +104,8 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ }, customer: function() { - erpnext.utils.get_party_details(this.frm); + var me = this; + erpnext.utils.get_party_details(this.frm, null, null, function(){me.apply_pricing_rule()}); }, customer_address: function() { @@ -119,6 +120,14 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({ erpnext.utils.get_contact_details(this.frm); }, + sales_partner: function() { + this.apply_pricing_rule(); + }, + + campaign: function() { + this.apply_pricing_rule(); + }, + barcode: function(doc, cdt, cdn) { this.item_code(doc, cdt, cdn); }, diff --git a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json index e093def886..13307ef64a 100644 --- a/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json +++ b/erpnext/stock/doctype/delivery_note_item/delivery_note_item.json @@ -1,6 +1,6 @@ { "autoname": "DND/.#######", - "creation": "2013-04-22 13:15:44.000000", + "creation": "2013-04-22 13:15:44", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -225,17 +225,9 @@ "width": "100px" }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -437,9 +429,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:20:58.000000", + "modified": "2014-05-28 12:42:05.788579", "modified_by": "Administrator", "module": "Stock", "name": "Delivery Note Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json index 0c8100ce7d..548a7dacf1 100755 --- a/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json +++ b/erpnext/stock/doctype/purchase_receipt_item/purchase_receipt_item.json @@ -1,6 +1,6 @@ { "autoname": "GRND/.#######", - "creation": "2013-05-24 19:29:10.000000", + "creation": "2013-05-24 19:29:10", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -256,17 +256,9 @@ "width": "100px" }, { - "fieldname": "pricing_rule_for_price", + "fieldname": "pricing_rule", "fieldtype": "Link", - "label": "Pricing Rule For Price", - "options": "Pricing Rule", - "permlevel": 0, - "read_only": 1 - }, - { - "fieldname": "pricing_rule_for_discount", - "fieldtype": "Link", - "label": "Pricing Rule For Discount", + "label": "Pricing Rule", "options": "Pricing Rule", "permlevel": 0, "read_only": 1 @@ -553,9 +545,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-28 11:27:09.000000", + "modified": "2014-05-28 12:43:16.669040", "modified_by": "Administrator", "module": "Stock", "name": "Purchase Receipt Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index f9c7526a96..bd8cd3e939 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -68,7 +68,12 @@ def get_item_details(args): 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) + # update args with out, if key or value not exists + for key, value in out.iteritems(): + if args.get(key) is None: + args[key] = value + + out.update(apply_pricing_rule(args)) if args.get("doctype") in ("Sales Invoice", "Delivery Note"): if item_doc.has_serial_no == "Yes" and not args.serial_no: @@ -243,36 +248,50 @@ def get_pos_settings(company): 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) - all_pricing_rules = get_pricing_rules(args_dict) +@frappe.whitelist() +def apply_pricing_rule(args): + if isinstance(args, basestring): + args = json.loads(args) - rule_for_price = False - for rule_for in ["price", "discount_percentage"]: - pricing_rules = filter(lambda x: x[rule_for] > 0.0, all_pricing_rules) - if rule_for_price: - pricing_rules = filter(lambda x: not x["for_price_list"], pricing_rules) + args = frappe._dict(args) + out = frappe._dict() - pricing_rule = filter_pricing_rules(args_dict, pricing_rules) + if not args.get("item_group") or not args.get("brand"): + args.item_group, args.brand = frappe.db.get_value("Item", + args.item_code, ["item_group", "brand"]) - if pricing_rule: - if rule_for == "discount_percentage": - out["discount_percentage"] = pricing_rule["discount_percentage"] - out["pricing_rule_for_discount"] = pricing_rule["name"] - else: - out["base_price_list_rate"] = pricing_rule["price"] - out["price_list_rate"] = pricing_rule["price"] * \ - flt(args_dict.plc_conversion_rate) / flt(args_dict.conversion_rate) - out["pricing_rule_for_price"] = pricing_rule["name"] - rule_for_price = True + if not args.get("customer_group") or not args.get("territory"): + args.customer_group, args.territory = frappe.db.get_value("Customer", + args.customer, ["customer_group", "territory"]) -def get_pricing_rules(args_dict): + if not args.get("supplier_type"): + args.supplier_type = frappe.db.get_value("Supplier", args.supplier, "supplier_type") + + pricing_rules = get_pricing_rules(args) + pricing_rule = filter_pricing_rules(args, pricing_rules) + + if pricing_rule: + out.pricing_rule = pricing_rule.name + if pricing_rule.price_or_discount == "Price": + out.base_price_list_rate = pricing_rule.price + out.price_list_rate = pricing_rule.price*flt(args.plc_conversion_rate)/flt(args.conversion_rate) + out.base_rate = out.base_price_list_rate + out.rate = out.price_list_rate + out.discount_percentage = 0.0 + else: + out.discount_percentage = pricing_rule.discount_percentage + else: + out.pricing_rule = None + + return out + + +def get_pricing_rules(args): 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"]) + if args.get(field): + lft, rgt = frappe.db.get_value(doctype, args[field], ["lft", "rgt"]) parent_groups = frappe.db.sql_list("""select name from `tab%s` where lft<=%s and rgt>=%s""" % (doctype, '%s', '%s'), (lft, rgt)) @@ -284,8 +303,8 @@ def get_pricing_rules(args_dict): conditions = "" - for field in ["customer", "supplier", "supplier_type", "campaign", "sales_partner"]: - if args_dict.get(field): + for field in ["company", "customer", "supplier", "supplier_type", "campaign", "sales_partner"]: + if args.get(field): conditions += " and ifnull("+field+", '') in (%("+field+")s, '')" else: conditions += " and ifnull("+field+", '') = ''" @@ -297,8 +316,7 @@ def get_pricing_rules(args_dict): conditions += " and ifnull(for_price_list, '') in (%(price_list)s, '')" - - if args_dict.get("transaction_date"): + if args.get("transaction_date"): conditions += """ and %(transaction_date)s between ifnull(valid_from, '2000-01-01') and ifnull(valid_upto, '2500-12-31')""" @@ -307,13 +325,13 @@ def get_pricing_rules(args_dict): 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), - args_dict, as_dict=1) + args, as_dict=1) -def filter_pricing_rules(args_dict, pricing_rules): +def filter_pricing_rules(args, pricing_rules): # filter for qty - if pricing_rules and args_dict.get("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) + if pricing_rules and args.get("qty"): + pricing_rules = filter(lambda x: (args.qty>=flt(x.min_qty) + and (args.qty<=x.max_qty if x.max_qty else True)), pricing_rules) # find pricing rule with highest priority if pricing_rules: @@ -323,15 +341,19 @@ def filter_pricing_rules(args_dict, pricing_rules): # apply internal priority all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory", - "supplier", "supplier_type", "campaign", "for_price_list", "sales_partner"] + "supplier", "supplier_type", "campaign", "sales_partner"] if len(pricing_rules) > 1: 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): - pricing_rules = apply_internal_priority(pricing_rules, field_set, args_dict) + pricing_rules = apply_internal_priority(pricing_rules, field_set, args) break + if len(pricing_rules) > 1: + price_or_discount = list(set([d.price_or_discount for d in pricing_rules])) + if len(price_or_discount) == 1 and price_or_discount[0] == "Discount Percentage": + pricing_rules = filter(lambda x: x.for_price_list==args.price_list, pricing_rules) if len(pricing_rules) > 1: frappe.throw(_("Multiple Price Rule exists with same criteria, please resolve \ @@ -350,11 +372,11 @@ def if_all_rules_same(pricing_rules, fields): return all_rules_same -def apply_internal_priority(pricing_rules, field_set, args_dict): +def apply_internal_priority(pricing_rules, field_set, args): filtered_rules = [] for field in field_set: - if args_dict.get(field): - filtered_rules = filter(lambda x: x[field]==args_dict[field], pricing_rules) + if args.get(field): + filtered_rules = filter(lambda x: x[field]==args[field], pricing_rules) if filtered_rules: break return filtered_rules or pricing_rules From ea4aa04cc485dac2b24119b8295e3569bab512b5 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 28 May 2014 12:56:28 +0530 Subject: [PATCH 03/21] Search query for account cleanup --- .../accounts_payable/accounts_payable.js | 2 +- .../accounts_receivable.js | 2 +- .../bank_clearance_summary.js | 2 +- .../bank_reconciliation_statement.js | 2 +- .../item_wise_purchase_register.js | 2 +- .../item_wise_sales_register.js | 2 +- .../payment_period_based_on_invoice_date.js | 2 +- .../purchase_register/purchase_register.js | 2 +- .../report/sales_register/sales_register.js | 2 +- erpnext/accounts/utils.py | 24 ------------------- erpnext/controllers/queries.py | 12 ++++++++++ 11 files changed, 21 insertions(+), 33 deletions(-) diff --git a/erpnext/accounts/report/accounts_payable/accounts_payable.js b/erpnext/accounts/report/accounts_payable/accounts_payable.js index 09fbd3ef28..300c2285e7 100644 --- a/erpnext/accounts/report/accounts_payable/accounts_payable.js +++ b/erpnext/accounts/report/accounts_payable/accounts_payable.js @@ -18,7 +18,7 @@ frappe.query_reports["Accounts Payable"] = { "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js index 1cf0941e0f..304c21bebb 100644 --- a/erpnext/accounts/report/accounts_receivable/accounts_receivable.js +++ b/erpnext/accounts/report/accounts_receivable/accounts_receivable.js @@ -18,7 +18,7 @@ frappe.query_reports["Accounts Receivable"] = { "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js index abeaba85e5..c28ba70a25 100644 --- a/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js +++ b/erpnext/accounts/report/bank_clearance_summary/bank_clearance_summary.js @@ -23,7 +23,7 @@ frappe.query_reports["Bank Clearance Summary"] = { "options": "Account", "get_query": function() { return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": [ ['Account', 'account_type', 'in', 'Bank, Cash'], ['Account', 'group_or_ledger', '=', 'Ledger'], diff --git a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js index 4bdcd9e0c7..adc9ca2500 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js +++ b/erpnext/accounts/report/bank_reconciliation_statement/bank_reconciliation_statement.js @@ -11,7 +11,7 @@ frappe.query_reports["Bank Reconciliation Statement"] = { "reqd": 1, "get_query": function() { return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": [ ['Account', 'account_type', 'in', 'Bank, Cash'], ['Account', 'group_or_ledger', '=', 'Ledger'], diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js index 402f894d3f..13c0edc0a7 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.js @@ -30,7 +30,7 @@ frappe.query_reports["Item-wise Purchase Register"] = { "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js index 3264da7155..79b1785dec 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.js @@ -24,7 +24,7 @@ frappe.query_reports["Item-wise Sales Register"] = frappe.query_reports["Sales R "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js index b0833b54a7..bff3f70a34 100644 --- a/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js +++ b/erpnext/accounts/report/payment_period_based_on_invoice_date/payment_period_based_on_invoice_date.js @@ -29,7 +29,7 @@ frappe.query_reports["Payment Period Based On Invoice Date"] = { options: "Account", get_query: function() { return { - query: "erpnext.accounts.utils.get_account_list", + query: "erpnext.controllers.queries.get_account_list", filters: { "report_type": "Balance Sheet", company: frappe.query_report.filters_by_name.company.get_value() diff --git a/erpnext/accounts/report/purchase_register/purchase_register.js b/erpnext/accounts/report/purchase_register/purchase_register.js index 7e999dee70..a1a41a5ee0 100644 --- a/erpnext/accounts/report/purchase_register/purchase_register.js +++ b/erpnext/accounts/report/purchase_register/purchase_register.js @@ -24,7 +24,7 @@ frappe.query_reports["Purchase Register"] = { "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/report/sales_register/sales_register.js b/erpnext/accounts/report/sales_register/sales_register.js index 0cc48a6489..ac30562fd7 100644 --- a/erpnext/accounts/report/sales_register/sales_register.js +++ b/erpnext/accounts/report/sales_register/sales_register.js @@ -24,7 +24,7 @@ frappe.query_reports["Sales Register"] = { "get_query": function() { var company = frappe.query_report.filters_by_name.company.get_value(); return { - "query": "erpnext.accounts.utils.get_account_list", + "query": "erpnext.controllers.queries.get_account_list", "filters": { "report_type": "Balance Sheet", "company": company, diff --git a/erpnext/accounts/utils.py b/erpnext/accounts/utils.py index 75825fcb7e..160514bfe5 100644 --- a/erpnext/accounts/utils.py +++ b/erpnext/accounts/utils.py @@ -195,30 +195,6 @@ def update_against_doc(d, jv_obj): jv_obj.ignore_validate_update_after_submit = True jv_obj.save() -def get_account_list(doctype, txt, searchfield, start, page_len, filters): - filters = add_group_or_ledger_filter("Account", filters) - - return frappe.widgets.reportview.execute("Account", filters = filters, - fields = ["name", "parent_account"], - limit_start=start, limit_page_length=page_len, as_list=True) - -def get_cost_center_list(doctype, txt, searchfield, start, page_len, filters): - filters = add_group_or_ledger_filter("Cost Center", filters) - - return frappe.widgets.reportview.execute("Cost Center", filters = filters, - fields = ["name", "parent_cost_center"], - limit_start=start, limit_page_length=page_len, as_list=True) - -def add_group_or_ledger_filter(doctype, filters): - if isinstance(filters, dict): - if not filters.get("group_or_ledger"): - filters["group_or_ledger"] = "Ledger" - elif isinstance(filters, list): - if "group_or_ledger" not in [d[0] for d in filters]: - filters.append([doctype, "group_or_ledger", "=", "Ledger"]) - - return filters - def remove_against_link_from_jv(ref_type, ref_no, against_field): linked_jv = frappe.db.sql_list("""select parent from `tabJournal Voucher Detail` where `%s`=%s and docstatus < 2""" % (against_field, "%s"), (ref_no)) diff --git a/erpnext/controllers/queries.py b/erpnext/controllers/queries.py index 5cc7f6448c..a30cde72a5 100644 --- a/erpnext/controllers/queries.py +++ b/erpnext/controllers/queries.py @@ -234,3 +234,15 @@ def get_batch_no(doctype, txt, searchfield, start, page_len, filters): 'posting_date': filters['posting_date'], 'txt': "%%%s%%" % txt, 'mcond':get_match_cond(doctype),'start': start, 'page_len': page_len}) + +def get_account_list(doctype, txt, searchfield, start, page_len, filters): + if isinstance(filters, dict): + if not filters.get("group_or_ledger"): + filters["group_or_ledger"] = "Ledger" + elif isinstance(filters, list): + if "group_or_ledger" not in [d[0] for d in filters]: + filters.append(["Account", "group_or_ledger", "=", "Ledger"]) + + return frappe.widgets.reportview.execute("Account", filters = filters, + fields = ["name", "parent_account"], + limit_start=start, limit_page_length=page_len, as_list=True) From 8de61559b01fa468548dff3e6c41d59c4f542d58 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 28 May 2014 15:12:36 +0530 Subject: [PATCH 04/21] Minor fixes in sales / purchase analytics. Fixes #1701 --- .../purchase_analytics/purchase_analytics.js | 98 +++++++++---------- .../page/sales_analytics/sales_analytics.js | 88 ++++++++--------- 2 files changed, 93 insertions(+), 93 deletions(-) diff --git a/erpnext/buying/page/purchase_analytics/purchase_analytics.js b/erpnext/buying/page/purchase_analytics/purchase_analytics.js index f695a4982f..2e29d01a0a 100644 --- a/erpnext/buying/page/purchase_analytics/purchase_analytics.js +++ b/erpnext/buying/page/purchase_analytics/purchase_analytics.js @@ -1,18 +1,18 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -frappe.pages['purchase-analytics'].onload = function(wrapper) { +frappe.pages['purchase-analytics'].onload = function(wrapper) { frappe.ui.make_app_page({ parent: wrapper, title: __('Purchase Analytics'), single_column: true - }); - + }); + new erpnext.PurchaseAnalytics(wrapper); - + wrapper.appframe.add_module_icon("Buying") - + } erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ @@ -22,19 +22,19 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ page: wrapper, parent: $(wrapper).find('.layout-main'), appframe: wrapper.appframe, - doctypes: ["Item", "Item Group", "Supplier", "Supplier Type", "Company", "Fiscal Year", - "Purchase Invoice", "Purchase Invoice Item", - "Purchase Order", "Purchase Order Item[Purchase Analytics]", + doctypes: ["Item", "Item Group", "Supplier", "Supplier Type", "Company", "Fiscal Year", + "Purchase Invoice", "Purchase Invoice Item", + "Purchase Order", "Purchase Order Item[Purchase Analytics]", "Purchase Receipt", "Purchase Receipt Item[Purchase Analytics]"], tree_grid: { show: true } }); - + this.tree_grids = { "Supplier Type": { label: __("Supplier Type / Supplier"), - show: true, + show: true, item_key: "supplier", - parent_field: "parent_supplier_type", + parent_field: "parent_supplier_type", formatter: function(item) { // return repl('%(value)s', { // value: item.name, @@ -45,29 +45,29 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ }, "Supplier": { label: __("Supplier"), - show: false, + show: false, item_key: "supplier", formatter: function(item) { return item.name; } - }, + }, "Item Group": { label: "Item", - show: true, - parent_field: "parent_item_group", + show: true, + parent_field: "parent_item_group", item_key: "item_code", formatter: function(item) { return item.name; } - }, + }, "Item": { label: "Item", - show: false, + show: false, item_key: "item_code", formatter: function(item) { return item.name; } - }, + }, } }, setup_columns: function() { @@ -82,24 +82,24 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ formatter: this.currency_formatter} ]; - this.make_date_range_columns(); + this.make_date_range_columns(); this.columns = std_columns.concat(this.columns); }, filters: [ - {fieldtype:"Select", label: __("Tree Type"), options:["Supplier Type", "Supplier", + {fieldtype:"Select", label: __("Tree Type"), options:["Supplier Type", "Supplier", "Item Group", "Item"], filter: function(val, item, opts, me) { return me.apply_zero_filter(val, item, opts, me); }}, - {fieldtype:"Select", label: __("Based On"), options:["Purchase Invoice", + {fieldtype:"Select", label: __("Based On"), options:["Purchase Invoice", "Purchase Order", "Purchase Receipt"]}, {fieldtype:"Select", label: __("Value or Qty"), options:["Value", "Quantity"]}, - {fieldtype:"Select", label: __("Company"), link:"Company", + {fieldtype:"Select", label: __("Company"), link:"Company", default_value: "Select Company..."}, {fieldtype:"Date", label: __("From Date")}, {fieldtype:"Label", label: __("To")}, {fieldtype:"Date", label: __("To Date")}, - {fieldtype:"Select", label: __("Range"), + {fieldtype:"Select", label: __("Range"), options:["Daily", "Weekly", "Monthly", "Quarterly", "Yearly"]}, {fieldtype:"Button", label: __("Refresh"), icon:"icon-refresh icon-white"}, {fieldtype:"Button", label: __("Reset Filters"), icon: "icon-filter"} @@ -107,10 +107,10 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ setup_filters: function() { var me = this; this._super(); - + this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on", "company"]); - this.show_zero_check() + this.show_zero_check() this.setup_plot_check(); }, init_filter_values: function() { @@ -124,34 +124,34 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ // Add 'All Supplier Types' Supplier Type // (Supplier / Item are not mandatory!!) // Set parent supplier type for tree view - + $.each(frappe.report_dump.data["Supplier Type"], function(i, v) { v['parent_supplier_type'] = "All Supplier Types" }) - + frappe.report_dump.data["Supplier Type"] = [{ - name: __("All Supplier Types"), + name: __("All Supplier Types"), id: "All Supplier Types", }].concat(frappe.report_dump.data["Supplier Type"]); - + frappe.report_dump.data["Supplier"].push({ - name: __("Not Set"), + name: __("Not Set"), parent_supplier_type: "All Supplier Types", id: "Not Set", }); frappe.report_dump.data["Item"].push({ - name: __("Not Set"), + name: __("Not Set"), parent_item_group: "All Item Groups", id: "Not Set", }); } - + if (!this.tl || !this.tl[this.based_on]) { this.make_transaction_list(this.based_on, this.based_on + " Item"); } - - + + if(!this.data || me.item_type != me.tree_type) { if(me.tree_type=='Supplier') { var items = frappe.report_dump.data["Supplier"]; @@ -177,20 +177,20 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ me.parent_map[d.name] = d[me.tree_grid.parent_field]; } me.reset_item_values(d); - }); - + }); + this.set_indent(); - + } else { // otherwise, only reset values $.each(this.data, function(i, d) { me.reset_item_values(d); }); } - + this.prepare_balances(); if(me.tree_grid.show) { - this.set_totals(false); + this.set_totals(false); this.update_groups(); } else { this.set_totals(true); @@ -201,14 +201,14 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ var from_date = dateutil.str_to_obj(this.from_date); var to_date = dateutil.str_to_obj(this.to_date); var is_val = this.value_or_qty == 'Value'; - + $.each(this.tl[this.based_on], function(i, tl) { - if (me.is_default('company') ? true : tl.company === me.company) { + if (me.is_default('company') ? true : tl.company === me.company) { var posting_date = dateutil.str_to_obj(tl.posting_date); if (posting_date >= from_date && posting_date <= to_date) { - var item = me.item_by_name[tl[me.tree_grid.item_key]] || + var item = me.item_by_name[tl[me.tree_grid.item_key]] || me.item_by_name['Not Set']; - item[me.column_map[tl.posting_date].field] += (is_val ? tl.amount : tl.qty); + item[me.column_map[tl.posting_date].field] += (is_val ? tl.base_amount : tl.qty); } } }); @@ -220,10 +220,10 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ var parent = me.parent_map[item.name]; while(parent) { parent_group = me.item_by_name[parent]; - + $.each(me.columns, function(c, col) { if (col.formatter == me.currency_formatter) { - parent_group[col.field] = + parent_group[col.field] = flt(parent_group[col.field]) + flt(item[col.field]); } @@ -235,10 +235,10 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ set_totals: function(sort) { var me = this; var checked = false; - $.each(this.data, function(i, d) { + $.each(this.data, function(i, d) { d.total = 0.0; $.each(me.columns, function(i, col) { - if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") + if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") d.total += d[col.field]; if(d.checked) checked = true; }) @@ -251,7 +251,7 @@ erpnext.PurchaseAnalytics = frappe.views.TreeGridReport.extend({ } }, get_plot_points: function(item, col, idx) { - return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]], + return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]], [dateutil.user_to_obj(col.name).getTime(), item[col.field]]]; } -}); \ No newline at end of file +}); diff --git a/erpnext/selling/page/sales_analytics/sales_analytics.js b/erpnext/selling/page/sales_analytics/sales_analytics.js index 25c8f80497..2117370285 100644 --- a/erpnext/selling/page/sales_analytics/sales_analytics.js +++ b/erpnext/selling/page/sales_analytics/sales_analytics.js @@ -1,17 +1,17 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -frappe.pages['sales-analytics'].onload = function(wrapper) { +frappe.pages['sales-analytics'].onload = function(wrapper) { frappe.ui.make_app_page({ parent: wrapper, title: __('Sales Analytics'), single_column: true }); new erpnext.SalesAnalytics(wrapper); - + wrapper.appframe.add_module_icon("Selling") - + } erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ @@ -21,55 +21,55 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ page: wrapper, parent: $(wrapper).find('.layout-main'), appframe: wrapper.appframe, - doctypes: ["Item", "Item Group", "Customer", "Customer Group", "Company", "Territory", - "Fiscal Year", "Sales Invoice", "Sales Invoice Item", - "Sales Order", "Sales Order Item[Sales Analytics]", + doctypes: ["Item", "Item Group", "Customer", "Customer Group", "Company", "Territory", + "Fiscal Year", "Sales Invoice", "Sales Invoice Item", + "Sales Order", "Sales Order Item[Sales Analytics]", "Delivery Note", "Delivery Note Item[Sales Analytics]"], tree_grid: { show: true } }); - + this.tree_grids = { "Customer Group": { label: __("Customer Group / Customer"), - show: true, + show: true, item_key: "customer", - parent_field: "parent_customer_group", + parent_field: "parent_customer_group", formatter: function(item) { return item.name; } }, "Customer": { label: __("Customer"), - show: false, + show: false, item_key: "customer", formatter: function(item) { return item.name; } - }, + }, "Item Group": { label: __("Item"), - show: true, - parent_field: "parent_item_group", + show: true, + parent_field: "parent_item_group", item_key: "item_code", formatter: function(item) { return item.name; } - }, + }, "Item": { label: __("Item"), - show: false, + show: false, item_key: "item_code", formatter: function(item) { return item.name; } - }, + }, "Territory": { label: __("Territory / Customer"), - show: true, + show: true, item_key: "customer", - parent_field: "parent_territory", + parent_field: "parent_territory", formatter: function(item) { return item.name; } - } + } } }, setup_columns: function() { @@ -84,24 +84,24 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ formatter: this.currency_formatter} ]; - this.make_date_range_columns(); + this.make_date_range_columns(); this.columns = std_columns.concat(this.columns); }, filters: [ - {fieldtype:"Select", fieldname: "tree_type", label: __("Tree Type"), options:["Customer Group", "Customer", + {fieldtype:"Select", fieldname: "tree_type", label: __("Tree Type"), options:["Customer Group", "Customer", "Item Group", "Item", "Territory"], filter: function(val, item, opts, me) { return me.apply_zero_filter(val, item, opts, me); }}, - {fieldtype:"Select", fieldname: "based_on", label: __("Based On"), options:["Sales Invoice", + {fieldtype:"Select", fieldname: "based_on", label: __("Based On"), options:["Sales Invoice", "Sales Order", "Delivery Note"]}, {fieldtype:"Select", fieldname: "value_or_qty", label: __("Value or Qty"), options:["Value", "Quantity"]}, - {fieldtype:"Select", fieldname: "company", label: __("Company"), link:"Company", + {fieldtype:"Select", fieldname: "company", label: __("Company"), link:"Company", default_value: "Select Company..."}, {fieldtype:"Date", fieldname: "from_date", label: __("From Date")}, {fieldtype:"Label", fieldname: "to", label: __("To")}, {fieldtype:"Date", fieldname: "to_date", label: __("To Date")}, - {fieldtype:"Select", fieldname: "range", label: __("Range"), + {fieldtype:"Select", fieldname: "range", label: __("Range"), options:["Daily", "Weekly", "Monthly", "Quarterly", "Yearly"]}, {fieldtype:"Button", fieldname: "refresh", label: __("Refresh"), icon:"icon-refresh"}, {fieldtype:"Button", fieldname: "reset_filters", label: __("Reset Filters"), icon:"icon-filter"} @@ -109,10 +109,10 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ setup_filters: function() { var me = this; this._super(); - + this.trigger_refresh_on_change(["value_or_qty", "tree_type", "based_on", "company"]); - this.show_zero_check() + this.show_zero_check() this.setup_plot_check(); }, init_filter_values: function() { @@ -125,14 +125,14 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ // add 'Not Set' Customer & Item // (Customer / Item are not mandatory!!) frappe.report_dump.data["Customer"].push({ - name: "Not Set", + name: "Not Set", parent_customer_group: "All Customer Groups", parent_territory: "All Territories", id: "Not Set", }); frappe.report_dump.data["Item"].push({ - name: "Not Set", + name: "Not Set", parent_item_group: "All Item Groups", id: "Not Set", }); @@ -141,7 +141,7 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ if (!this.tl || !this.tl[this.based_on]) { this.make_transaction_list(this.based_on, this.based_on + " Item"); } - + if(!this.data || me.item_type != me.tree_type) { if(me.tree_type=='Customer') { var items = frappe.report_dump.data["Customer"]; @@ -159,7 +159,7 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ me.parent_map = {}; me.item_by_name = {}; me.data = []; - + $.each(items, function(i, v) { var d = copy_dict(v); @@ -169,20 +169,20 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ me.parent_map[d.name] = d[me.tree_grid.parent_field]; } me.reset_item_values(d); - }); - + }); + this.set_indent(); - + } else { // otherwise, only reset values $.each(this.data, function(i, d) { me.reset_item_values(d); }); } - + this.prepare_balances(); if(me.tree_grid.show) { - this.set_totals(false); + this.set_totals(false); this.update_groups(); } else { this.set_totals(true); @@ -194,14 +194,14 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ var from_date = dateutil.str_to_obj(this.from_date); var to_date = dateutil.str_to_obj(this.to_date); var is_val = this.value_or_qty == 'Value'; - + $.each(this.tl[this.based_on], function(i, tl) { - if (me.is_default('company') ? true : tl.company === me.company) { + if (me.is_default('company') ? true : tl.company === me.company) { var posting_date = dateutil.str_to_obj(tl.posting_date); if (posting_date >= from_date && posting_date <= to_date) { - var item = me.item_by_name[tl[me.tree_grid.item_key]] || + var item = me.item_by_name[tl[me.tree_grid.item_key]] || me.item_by_name['Not Set']; - item[me.column_map[tl.posting_date].field] += (is_val ? tl.amount : tl.qty); + item[me.column_map[tl.posting_date].field] += (is_val ? tl.base_amount : tl.qty); } } }); @@ -213,10 +213,10 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ var parent = me.parent_map[item.name]; while(parent) { parent_group = me.item_by_name[parent]; - + $.each(me.columns, function(c, col) { if (col.formatter == me.currency_formatter) { - parent_group[col.field] = + parent_group[col.field] = flt(parent_group[col.field]) + flt(item[col.field]); } @@ -228,10 +228,10 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ set_totals: function(sort) { var me = this; var checked = false; - $.each(this.data, function(i, d) { + $.each(this.data, function(i, d) { d.total = 0.0; $.each(me.columns, function(i, col) { - if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") + if(col.formatter==me.currency_formatter && !col.hidden && col.field!="total") d.total += d[col.field]; if(d.checked) checked = true; }) @@ -244,7 +244,7 @@ erpnext.SalesAnalytics = frappe.views.TreeGridReport.extend({ } }, get_plot_points: function(item, col, idx) { - return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]], + return [[dateutil.str_to_obj(col.id).getTime(), item[col.field]], [dateutil.user_to_obj(col.name).getTime(), item[col.field]]]; } }); From ccb9826afd4ba0001dc6ad3916f7d5d9e2e3f652 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 28 May 2014 15:46:54 +0530 Subject: [PATCH 05/21] pricing list tets case fixes --- erpnext/accounts/doctype/pricing_rule/pricing_rule.json | 2 +- .../accounts/doctype/pricing_rule/test_pricing_rule.py | 2 +- erpnext/stock/get_item_details.py | 8 +++++--- 3 files changed, 7 insertions(+), 5 deletions(-) diff --git a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json index 5fbb08f1cf..e023dd08c3 100644 --- a/erpnext/accounts/doctype/pricing_rule/pricing_rule.json +++ b/erpnext/accounts/doctype/pricing_rule/pricing_rule.json @@ -223,7 +223,7 @@ "icon": "icon-gift", "idx": 1, "istable": 0, - "modified": "2014-05-27 15:14:34.849671", + "modified": "2014-05-28 15:36:29.403659", "modified_by": "Administrator", "module": "Accounts", "name": "Pricing Rule", diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 003c6e66b4..1c53902076 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -72,7 +72,7 @@ class TestPricingRule(unittest.TestCase): frappe.db.sql("update `tabPricing Rule` set priority=NULL where campaign='_Test Campaign'") from erpnext.stock.get_item_details import MultiplePricingRuleConflict - self.assertRaises (MultiplePricingRuleConflict, get_item_details, args) + self.assertRaises(MultiplePricingRuleConflict, get_item_details, args) args.item_code = "_Test Item 2" details = get_item_details(args) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index bd8cd3e939..fe62070640 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -260,11 +260,11 @@ def apply_pricing_rule(args): args.item_group, args.brand = frappe.db.get_value("Item", args.item_code, ["item_group", "brand"]) - if not args.get("customer_group") or not args.get("territory"): + if args.get("customer") and (not args.get("customer_group") or not args.get("territory")): args.customer_group, args.territory = frappe.db.get_value("Customer", args.customer, ["customer_group", "territory"]) - if not args.get("supplier_type"): + if args.get("supplier") and not args.get("supplier_type"): args.supplier_type = frappe.db.get_value("Supplier", args.supplier, "supplier_type") pricing_rules = get_pricing_rules(args) @@ -350,10 +350,12 @@ def filter_pricing_rules(args, pricing_rules): if if_all_rules_same(pricing_rules, remaining_fields): pricing_rules = apply_internal_priority(pricing_rules, field_set, args) break + if len(pricing_rules) > 1: price_or_discount = list(set([d.price_or_discount for d in pricing_rules])) if len(price_or_discount) == 1 and price_or_discount[0] == "Discount Percentage": - pricing_rules = filter(lambda x: x.for_price_list==args.price_list, pricing_rules) + pricing_rules = filter(lambda x: x.for_price_list==args.price_list, pricing_rules) \ + or pricing_rules if len(pricing_rules) > 1: frappe.throw(_("Multiple Price Rule exists with same criteria, please resolve \ From e7546e230572e5cc6c5aae95e6c0228489b3b500 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 28 May 2014 16:25:54 +0530 Subject: [PATCH 06/21] SMS Settings added in setup and selling module page. Fixes #1693 --- erpnext/config/selling.py | 5 +++++ erpnext/config/setup.py | 5 +++++ 2 files changed, 10 insertions(+) diff --git a/erpnext/config/selling.py b/erpnext/config/selling.py index 4d3e059188..bb70ac9607 100644 --- a/erpnext/config/selling.py +++ b/erpnext/config/selling.py @@ -156,6 +156,11 @@ def get_data(): "name": "Industry Type", "description": _("Track Leads by Industry Type.") }, + { + "type": "doctype", + "name": "SMS Settings", + "description": _("Setup SMS gateway settings") + }, ] }, { diff --git a/erpnext/config/setup.py b/erpnext/config/setup.py index e538de5ab3..66b44e28c5 100644 --- a/erpnext/config/setup.py +++ b/erpnext/config/setup.py @@ -83,6 +83,11 @@ def get_data(): "name": "Jobs Email Settings", "description": _("Setup incoming server for jobs email id. (e.g. jobs@example.com)") }, + { + "type": "doctype", + "name": "SMS Settings", + "description": _("Setup SMS gateway settings") + }, ] }, { From 47a8670d378e7fb72bf2356aba574e256243d74b Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 28 May 2014 17:03:28 +0530 Subject: [PATCH 07/21] pricing rule testcase fixes --- erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py | 2 +- erpnext/stock/get_item_details.py | 1 + 2 files changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py index 1c53902076..b17c995298 100644 --- a/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py +++ b/erpnext/accounts/doctype/pricing_rule/test_pricing_rule.py @@ -20,6 +20,7 @@ class TestPricingRule(unittest.TestCase): "price_or_discount": "Discount Percentage", "price": 0, "discount_percentage": 10, + "company": "_Test Company" } frappe.get_doc(test_record.copy()).insert() @@ -36,7 +37,6 @@ class TestPricingRule(unittest.TestCase): "transaction_type": "selling", "customer": "_Test Customer", }) - details = get_item_details(args) self.assertEquals(details.get("discount_percentage"), 10) diff --git a/erpnext/stock/get_item_details.py b/erpnext/stock/get_item_details.py index fe62070640..4a295d8242 100644 --- a/erpnext/stock/get_item_details.py +++ b/erpnext/stock/get_item_details.py @@ -268,6 +268,7 @@ def apply_pricing_rule(args): args.supplier_type = frappe.db.get_value("Supplier", args.supplier, "supplier_type") pricing_rules = get_pricing_rules(args) + pricing_rule = filter_pricing_rules(args, pricing_rules) if pricing_rule: From d0605443fb6cbf4b888417804aa745b64434d2ac Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 28 May 2014 17:11:22 +0530 Subject: [PATCH 08/21] removed print statement --- erpnext/stock/doctype/item/item.py | 1 - 1 file changed, 1 deletion(-) diff --git a/erpnext/stock/doctype/item/item.py b/erpnext/stock/doctype/item/item.py index 104f905383..6d6db94f30 100644 --- a/erpnext/stock/doctype/item/item.py +++ b/erpnext/stock/doctype/item/item.py @@ -137,7 +137,6 @@ class Item(WebsiteGenerator): bom = frappe.db.sql("""select name from `tabBOM` where item = %s and is_active = 1""", (self.name,)) if bom and bom[0][0]: - print self.name frappe.throw(_("""Allow Bill of Materials should be 'Yes'. Because one or many active BOMs present for this item""")) def fill_customer_code(self): From 9bc9b8795ba720c6c1619b383112f9831e2874fa Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 29 May 2014 14:18:40 +0530 Subject: [PATCH 09/21] Fixes in stock reconciliation --- .../doctype/stock_reconciliation/stock_reconciliation.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py index 35030a6a78..78cf194cc2 100644 --- a/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py +++ b/erpnext/stock/doctype/stock_reconciliation/stock_reconciliation.py @@ -11,8 +11,11 @@ from erpnext.stock.stock_ledger import update_entries_after from erpnext.controllers.stock_controller import StockController class StockReconciliation(StockController): - def validate(self): + def __init__(self, arg1, arg2=None): + super(StockReconciliation, self).__init__(arg1, arg2) self.head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"] + + def validate(self): self.entries = [] self.validate_data() @@ -300,4 +303,5 @@ class StockReconciliation(StockController): @frappe.whitelist() def upload(): from frappe.utils.datautils import read_csv_content_from_uploaded_file - return read_csv_content_from_uploaded_file() + csv_content = read_csv_content_from_uploaded_file() + return filter(lambda x: x and any(x), csv_content) From c3cbe2a30ca1d3fdd9762d0fb7ed41f0971f0639 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 29 May 2014 14:19:32 +0530 Subject: [PATCH 10/21] minor fixes in sales invoice validation --- erpnext/controllers/accounts_controller.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 683f72b0f2..1f2e3b2699 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -415,7 +415,7 @@ class AccountsController(TransactionBase): if total_billed_amt - max_allowed_amt > 0.01: reduce_by = total_billed_amt - max_allowed_amt - frappe.throw(_("Cannot overbill for Item {0} in row {0} more than {1}. To allow overbilling, please set in 'Setup' > 'Global Defaults'").format(item.item_code, item.row, max_allowed_amt)) + frappe.throw(_("Cannot overbill for Item {0} in row {0} more than {1}. To allow overbilling, please set in 'Setup' > 'Global Defaults'").format(item.item_code, item.idx, max_allowed_amt)) def get_company_default(self, fieldname): from erpnext.accounts.utils import get_company_default From 732a7e81a0ae450f1f0342bb6c8e8072d24881f3 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 29 May 2014 15:42:23 +0530 Subject: [PATCH 11/21] Incoming rate in stock ledger and valuation rate in stock balance report. Fixes #1706 --- erpnext/startup/report_data_map.py | 32 ++++---- .../stock/page/stock_balance/stock_balance.js | 79 ++++++++++--------- .../stock/page/stock_ledger/stock_ledger.js | 54 ++++++------- .../stock/report/stock_ledger/stock_ledger.py | 22 +++--- 4 files changed, 97 insertions(+), 90 deletions(-) diff --git a/erpnext/startup/report_data_map.py b/erpnext/startup/report_data_map.py index e614c71ae0..ce71310ad9 100644 --- a/erpnext/startup/report_data_map.py +++ b/erpnext/startup/report_data_map.py @@ -18,14 +18,14 @@ data_map = { # Accounts "Account": { - "columns": ["name", "parent_account", "lft", "rgt", "report_type", + "columns": ["name", "parent_account", "lft", "rgt", "report_type", "company", "group_or_ledger"], "conditions": ["docstatus < 2"], "order_by": "lft", "links": { "company": ["Company", "name"], } - + }, "Cost Center": { "columns": ["name", "lft", "rgt"], @@ -33,7 +33,7 @@ data_map = { "order_by": "lft" }, "GL Entry": { - "columns": ["name", "account", "posting_date", "cost_center", "debit", "credit", + "columns": ["name", "account", "posting_date", "cost_center", "debit", "credit", "is_opening", "company", "voucher_type", "voucher_no", "remarks"], "order_by": "posting_date, account", "links": { @@ -45,8 +45,8 @@ data_map = { # Stock "Item": { - "columns": ["name", "if(item_name=name, '', item_name) as item_name", "description", - "item_group as parent_item_group", "stock_uom", "brand", "valuation_method", + "columns": ["name", "if(item_name=name, '', item_name) as item_name", "description", + "item_group as parent_item_group", "stock_uom", "brand", "valuation_method", "re_order_level", "re_order_qty"], # "conditions": ["docstatus < 2"], "order_by": "name", @@ -76,7 +76,7 @@ data_map = { "order_by": "name" }, "Stock Ledger Entry": { - "columns": ["name", "posting_date", "posting_time", "item_code", "warehouse", + "columns": ["name", "posting_date", "posting_time", "item_code", "warehouse", "actual_qty as qty", "voucher_type", "voucher_no", "project", "ifnull(incoming_rate,0) as incoming_rate", "stock_uom", "serial_no"], "order_by": "posting_date, posting_time, name", @@ -98,8 +98,8 @@ data_map = { "order_by": "posting_date, posting_time, name", }, "Production Order": { - "columns": ["name", "production_item as item_code", - "(ifnull(qty, 0) - ifnull(produced_qty, 0)) as qty", + "columns": ["name", "production_item as item_code", + "(ifnull(qty, 0) - ifnull(produced_qty, 0)) as qty", "fg_warehouse as warehouse"], "conditions": ["docstatus=1", "status != 'Stopped'", "ifnull(fg_warehouse, '')!=''", "ifnull(qty, 0) > ifnull(produced_qty, 0)"], @@ -109,7 +109,7 @@ data_map = { }, }, "Material Request Item": { - "columns": ["item.name as name", "item_code", "warehouse", + "columns": ["item.name as name", "item_code", "warehouse", "(ifnull(qty, 0) - ifnull(ordered_qty, 0)) as qty"], "from": "`tabMaterial Request Item` item, `tabMaterial Request` main", "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", @@ -120,21 +120,21 @@ data_map = { }, }, "Purchase Order Item": { - "columns": ["item.name as name", "item_code", "warehouse", + "columns": ["item.name as name", "item_code", "warehouse", "(ifnull(qty, 0) - ifnull(received_qty, 0)) as qty"], "from": "`tabPurchase Order Item` item, `tabPurchase Order` main", - "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", + "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", "ifnull(warehouse, '')!=''", "ifnull(qty, 0) > ifnull(received_qty, 0)"], "links": { "item_code": ["Item", "name"], "warehouse": ["Warehouse", "name"] }, }, - + "Sales Order Item": { "columns": ["item.name as name", "item_code", "(ifnull(qty, 0) - ifnull(delivered_qty, 0)) as qty", "warehouse"], "from": "`tabSales Order Item` item, `tabSales Order` main", - "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", + "conditions": ["item.parent = main.name", "main.docstatus=1", "main.status != 'Stopped'", "ifnull(warehouse, '')!=''", "ifnull(qty, 0) > ifnull(delivered_qty, 0)"], "links": { "item_code": ["Item", "name"], @@ -144,7 +144,7 @@ data_map = { # Sales "Customer": { - "columns": ["name", "if(customer_name=name, '', customer_name) as customer_name", + "columns": ["name", "if(customer_name=name, '', customer_name) as customer_name", "customer_group as parent_customer_group", "territory as parent_territory"], "conditions": ["docstatus < 2"], "order_by": "name", @@ -218,7 +218,7 @@ data_map = { } }, "Supplier": { - "columns": ["name", "if(supplier_name=name, '', supplier_name) as supplier_name", + "columns": ["name", "if(supplier_name=name, '', supplier_name) as supplier_name", "supplier_type as parent_supplier_type"], "conditions": ["docstatus < 2"], "order_by": "name", @@ -291,5 +291,5 @@ data_map = { "conditions": ["docstatus < 2"], "order_by": "creation" } - + } diff --git a/erpnext/stock/page/stock_balance/stock_balance.js b/erpnext/stock/page/stock_balance/stock_balance.js index dbd8830774..18f79169a9 100644 --- a/erpnext/stock/page/stock_balance/stock_balance.js +++ b/erpnext/stock/page/stock_balance/stock_balance.js @@ -3,18 +3,18 @@ frappe.require("assets/erpnext/js/stock_analytics.js"); -frappe.pages['stock-balance'].onload = function(wrapper) { +frappe.pages['stock-balance'].onload = function(wrapper) { frappe.ui.make_app_page({ parent: wrapper, title: __('Stock Balance'), single_column: true }); - + new erpnext.StockBalance(wrapper); - + wrapper.appframe.add_module_icon("Stock") - + } erpnext.StockBalance = erpnext.StockAnalytics.extend({ @@ -30,40 +30,42 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({ {id: "name", name: __("Item"), field: "name", width: 300, formatter: this.tree_formatter}, {id: "item_name", name: __("Item Name"), field: "item_name", width: 100}, - {id: "description", name: __("Description"), field: "description", width: 200, + {id: "description", name: __("Description"), field: "description", width: 200, formatter: this.text_formatter}, {id: "brand", name: __("Brand"), field: "brand", width: 100}, {id: "stock_uom", name: __("UOM"), field: "stock_uom", width: 100}, - {id: "opening_qty", name: __("Opening Qty"), field: "opening_qty", width: 100, + {id: "opening_qty", name: __("Opening Qty"), field: "opening_qty", width: 100, formatter: this.currency_formatter}, - {id: "inflow_qty", name: __("In Qty"), field: "inflow_qty", width: 100, + {id: "inflow_qty", name: __("In Qty"), field: "inflow_qty", width: 100, formatter: this.currency_formatter}, - {id: "outflow_qty", name: __("Out Qty"), field: "outflow_qty", width: 100, + {id: "outflow_qty", name: __("Out Qty"), field: "outflow_qty", width: 100, formatter: this.currency_formatter}, - {id: "closing_qty", name: __("Closing Qty"), field: "closing_qty", width: 100, + {id: "closing_qty", name: __("Closing Qty"), field: "closing_qty", width: 100, formatter: this.currency_formatter}, - - {id: "opening_value", name: __("Opening Value"), field: "opening_value", width: 100, + + {id: "opening_value", name: __("Opening Value"), field: "opening_value", width: 100, formatter: this.currency_formatter}, - {id: "inflow_value", name: __("In Value"), field: "inflow_value", width: 100, + {id: "inflow_value", name: __("In Value"), field: "inflow_value", width: 100, formatter: this.currency_formatter}, - {id: "outflow_value", name: __("Out Value"), field: "outflow_value", width: 100, + {id: "outflow_value", name: __("Out Value"), field: "outflow_value", width: 100, formatter: this.currency_formatter}, - {id: "closing_value", name: __("Closing Value"), field: "closing_value", width: 100, + {id: "closing_value", name: __("Closing Value"), field: "closing_value", width: 100, + formatter: this.currency_formatter}, + {id: "valuation_rate", name: __("Valuation Rate"), field: "valuation_rate", width: 100, formatter: this.currency_formatter}, ]; }, - + filters: [ - {fieldtype:"Select", label: __("Brand"), link:"Brand", + {fieldtype:"Select", label: __("Brand"), link:"Brand", default_value: "Select Brand...", filter: function(val, item, opts) { return val == opts.default_value || item.brand == val || item._show; }, link_formatter: {filter_input: "brand"}}, - {fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", + {fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", default_value: "Select Warehouse...", filter: function(val, item, opts, me) { return me.apply_zero_filter(val, item, opts, me); }}, - {fieldtype:"Select", label: __("Project"), link:"Project", + {fieldtype:"Select", label: __("Project"), link:"Project", default_value: "Select Project...", filter: function(val, item, opts, me) { return me.apply_zero_filter(val, item, opts, me); }, link_formatter: {filter_input: "project"}}, @@ -73,16 +75,16 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({ {fieldtype:"Button", label: __("Refresh"), icon:"icon-refresh icon-white"}, {fieldtype:"Button", label: __("Reset Filters"), icon: "icon-filter"} ], - + setup_plot_check: function() { return; }, - + prepare_data: function() { this.stock_entry_map = this.make_name_map(frappe.report_dump.data["Stock Entry"], "name"); this._super(); }, - + prepare_balances: function() { var me = this; var from_date = dateutil.str_to_obj(this.from_date); @@ -95,26 +97,26 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({ for(var i=0, j=data.length; i 0) + item.valuation_rate = flt(item.closing_value) / flt(item.closing_qty); + else item.valuation_rate = 0.0 }); }, - + update_groups: function() { var me = this; @@ -155,24 +162,22 @@ erpnext.StockBalance = erpnext.StockAnalytics.extend({ while(parent) { parent_group = me.item_by_name[parent]; $.each(me.columns, function(c, col) { - if (col.formatter == me.currency_formatter) { - parent_group[col.field] = - flt(parent_group[col.field]) - + flt(item[col.field]); + if (col.formatter == me.currency_formatter && col.field != "valuation_rate") { + parent_group[col.field] = flt(parent_group[col.field]) + flt(item[col.field]); } }); - + // show parent if filtered by brand if(item.brand == me.brand) parent_group._show = true; - + parent = me.parent_map[parent]; } } }); }, - + get_plot_data: function() { return; } -}); \ No newline at end of file +}); diff --git a/erpnext/stock/page/stock_ledger/stock_ledger.js b/erpnext/stock/page/stock_ledger/stock_ledger.js index 02af7149f7..b4086dc66e 100644 --- a/erpnext/stock/page/stock_ledger/stock_ledger.js +++ b/erpnext/stock/page/stock_ledger/stock_ledger.js @@ -1,13 +1,13 @@ // Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors // License: GNU General Public License v3. See license.txt -frappe.pages['stock-ledger'].onload = function(wrapper) { +frappe.pages['stock-ledger'].onload = function(wrapper) { frappe.ui.make_app_page({ parent: wrapper, title: __('Stock Ledger'), single_column: true }); - + new erpnext.StockLedger(wrapper); wrapper.appframe.add_module_icon("Stock") } @@ -30,7 +30,7 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ this.columns = [ {id: "posting_datetime", name: __("Posting Date"), field: "posting_datetime", width: 120, formatter: this.date_formatter}, - {id: "item_code", name: __("Item Code"), field: "item_code", width: 160, + {id: "item_code", name: __("Item Code"), field: "item_code", width: 160, link_formatter: { filter_input: "item_code", open_btn: true, @@ -57,10 +57,10 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ doctype: "dataContext.voucher_type" }}, ]; - + }, filters: [ - {fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", + {fieldtype:"Select", label: __("Warehouse"), link:"Warehouse", default_value: "Select Warehouse...", filter: function(val, item, opts) { return item.warehouse == val || val == opts.default_value; }}, @@ -68,7 +68,7 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ filter: function(val, item, opts) { return item.item_code == val || !val; }}, - {fieldtype:"Select", label: "Brand", link:"Brand", + {fieldtype:"Select", label: "Brand", link:"Brand", default_value: "Select Brand...", filter: function(val, item, opts) { return val == opts.default_value || item.brand == val || item._show; }, link_formatter: {filter_input: "brand"}}, @@ -87,17 +87,17 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ {fieldtype:"Button", label: __("Refresh"), icon:"icon-refresh icon-white"}, {fieldtype:"Button", label: __("Reset Filters"), icon: "icon-filter"} ], - + setup_filters: function() { var me = this; this._super(); - + this.wrapper.bind("apply_filters_from_route", function() { me.toggle_enable_brand(); }); this.filter_inputs.item_code.change(function() { me.toggle_enable_brand(); }); - + this.trigger_refresh_on_change(["item_code", "warehouse", "brand"]); }, - + toggle_enable_brand: function() { if(!this.filter_inputs.item_code.val()) { this.filter_inputs.brand.prop("disabled", false); @@ -107,7 +107,7 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ .prop("disabled", true); } }, - + init_filter_values: function() { this._super(); this.filter_inputs.warehouse.get(0).selectedIndex = 0; @@ -131,19 +131,19 @@ erpnext.StockLedger = erpnext.StockGridReport.extend({ item_code: "Total Out", qty: 0.0, balance: 0.0, balance_value: 0.0, id:"_total_out", _show: true, _style: "font-weight: bold" } - + // clear balance $.each(frappe.report_dump.data["Item"], function(i, item) { - item.balance = item.balance_value = 0.0; + item.balance = item.balance_value = 0.0; }); - + // initialize warehouse-item map this.item_warehouse = {}; this.serialized_buying_rates = this.get_serialized_buying_rates(); var from_datetime = dateutil.str_to_obj(me.from_date + " 00:00:00"); var to_datetime = dateutil.str_to_obj(me.to_date + " 23:59:59"); - - // + + // for(var i=0, j=data.length; i 0 else 0.0), + sle.valuation_rate, sle.stock_value, sle.voucher_type, sle.voucher_no, + voucher_link_icon, sle.batch_no, sle.serial_no, sle.company]) return columns, data def get_columns(): - return ["Date:Datetime:95", "Item:Link/Item:130", "Item Name::100", - "Item Group:Link/Item Group:100", "Brand:Link/Brand:100", - "Description::200", "Warehouse:Link/Warehouse:100", - "Stock UOM:Link/UOM:100", "Qty:Float:50", "Balance Qty:Float:100", "Valuation Rate:Currency:110", - "Balance Value:Currency:110", "Voucher Type::110", "Voucher #::100", "Link::30", - "Batch:Link/Batch:100", "Serial #:Link/Serial No:100", "Company:Link/Company:100"] + return ["Date:Datetime:95", "Item:Link/Item:130", "Item Name::100", "Item Group:Link/Item Group:100", + "Brand:Link/Brand:100", "Description::200", "Warehouse:Link/Warehouse:100", + "Stock UOM:Link/UOM:100", "Qty:Float:50", "Balance Qty:Float:100", + "Incoming Rate:Currency:110", "Valuation Rate:Currency:110", "Balance Value:Currency:110", + "Voucher Type::110", "Voucher #::100", "Link::30", "Batch:Link/Batch:100", + "Serial #:Link/Serial No:100", "Company:Link/Company:100"] def get_stock_ledger_entries(filters): return frappe.db.sql("""select concat_ws(" ", posting_date, posting_time) as date, - item_code, warehouse, actual_qty, qty_after_transaction, valuation_rate, + item_code, warehouse, actual_qty, qty_after_transaction, incoming_rate, valuation_rate, stock_value, voucher_type, voucher_no, batch_no, serial_no, company from `tabStock Ledger Entry` where company = %(company)s and From e71159d6ea89437966561cde9386089c23774dff Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 29 May 2014 16:18:49 +0530 Subject: [PATCH 12/21] Standard Rate field removed from item. Fixes #1688 --- erpnext/manufacturing/doctype/bom/bom.py | 4 +- .../doctype/bom_item/bom_item.json | 12 ++-- erpnext/stock/doctype/item/item.json | 12 +--- .../stock/report/item_prices/item_prices.py | 63 +++++++++---------- 4 files changed, 41 insertions(+), 50 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index c39a5b7aac..13bf0875e4 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -54,7 +54,7 @@ class BOM(Document): def get_item_det(self, item_code): item = frappe.db.sql("""select name, is_asset_item, is_purchase_item, docstatus, description, is_sub_contracted_item, stock_uom, default_bom, - last_purchase_rate, standard_rate, is_manufactured_item + last_purchase_rate, is_manufactured_item from `tabItem` where name=%s""", item_code, as_dict = 1) return item @@ -111,8 +111,6 @@ class BOM(Document): frappe.throw(_("Please select Price List")) rate = frappe.db.get_value("Item Price", {"price_list": self.buying_price_list, "item_code": arg["item_code"]}, "price_list_rate") or 0 - elif self.rm_cost_as_per == 'Standard Rate': - rate = arg['standard_rate'] return rate diff --git a/erpnext/manufacturing/doctype/bom_item/bom_item.json b/erpnext/manufacturing/doctype/bom_item/bom_item.json index fbf478c756..0231a703f1 100644 --- a/erpnext/manufacturing/doctype/bom_item/bom_item.json +++ b/erpnext/manufacturing/doctype/bom_item/bom_item.json @@ -1,5 +1,5 @@ { - "creation": "2013-02-22 01:27:49.000000", + "creation": "2013-02-22 01:27:49", "docstatus": 0, "doctype": "DocType", "fields": [ @@ -79,7 +79,8 @@ "fieldtype": "Float", "in_list_view": 1, "label": "Rate", - "permlevel": 0 + "permlevel": 0, + "reqd": 1 }, { "fieldname": "col_break2", @@ -133,9 +134,12 @@ ], "idx": 1, "istable": 1, - "modified": "2014-02-03 12:47:39.000000", + "modified": "2014-05-29 15:56:31.859868", "modified_by": "Administrator", "module": "Manufacturing", "name": "BOM Item", - "owner": "Administrator" + "owner": "Administrator", + "permissions": [], + "sort_field": "modified", + "sort_order": "DESC" } \ No newline at end of file diff --git a/erpnext/stock/doctype/item/item.json b/erpnext/stock/doctype/item/item.json index 0e12cd2963..92c16f8b90 100644 --- a/erpnext/stock/doctype/item/item.json +++ b/erpnext/stock/doctype/item/item.json @@ -439,16 +439,6 @@ "permlevel": 0, "read_only": 1 }, - { - "depends_on": "eval:doc.is_purchase_item==\"Yes\"", - "fieldname": "standard_rate", - "fieldtype": "Float", - "label": "Standard Rate", - "oldfieldname": "standard_rate", - "oldfieldtype": "Currency", - "permlevel": 0, - "read_only": 0 - }, { "depends_on": "eval:doc.is_purchase_item==\"Yes\"", "fieldname": "column_break2", @@ -835,7 +825,7 @@ "icon": "icon-tag", "idx": 1, "max_attachments": 1, - "modified": "2014-05-21 15:37:30.124881", + "modified": "2014-05-29 16:05:53.126214", "modified_by": "Administrator", "module": "Stock", "name": "Item", diff --git a/erpnext/stock/report/item_prices/item_prices.py b/erpnext/stock/report/item_prices/item_prices.py index 0d5539ecec..d2da54f8fa 100644 --- a/erpnext/stock/report/item_prices/item_prices.py +++ b/erpnext/stock/report/item_prices/item_prices.py @@ -7,7 +7,7 @@ from frappe.utils import flt def execute(filters=None): if not filters: filters = {} - + columns = get_columns(filters) item_map = get_item_details() pl = get_price_list() @@ -19,34 +19,33 @@ def execute(filters=None): precision = get_currency_precision() or 2 data = [] for item in sorted(item_map): - data.append([item, item_map[item]["item_name"], - item_map[item]["description"], item_map[item]["stock_uom"], - flt(last_purchase_rate.get(item, 0), precision), - flt(val_rate_map.get(item, 0), precision), - pl.get(item, {}).get("Selling"), - pl.get(item, {}).get("Buying"), - flt(bom_rate.get(item, 0), precision), - flt(item_map[item]["standard_rate"], precision) + data.append([item, item_map[item]["item_name"], + item_map[item]["description"], item_map[item]["stock_uom"], + flt(last_purchase_rate.get(item, 0), precision), + flt(val_rate_map.get(item, 0), precision), + pl.get(item, {}).get("Selling"), + pl.get(item, {}).get("Buying"), + flt(bom_rate.get(item, 0), precision) ]) - + return columns, data def get_columns(filters): """return columns based on filters""" - - columns = ["Item:Link/Item:100", "Item Name::150", "Description::150", "UOM:Link/UOM:80", - "Last Purchase Rate:Currency:90", "Valuation Rate:Currency:80", "Sales Price List::80", - "Purchase Price List::80", "BOM Rate:Currency:90", "Standard Rate:Currency:100"] + + columns = ["Item:Link/Item:100", "Item Name::150", "Description::150", "UOM:Link/UOM:80", + "Last Purchase Rate:Currency:90", "Valuation Rate:Currency:80", "Sales Price List::80", + "Purchase Price List::80", "BOM Rate:Currency:90"] return columns def get_item_details(): """returns all items details""" - + item_map = {} - + for i in frappe.db.sql("select name, item_name, description, \ - stock_uom, standard_rate from tabItem \ + stock_uom from tabItem \ order by item_code", as_dict=1): item_map.setdefault(i.name, i) @@ -57,42 +56,42 @@ def get_price_list(): rate = {} - price_list = frappe.db.sql("""select ip.item_code, ip.buying, ip.selling, - concat(ip.price_list, " - ", ip.currency, " ", ip.price_list_rate) as price - from `tabItem Price` ip, `tabPrice List` pl + price_list = frappe.db.sql("""select ip.item_code, ip.buying, ip.selling, + concat(ip.price_list, " - ", ip.currency, " ", ip.price_list_rate) as price + from `tabItem Price` ip, `tabPrice List` pl where ip.price_list=pl.name and pl.enabled=1""", as_dict=1) for j in price_list: if j.price: rate.setdefault(j.item_code, {}).setdefault("Buying" if j.buying else "Selling", []).append(j.price) item_rate_map = {} - + for item in rate: for buying_or_selling in rate[item]: - item_rate_map.setdefault(item, {}).setdefault(buying_or_selling, + item_rate_map.setdefault(item, {}).setdefault(buying_or_selling, ", ".join(rate[item].get(buying_or_selling, []))) - + return item_rate_map def get_last_purchase_rate(): item_last_purchase_rate_map = {} - query = """select * from (select + query = """select * from (select result.item_code, result.base_rate from ( - (select + (select po_item.item_code, po_item.item_name, po.transaction_date as posting_date, - po_item.base_price_list_rate, - po_item.discount_percentage, + po_item.base_price_list_rate, + po_item.discount_percentage, po_item.base_rate from `tabPurchase Order` po, `tabPurchase Order Item` po_item where po.name = po_item.parent and po.docstatus = 1) union - (select + (select pr_item.item_code, pr_item.item_name, pr.posting_date, @@ -114,8 +113,8 @@ def get_item_bom_rate(): """Get BOM rate of an item from BOM""" item_bom_map = {} - - for b in frappe.db.sql("""select item, (total_cost/quantity) as bom_rate + + for b in frappe.db.sql("""select item, (total_cost/quantity) as bom_rate from `tabBOM` where is_active=1 and is_default=1""", as_dict=1): item_bom_map.setdefault(b.item, flt(b.bom_rate)) @@ -125,8 +124,8 @@ def get_valuation_rate(): """Get an average valuation rate of an item from all warehouses""" item_val_rate_map = {} - - for d in frappe.db.sql("""select item_code, + + for d in frappe.db.sql("""select item_code, sum(actual_qty*valuation_rate)/sum(actual_qty) as val_rate from tabBin where actual_qty > 0 group by item_code""", as_dict=1): item_val_rate_map.setdefault(d.item_code, d.val_rate) From 3dc6a8019840b9a31c7cc8d0939a374e9929cb0a Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 29 May 2014 16:29:08 +0530 Subject: [PATCH 13/21] deleted delivery note packing list wise print format --- .../delivery_note_packing_list_wise.json | 13 ------------- 1 file changed, 13 deletions(-) delete mode 100644 erpnext/stock/print_format/delivery_note_packing_list_wise/delivery_note_packing_list_wise.json diff --git a/erpnext/stock/print_format/delivery_note_packing_list_wise/delivery_note_packing_list_wise.json b/erpnext/stock/print_format/delivery_note_packing_list_wise/delivery_note_packing_list_wise.json deleted file mode 100644 index a971a104ae..0000000000 --- a/erpnext/stock/print_format/delivery_note_packing_list_wise/delivery_note_packing_list_wise.json +++ /dev/null @@ -1,13 +0,0 @@ -{ - "creation": "2011-08-23 16:49:40", - "docstatus": 0, - "doctype": "Print Format", - "html": "\n\n\n\n\n\n\n\n\n\n", - "idx": 1, - "modified": "2014-05-13 16:07:19.133031", - "modified_by": "Administrator", - "module": "Stock", - "name": "Delivery Note Packing List Wise", - "owner": "Administrator", - "standard": "Yes" -} \ No newline at end of file From f3552ca7376c0da7c15dc159e62e8cf3fd8e9432 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 29 May 2014 18:26:01 +0530 Subject: [PATCH 14/21] packing slip fixes #1711 --- erpnext/stock/doctype/packing_slip/packing_slip.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/packing_slip/packing_slip.py b/erpnext/stock/doctype/packing_slip/packing_slip.py index e3d01999f1..63657b75ab 100644 --- a/erpnext/stock/doctype/packing_slip/packing_slip.py +++ b/erpnext/stock/doctype/packing_slip/packing_slip.py @@ -141,7 +141,7 @@ class PackingSlip(Document): note """ recommended_case_no = frappe.db.sql("""SELECT MAX(to_case_no) FROM `tabPacking Slip` - WHERE delivery_note = %(delivery_note)s AND docstatus=1""", self.as_dict()) + WHERE delivery_note = %s AND docstatus=1""", self.delivery_note) return cint(recommended_case_no[0][0]) + 1 From 66cecf48247da3dc83b907169481dad80536588d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 29 May 2014 18:36:58 +0530 Subject: [PATCH 15/21] uom trigger issue in stock entry fixes #1712 --- .../stock/doctype/stock_entry/stock_entry.py | 17 +++++++++-------- 1 file changed, 9 insertions(+), 8 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 900474be3b..039d4a03f8 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -365,17 +365,18 @@ class StockEntry(StockController): ret.update(stock_and_rate) return ret - def get_uom_details(self, arg = ''): - arg, ret = eval(arg), {} - uom = frappe.db.sql("""select conversion_factor from `tabUOM Conversion Detail` - where parent = %s and uom = %s""", (arg['item_code'], arg['uom']), as_dict = 1) - if not uom or not flt(uom[0].conversion_factor): - frappe.msgprint(_("UOM coversion factor required for UOM {0} in Item {1}").format(arg["uom"], arg["item_code"])) + def get_uom_details(self, args): + conversion_factor = frappe.db.get_value("UOM Conversion Detail", {"parent": args.get("item_code"), + "uom": args.get("uom")}, "conversion_factor") + + if not conversion_factor: + frappe.msgprint(_("UOM coversion factor required for UOM: {0} in Item: {1}") + .format(args.get("uom"), args.get("item_code"))) ret = {'uom' : ''} else: ret = { - 'conversion_factor' : flt(uom[0]['conversion_factor']), - 'transfer_qty' : flt(arg['qty']) * flt(uom[0]['conversion_factor']), + 'conversion_factor' : flt(conversion_factor), + 'transfer_qty' : flt(args.get("qty")) * flt(conversion_factor) } return ret From 7f03e24c5518fefe6a939e34f26bf6da0a34456f Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 29 May 2014 18:53:09 +0530 Subject: [PATCH 16/21] Valuation rate of raw materials in BOM. #1688 --- erpnext/manufacturing/doctype/bom/bom.py | 29 ++++++++---------------- 1 file changed, 9 insertions(+), 20 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 13bf0875e4..56bff32f8e 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -3,7 +3,7 @@ from __future__ import unicode_literals import frappe -from frappe.utils import cint, cstr, flt, now, nowdate +from frappe.utils import cint, cstr, flt from frappe import _ from frappe.model.document import Document @@ -132,26 +132,15 @@ class BOM(Document): return bom and bom[0]['unit_cost'] or 0 def get_valuation_rate(self, args): - """ Get average valuation rate of relevant warehouses - as per valuation method (MAR/FIFO) - as on costing date - """ - from erpnext.stock.utils import get_incoming_rate - posting_date, posting_time = nowdate(), now().split()[1] - warehouse = frappe.db.sql("select warehouse from `tabBin` where item_code = %s", args['item_code']) - rate = [] - for wh in warehouse: - r = get_incoming_rate({ - "item_code": args.get("item_code"), - "warehouse": wh[0], - "posting_date": posting_date, - "posting_time": posting_time, - "qty": args.get("qty") or 0 - }) - if r: - rate.append(r) + """ Get weighted average of valuation rate from all warehouses """ - return rate and flt(sum(rate))/len(rate) or 0 + total_qty, total_value = 0, 0 + for d in frappe.db.sql("""select actual_qty, stock_value from `tabBin` + where item_code=%s and actual_qty > 0""", args['item_code'], as_dict=1): + total_qty += flt(d.actual_qty) + total_value += flt(d.stock_value) + + return total_value / total_qty def manage_default_bom(self): """ Uncheck others if current one is selected as default, From c7253b3a370306ea317ef26a00c5c29444f5896d Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 29 May 2014 19:48:41 +0530 Subject: [PATCH 17/21] Get valuation rate for fg item base don issued item cost + operation cost. #1688 --- erpnext/manufacturing/doctype/bom/bom.js | 22 +++++++++--------- .../stock/doctype/stock_entry/stock_entry.py | 23 +++++++++++++++---- erpnext/stock/utils.py | 4 ---- 3 files changed, 29 insertions(+), 20 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.js b/erpnext/manufacturing/doctype/bom/bom.js index ac023f360d..1cee6b9103 100644 --- a/erpnext/manufacturing/doctype/bom/bom.js +++ b/erpnext/manufacturing/doctype/bom/bom.js @@ -4,11 +4,11 @@ // On REFRESH cur_frm.cscript.refresh = function(doc,dt,dn){ cur_frm.toggle_enable("item", doc.__islocal); - + if (!doc.__islocal && doc.docstatus<2) { cur_frm.add_custom_button(__("Update Cost"), cur_frm.cscript.update_cost); } - + cur_frm.cscript.with_operations(doc); set_operation_no(doc); } @@ -41,14 +41,14 @@ var set_operation_no = function(doc) { var op = op_table[i].operation_no; if (op && !inList(operations, op)) operations.push(op); } - - frappe.meta.get_docfield("BOM Item", "operation_no", + + frappe.meta.get_docfield("BOM Item", "operation_no", cur_frm.docname).options = operations.join("\n"); - + $.each(doc.bom_materials || [], function(i, v) { if(!inList(operations, cstr(v.operation_no))) v.operation_no = null; }); - + refresh_field("bom_materials"); } @@ -97,7 +97,7 @@ var get_bom_material_detail= function(doc, cdt, cdn) { doc: cur_frm.doc, method: "get_bom_material_detail", args: { - 'item_code': d.item_code, + 'item_code': d.item_code, 'bom_no': d.bom_no != null ? d.bom_no: '', 'qty': d.qty }, @@ -131,7 +131,7 @@ cur_frm.cscript.rate = function(doc, cdt, cdn) { } } -var calculate_op_cost = function(doc) { +var calculate_op_cost = function(doc) { var op = doc.bom_operations || []; total_op_cost = 0; for(var i=0;i Date: Thu, 29 May 2014 20:09:04 +0530 Subject: [PATCH 18/21] Total valuation for manufactured or repacked item(s) can not be less than total valuation of raw materials #1688 --- .../stock/doctype/stock_entry/stock_entry.py | 21 ++++++++++++++++--- 1 file changed, 18 insertions(+), 3 deletions(-) diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index 1d04a7dbc3..c613e4ea11 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -41,6 +41,7 @@ class StockEntry(StockController): self.validate_return_reference_doc() self.validate_with_material_request() self.validate_fiscal_year() + self.validate_valuation_rate() self.set_total_amount() def on_submit(self): @@ -170,6 +171,19 @@ class StockEntry(StockController): frappe.throw(_("Stock Entries already created for Production Order ") + self.production_order + ":" + ", ".join(other_ste), DuplicateEntryForProductionOrderError) + def validate_valuation_rate(self): + if self.purpose == "Manufacture/Repack": + valuation_at_source, valuation_at_target = 0, 0 + for d in self.get("mtn_details"): + if d.s_warehouse and not d.t_warehouse: + valuation_at_source += flt(d.amount) + if d.t_warehouse and not d.s_warehouse: + valuation_at_target += flt(d.amount) + + if valuation_at_target < valuation_at_source: + frappe.throw(_("Total valuation for manufactured or repacked item(s) can not be less than \ + total valuation of raw materials")) + def set_total_amount(self): self.total_amount = sum([flt(item.amount) for item in self.get("mtn_details")]) @@ -202,9 +216,10 @@ class StockEntry(StockController): if self.production_order and self.purpose == "Manufacture/Repack": for d in self.get("mtn_details"): if d.bom_no: - bom = frappe.db.get_value("BOM", d.bom_no, ["operating_cost", "quantity"], as_dict=1) - operation_cost_per_unit = flt(bom.operating_cost) / flt(bom.quantity) - d.incoming_rate = operation_cost_per_unit + (raw_material_cost / flt(d.transfer_qty)) + if not flt(d.incoming_rate): + bom = frappe.db.get_value("BOM", d.bom_no, ["operating_cost", "quantity"], as_dict=1) + operation_cost_per_unit = flt(bom.operating_cost) / flt(bom.quantity) + d.incoming_rate = operation_cost_per_unit + (raw_material_cost / flt(d.transfer_qty)) d.amount = flt(d.transfer_qty) * flt(d.incoming_rate) def get_incoming_rate(self, args): From 6b1a8e0a40813b29018a9d727be19a412f94342b Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Thu, 29 May 2014 22:57:13 +0530 Subject: [PATCH 19/21] minor fixes --- erpnext/manufacturing/doctype/bom/bom.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/bom/bom.py b/erpnext/manufacturing/doctype/bom/bom.py index 56bff32f8e..ffcbbd9920 100644 --- a/erpnext/manufacturing/doctype/bom/bom.py +++ b/erpnext/manufacturing/doctype/bom/bom.py @@ -134,13 +134,13 @@ class BOM(Document): def get_valuation_rate(self, args): """ Get weighted average of valuation rate from all warehouses """ - total_qty, total_value = 0, 0 + total_qty, total_value = 0.0, 0.0 for d in frappe.db.sql("""select actual_qty, stock_value from `tabBin` where item_code=%s and actual_qty > 0""", args['item_code'], as_dict=1): total_qty += flt(d.actual_qty) total_value += flt(d.stock_value) - return total_value / total_qty + return total_value / total_qty if total_qty else 0.0 def manage_default_bom(self): """ Uncheck others if current one is selected as default, From cb9bdf43f6a0a6aadf42fa0c810a8c7829dd98f6 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 30 May 2014 11:20:02 +0530 Subject: [PATCH 20/21] over billing validation fixed --- erpnext/controllers/accounts_controller.py | 2 +- erpnext/controllers/status_updater.py | 4 ++-- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 1f2e3b2699..4567dd7005 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -415,7 +415,7 @@ class AccountsController(TransactionBase): if total_billed_amt - max_allowed_amt > 0.01: reduce_by = total_billed_amt - max_allowed_amt - frappe.throw(_("Cannot overbill for Item {0} in row {0} more than {1}. To allow overbilling, please set in 'Setup' > 'Global Defaults'").format(item.item_code, item.idx, max_allowed_amt)) + frappe.throw(_("Cannot overbill for Item {0} in row {0} more than {1}. To allow overbilling, please set in Stock Settings").format(item.item_code, item.idx, max_allowed_amt)) def get_company_default(self, fieldname): from erpnext.accounts.utils import get_company_default diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index 0e4ac31e60..9322ca6aa6 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -156,8 +156,8 @@ class StatusUpdater(Document): item['max_allowed'] = flt(item[args['target_ref_field']] * (100+tolerance)/100) item['reduce_by'] = item[args['target_field']] - item['max_allowed'] - msgprint(_("Allowance for over-delivery / over-billing crossed for Item {0}").format(item["item_code"])) - throw(_("{0} must be less than or equal to {1}").format(_(item["target_ref_field"]), item[args["max_allowed"]])) + msgprint(_("Allowance for over-delivery / over-billing crossed for Item {0}.").format(item["item_code"])) + throw(_("{0} must be less than or equal to {1}").format(item["target_ref_field"].title(), item["max_allowed"])) def update_qty(self, change_modified=True): """ From c1367d9d10b3ffb59dc7c7ef9eea516d809d41c1 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Fri, 30 May 2014 11:43:00 +0530 Subject: [PATCH 21/21] minor fixes --- erpnext/public/js/transaction.js | 5 +++-- erpnext/public/js/utils/party.js | 2 +- erpnext/stock/doctype/stock_entry/stock_entry.py | 3 +-- 3 files changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/public/js/transaction.js b/erpnext/public/js/transaction.js index b336637f0a..6d30ef0999 100644 --- a/erpnext/public/js/transaction.js +++ b/erpnext/public/js/transaction.js @@ -367,8 +367,9 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({ } - if(item) _apply_pricing_rule(item); - else { + if(item) { + _apply_pricing_rule(item); + } else { $.each(this.get_item_doclist(), function(n, item) { _apply_pricing_rule(item); }); diff --git a/erpnext/public/js/utils/party.js b/erpnext/public/js/utils/party.js index 9da0353dbb..40db97feb8 100644 --- a/erpnext/public/js/utils/party.js +++ b/erpnext/public/js/utils/party.js @@ -33,7 +33,7 @@ erpnext.utils.get_party_details = function(frm, method, args, callback) { frm.updating_party_details = true; frm.set_value(r.message); frm.updating_party_details = false; - if(callback) callback() + if(callback) callback(); } } }); diff --git a/erpnext/stock/doctype/stock_entry/stock_entry.py b/erpnext/stock/doctype/stock_entry/stock_entry.py index c613e4ea11..cbe8c29749 100644 --- a/erpnext/stock/doctype/stock_entry/stock_entry.py +++ b/erpnext/stock/doctype/stock_entry/stock_entry.py @@ -181,8 +181,7 @@ class StockEntry(StockController): valuation_at_target += flt(d.amount) if valuation_at_target < valuation_at_source: - frappe.throw(_("Total valuation for manufactured or repacked item(s) can not be less than \ - total valuation of raw materials")) + frappe.throw(_("Total valuation for manufactured or repacked item(s) can not be less than total valuation of raw materials")) def set_total_amount(self): self.total_amount = sum([flt(item.amount) for item in self.get("mtn_details")])