From a3dd72a7596c64b0a33cce07c15af8075747a133 Mon Sep 17 00:00:00 2001 From: Nabin Hait Date: Wed, 28 May 2014 12:49:20 +0530 Subject: [PATCH] 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