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 00000000000..356cc0de9c3 --- /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 baefde26efb..5fbb08f1cf1 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 39260a2e9ed..61e7ade4415 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 158dec20467..d87456d2604 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 26f3be78894..d3b46060344 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 a5707bb2225..21b42a5f3f3 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 527213be01d..5b3bd9d8889 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 05cde6aab00..c1072a30ff3 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 c50dc3b6649..032448f79f4 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 23fb1c0e95d..224f784c691 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 11cb9d9627e..65dfe97af81 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 9033065bd91..683f72b0f24 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 e12a30e14ef..b336637f0a5 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 31abbb304f1..9da0353dbb9 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 4e19ee79706..a1807dd9ada 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 9d0ae0e031a..13ee085eefb 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 1e9643aeb89..b4841006e29 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 e093def8869..13307ef64a0 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 0c8100ce7db..548a7dacf10 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 f9c7526a960..bd8cd3e939f 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