Pricing Rule fixes and improvements. Fixes #1795
This commit is contained in:
parent
b35d84156f
commit
444f956e7b
@ -61,4 +61,31 @@ frappe.ui.form.on("Pricing Rule", "refresh", function(frm) {
|
||||
'</table>'].join("\n");
|
||||
|
||||
set_field_options("pricing_rule_help", help_content);
|
||||
|
||||
cur_frm.cscript.set_options_for_applicable_for();
|
||||
});
|
||||
|
||||
cur_frm.cscript.set_options_for_applicable_for = function() {
|
||||
var options = [""];
|
||||
var applicable_for = cur_frm.doc.applicable_for;
|
||||
|
||||
if(cur_frm.doc.selling) {
|
||||
options = $.merge(options, ["Customer", "Customer Group", "Territory", "Sales Partner", "Campaign"]);
|
||||
}
|
||||
if(cur_frm.doc.buying) {
|
||||
$.merge(options, ["Supplier", "Supplier Type"]);
|
||||
}
|
||||
|
||||
set_field_options("applicable_for", options.join("\n"));
|
||||
|
||||
if(!in_list(options, applicable_for)) applicable_for = null;
|
||||
cur_frm.set_value("applicable_for", applicable_for)
|
||||
}
|
||||
|
||||
cur_frm.cscript.selling = function() {
|
||||
cur_frm.cscript.set_options_for_applicable_for();
|
||||
}
|
||||
|
||||
cur_frm.cscript.buying = function() {
|
||||
cur_frm.cscript.set_options_for_applicable_for();
|
||||
}
|
||||
|
@ -1,288 +1,300 @@
|
||||
{
|
||||
"allow_import": 1,
|
||||
"autoname": "PRULE.#####",
|
||||
"creation": "2014-02-21 15:02:51",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"allow_import": 1,
|
||||
"autoname": "PRULE.#####",
|
||||
"creation": "2014-02-21 15:02:51",
|
||||
"docstatus": 0,
|
||||
"doctype": "DocType",
|
||||
"document_type": "Master",
|
||||
"fields": [
|
||||
{
|
||||
"fieldname": "applicability_section",
|
||||
"fieldtype": "Section Break",
|
||||
"in_list_view": 0,
|
||||
"label": "Applicability",
|
||||
"fieldname": "applicability_section",
|
||||
"fieldtype": "Section Break",
|
||||
"in_list_view": 0,
|
||||
"label": "Applicability",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"default": "Item Code",
|
||||
"fieldname": "apply_on",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Apply On",
|
||||
"options": "\nItem Code\nItem Group\nBrand",
|
||||
"permlevel": 0,
|
||||
"default": "Item Code",
|
||||
"fieldname": "apply_on",
|
||||
"fieldtype": "Select",
|
||||
"in_list_view": 1,
|
||||
"label": "Apply On",
|
||||
"options": "\nItem Code\nItem Group\nBrand",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.apply_on==\"Item Code\"",
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Item Code",
|
||||
"options": "Item",
|
||||
"permlevel": 0,
|
||||
"depends_on": "eval:doc.apply_on==\"Item Code\"",
|
||||
"fieldname": "item_code",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Item Code",
|
||||
"options": "Item",
|
||||
"permlevel": 0,
|
||||
"reqd": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.apply_on==\"Item Group\"",
|
||||
"fieldname": "item_group",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Item Group",
|
||||
"options": "Item Group",
|
||||
"depends_on": "eval:doc.apply_on==\"Item Group\"",
|
||||
"fieldname": "item_group",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Item Group",
|
||||
"options": "Item Group",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.apply_on==\"Brand\"",
|
||||
"fieldname": "brand",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Brand",
|
||||
"options": "Brand",
|
||||
"depends_on": "eval:doc.apply_on==\"Brand\"",
|
||||
"fieldname": "brand",
|
||||
"fieldtype": "Link",
|
||||
"in_list_view": 1,
|
||||
"label": "Brand",
|
||||
"options": "Brand",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "applicable_for",
|
||||
"fieldtype": "Select",
|
||||
"label": "Applicable For",
|
||||
"options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Type",
|
||||
"fieldname": "selling",
|
||||
"fieldtype": "Check",
|
||||
"label": "Selling",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.applicable_for==\"Customer\"",
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer",
|
||||
"options": "Customer",
|
||||
"fieldname": "buying",
|
||||
"fieldtype": "Check",
|
||||
"label": "Buying",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.applicable_for==\"Customer Group\"",
|
||||
"fieldname": "customer_group",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer Group",
|
||||
"options": "Customer Group",
|
||||
"fieldname": "applicable_for",
|
||||
"fieldtype": "Select",
|
||||
"label": "Applicable For",
|
||||
"options": "\nCustomer\nCustomer Group\nTerritory\nSales Partner\nCampaign\nSupplier\nSupplier Type",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.applicable_for==\"Territory\"",
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"label": "Territory",
|
||||
"options": "Territory",
|
||||
"depends_on": "eval:doc.applicable_for==\"Customer\"",
|
||||
"fieldname": "customer",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer",
|
||||
"options": "Customer",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.applicable_for==\"Sales Partner\"",
|
||||
"fieldname": "sales_partner",
|
||||
"fieldtype": "Link",
|
||||
"label": "Sales Partner",
|
||||
"options": "Sales Partner",
|
||||
"depends_on": "eval:doc.applicable_for==\"Customer Group\"",
|
||||
"fieldname": "customer_group",
|
||||
"fieldtype": "Link",
|
||||
"label": "Customer Group",
|
||||
"options": "Customer Group",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.applicable_for==\"Campaign\"",
|
||||
"fieldname": "campaign",
|
||||
"fieldtype": "Link",
|
||||
"label": "Campaign",
|
||||
"options": "Campaign",
|
||||
"depends_on": "eval:doc.applicable_for==\"Territory\"",
|
||||
"fieldname": "territory",
|
||||
"fieldtype": "Link",
|
||||
"label": "Territory",
|
||||
"options": "Territory",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.applicable_for==\"Supplier\"",
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier",
|
||||
"options": "Supplier",
|
||||
"depends_on": "eval:doc.applicable_for==\"Sales Partner\"",
|
||||
"fieldname": "sales_partner",
|
||||
"fieldtype": "Link",
|
||||
"label": "Sales Partner",
|
||||
"options": "Sales Partner",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.applicable_for==\"Supplier Type\"",
|
||||
"fieldname": "supplier_type",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier Type",
|
||||
"options": "Supplier Type",
|
||||
"depends_on": "eval:doc.applicable_for==\"Campaign\"",
|
||||
"fieldname": "campaign",
|
||||
"fieldtype": "Link",
|
||||
"label": "Campaign",
|
||||
"options": "Campaign",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "min_qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Min Qty",
|
||||
"depends_on": "eval:doc.applicable_for==\"Supplier\"",
|
||||
"fieldname": "supplier",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier",
|
||||
"options": "Supplier",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "max_qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Max Qty",
|
||||
"depends_on": "eval:doc.applicable_for==\"Supplier Type\"",
|
||||
"fieldname": "supplier_type",
|
||||
"fieldtype": "Link",
|
||||
"label": "Supplier Type",
|
||||
"options": "Supplier Type",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "col_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"fieldname": "max_qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Max Qty",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"fieldname": "min_qty",
|
||||
"fieldtype": "Float",
|
||||
"label": "Min Qty",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"default": "Today",
|
||||
"fieldname": "valid_from",
|
||||
"fieldtype": "Date",
|
||||
"label": "Valid From",
|
||||
"fieldname": "col_break1",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "valid_upto",
|
||||
"fieldtype": "Date",
|
||||
"label": "Valid Upto",
|
||||
"fieldname": "company",
|
||||
"fieldtype": "Link",
|
||||
"label": "Company",
|
||||
"options": "Company",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "priority",
|
||||
"fieldtype": "Select",
|
||||
"label": "Priority",
|
||||
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20",
|
||||
"default": "Today",
|
||||
"fieldname": "valid_from",
|
||||
"fieldtype": "Date",
|
||||
"label": "Valid From",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "disable",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disable",
|
||||
"fieldname": "valid_upto",
|
||||
"fieldtype": "Date",
|
||||
"label": "Valid Upto",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "price_discount_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Price / Discount",
|
||||
"fieldname": "priority",
|
||||
"fieldtype": "Select",
|
||||
"label": "Priority",
|
||||
"options": "\n1\n2\n3\n4\n5\n6\n7\n8\n9\n10\n11\n12\n13\n14\n15\n16\n17\n18\n19\n20",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"default": "Discount Percentage",
|
||||
"fieldname": "price_or_discount",
|
||||
"fieldtype": "Select",
|
||||
"label": "Price or Discount",
|
||||
"options": "\nPrice\nDiscount Percentage",
|
||||
"permlevel": 0,
|
||||
"fieldname": "disable",
|
||||
"fieldtype": "Check",
|
||||
"label": "Disable",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "price_discount_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "Price / Discount",
|
||||
"permlevel": 0
|
||||
},
|
||||
{
|
||||
"default": "Discount Percentage",
|
||||
"fieldname": "price_or_discount",
|
||||
"fieldtype": "Select",
|
||||
"label": "Price or Discount",
|
||||
"options": "\nPrice\nDiscount Percentage",
|
||||
"permlevel": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "col_break2",
|
||||
"fieldtype": "Column Break",
|
||||
"fieldname": "col_break2",
|
||||
"fieldtype": "Column Break",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.price_or_discount==\"Price\"",
|
||||
"fieldname": "price",
|
||||
"fieldtype": "Float",
|
||||
"label": "Price",
|
||||
"depends_on": "eval:doc.price_or_discount==\"Price\"",
|
||||
"fieldname": "price",
|
||||
"fieldtype": "Float",
|
||||
"label": "Price",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.price_or_discount==\"Discount Percentage\"",
|
||||
"fieldname": "discount_percentage",
|
||||
"fieldtype": "Float",
|
||||
"label": "Discount Percentage",
|
||||
"depends_on": "eval:doc.price_or_discount==\"Discount Percentage\"",
|
||||
"fieldname": "discount_percentage",
|
||||
"fieldtype": "Float",
|
||||
"label": "Discount Percentage",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"depends_on": "eval:doc.price_or_discount==\"Discount Percentage\"",
|
||||
"fieldname": "for_price_list",
|
||||
"fieldtype": "Link",
|
||||
"label": "For Price List",
|
||||
"options": "Price List",
|
||||
"depends_on": "eval:doc.price_or_discount==\"Discount Percentage\"",
|
||||
"fieldname": "for_price_list",
|
||||
"fieldtype": "Link",
|
||||
"label": "For Price List",
|
||||
"options": "Price List",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "help_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "",
|
||||
"options": "Simple",
|
||||
"fieldname": "help_section",
|
||||
"fieldtype": "Section Break",
|
||||
"label": "",
|
||||
"options": "Simple",
|
||||
"permlevel": 0
|
||||
},
|
||||
},
|
||||
{
|
||||
"fieldname": "pricing_rule_help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Pricing Rule Help",
|
||||
"fieldname": "pricing_rule_help",
|
||||
"fieldtype": "HTML",
|
||||
"label": "Pricing Rule Help",
|
||||
"permlevel": 0
|
||||
}
|
||||
],
|
||||
"icon": "icon-gift",
|
||||
"idx": 1,
|
||||
"istable": 0,
|
||||
"modified": "2014-05-28 15:36:29.403659",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Pricing Rule",
|
||||
"owner": "Administrator",
|
||||
],
|
||||
"icon": "icon-gift",
|
||||
"idx": 1,
|
||||
"istable": 0,
|
||||
"modified": "2014-06-19 15:00:09.962572",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Pricing Rule",
|
||||
"owner": "Administrator",
|
||||
"permissions": [
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"export": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"export": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Accounts Manager",
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"export": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Manager",
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"export": 0,
|
||||
"import": 0,
|
||||
"permlevel": 0,
|
||||
"print": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Sales Manager",
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Purchase Manager",
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Website Manager",
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Website Manager",
|
||||
"write": 1
|
||||
},
|
||||
},
|
||||
{
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"export": 1,
|
||||
"import": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"set_user_permissions": 1,
|
||||
"role": "System Manager",
|
||||
"create": 1,
|
||||
"delete": 1,
|
||||
"export": 1,
|
||||
"import": 1,
|
||||
"permlevel": 0,
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"restrict": 1,
|
||||
"role": "System Manager",
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"sort_field": "modified",
|
||||
],
|
||||
"sort_field": "modified",
|
||||
"sort_order": "DESC"
|
||||
}
|
||||
}
|
@ -5,13 +5,17 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
import json
|
||||
from frappe import throw, _
|
||||
from frappe.utils import flt
|
||||
from frappe.utils import flt, cint
|
||||
from frappe.model.document import Document
|
||||
|
||||
class MultiplePricingRuleConflict(frappe.ValidationError): pass
|
||||
|
||||
class PricingRule(Document):
|
||||
def validate(self):
|
||||
self.validate_mandatory()
|
||||
self.validate_applicable_for_selling_or_buying()
|
||||
self.validate_min_max_qty()
|
||||
self.cleanup_fields_value()
|
||||
self.validate_price_or_discount()
|
||||
@ -22,6 +26,18 @@ class PricingRule(Document):
|
||||
if tocheck and not self.get(tocheck):
|
||||
throw(_("{0} is required").format(self.meta.get_label(tocheck)), frappe.MandatoryError)
|
||||
|
||||
def validate_applicable_for_selling_or_buying(self):
|
||||
if not self.selling and not self.buying:
|
||||
throw(_("Atleast one of the Selling or Buying must be selected"))
|
||||
|
||||
if not self.selling and self.applicable_for in ["Customer", "Customer Group",
|
||||
"Territory", "Sales Partner", "Campaign"]:
|
||||
throw(_("Selling must be checked, if Applicable For is selected as {0}"
|
||||
.format(self.applicable_for)))
|
||||
|
||||
if not self.buying and self.applicable_for in ["Supplier", "Supplier Type"]:
|
||||
throw(_("Buying must be checked, if Applicable For is selected as {0}"
|
||||
.format(self.applicable_for)))
|
||||
|
||||
def validate_min_max_qty(self):
|
||||
if self.min_qty and self.max_qty and flt(self.min_qty) > flt(self.max_qty):
|
||||
@ -44,3 +60,181 @@ class PricingRule(Document):
|
||||
for field in ["Price", "Discount Percentage"]:
|
||||
if flt(self.get(frappe.scrub(field))) < 0:
|
||||
throw(_("{0} can not be negative").format(field))
|
||||
|
||||
#--------------------------------------------------------------------------------
|
||||
|
||||
@frappe.whitelist()
|
||||
def apply_pricing_rule(args):
|
||||
"""
|
||||
args = {
|
||||
"item_list": [{"doctype": "", "name": "", "item_code": "", "brand": "", "item_group": ""}, ...],
|
||||
"customer": "something",
|
||||
"customer_group": "something",
|
||||
"territory": "something",
|
||||
"supplier": "something",
|
||||
"supplier_type": "something",
|
||||
"currency": "something",
|
||||
"conversion_rate": "something",
|
||||
"price_list": "something",
|
||||
"plc_conversion_rate": "something",
|
||||
"company": "something",
|
||||
"transaction_date": "something",
|
||||
"campaign": "something",
|
||||
"sales_partner": "something",
|
||||
"ignore_pricing_rule": "something"
|
||||
}
|
||||
"""
|
||||
if isinstance(args, basestring):
|
||||
args = json.loads(args)
|
||||
|
||||
args = frappe._dict(args)
|
||||
|
||||
# list of dictionaries
|
||||
out = []
|
||||
|
||||
if args.get("parenttype") == "Material Request": return out
|
||||
|
||||
if not args.transaction_type:
|
||||
args.transaction_type = "buying" if frappe.get_meta(args.parenttype).get_field("supplier") \
|
||||
else "selling"
|
||||
|
||||
for item in args.get("item_list"):
|
||||
args_copy = args.copy()
|
||||
args_copy.update(item)
|
||||
out.append(get_pricing_rule_for_item(args_copy))
|
||||
|
||||
return out
|
||||
|
||||
def get_pricing_rule_for_item(args):
|
||||
if args.get("parenttype") == "Material Request": return {}
|
||||
|
||||
item_details = frappe._dict({
|
||||
"doctype": args.doctype,
|
||||
"name": args.name,
|
||||
"pricing_rule": None
|
||||
})
|
||||
|
||||
if args.ignore_pricing_rule or not args.item_code:
|
||||
return item_details
|
||||
|
||||
if not (args.item_group and args.brand):
|
||||
args.item_group, args.brand = frappe.db.get_value("Item", args.item_code, ["item_group", "brand"])
|
||||
|
||||
if args.customer and not (args.customer_group and args.territory):
|
||||
args.customer_group, args.territory = frappe.db.get_value("Customer", args.customer,
|
||||
["customer_group", "territory"])
|
||||
elif args.supplier and not args.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:
|
||||
item_details.pricing_rule = pricing_rule.name
|
||||
if pricing_rule.price_or_discount == "Price":
|
||||
item_details.update({
|
||||
"price_list_rate": pricing_rule.price*flt(args.plc_conversion_rate)/flt(args.conversion_rate),
|
||||
"discount_percentage": 0.0
|
||||
})
|
||||
else:
|
||||
item_details.discount_percentage = pricing_rule.discount_percentage
|
||||
|
||||
return item_details
|
||||
|
||||
def get_pricing_rules(args):
|
||||
def _get_tree_conditions(parenttype, allow_blank=True):
|
||||
field = frappe.scrub(parenttype)
|
||||
condition = ""
|
||||
if args.get(field):
|
||||
lft, rgt = frappe.db.get_value(parenttype, args[field], ["lft", "rgt"])
|
||||
parent_groups = frappe.db.sql_list("""select name from `tab%s`
|
||||
where lft<=%s and rgt>=%s""" % (parenttype, '%s', '%s'), (lft, rgt))
|
||||
|
||||
if parent_groups:
|
||||
if allow_blank: parent_groups.append('')
|
||||
condition = " ifnull("+field+", '') in ('" + "', '".join(parent_groups)+"')"
|
||||
|
||||
return condition
|
||||
|
||||
|
||||
conditions = ""
|
||||
for field in ["company", "customer", "supplier", "supplier_type", "campaign", "sales_partner"]:
|
||||
if args.get(field):
|
||||
conditions += " and ifnull("+field+", '') in (%("+field+")s, '')"
|
||||
else:
|
||||
conditions += " and ifnull("+field+", '') = ''"
|
||||
|
||||
for parenttype in ["Customer Group", "Territory"]:
|
||||
group_condition = _get_tree_conditions(parenttype)
|
||||
if group_condition:
|
||||
conditions += " and " + group_condition
|
||||
|
||||
conditions += " and ifnull(for_price_list, '') in (%(price_list)s, '')"
|
||||
|
||||
if args.get("transaction_date"):
|
||||
conditions += """ and %(transaction_date)s between ifnull(valid_from, '2000-01-01')
|
||||
and ifnull(valid_upto, '2500-12-31')"""
|
||||
|
||||
return frappe.db.sql("""select * from `tabPricing Rule`
|
||||
where (item_code=%(item_code)s or {item_group_condition} or brand=%(brand)s)
|
||||
and docstatus < 2 and ifnull(disable, 0) = 0
|
||||
and ifnull({transaction_type}, 0) = 1 {conditions}
|
||||
order by priority desc, name desc""".format(
|
||||
item_group_condition=_get_tree_conditions("Item Group", False),
|
||||
transaction_type=args.transaction_type, conditions=conditions), args, as_dict=1)
|
||||
|
||||
def filter_pricing_rules(args, pricing_rules):
|
||||
# filter for qty
|
||||
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:
|
||||
max_priority = max([cint(p.priority) for p in pricing_rules])
|
||||
if max_priority:
|
||||
pricing_rules = filter(lambda x: cint(x.priority)==max_priority, pricing_rules)
|
||||
|
||||
# apply internal priority
|
||||
all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory",
|
||||
"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)
|
||||
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) \
|
||||
or pricing_rules
|
||||
|
||||
if len(pricing_rules) > 1:
|
||||
frappe.throw(_("Multiple Price Rule exists with same criteria, please resolve \
|
||||
conflict by assigning priority. Price Rules: {0}")
|
||||
.format("\n".join([d.name for d in pricing_rules])), MultiplePricingRuleConflict)
|
||||
elif pricing_rules:
|
||||
return pricing_rules[0]
|
||||
|
||||
def if_all_rules_same(pricing_rules, fields):
|
||||
all_rules_same = True
|
||||
val = [pricing_rules[0][k] for k in fields]
|
||||
for p in pricing_rules[1:]:
|
||||
if val != [p[k] for k in fields]:
|
||||
all_rules_same = False
|
||||
break
|
||||
|
||||
return all_rules_same
|
||||
|
||||
def apply_internal_priority(pricing_rules, field_set, args):
|
||||
filtered_rules = []
|
||||
for field in field_set:
|
||||
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
|
||||
|
@ -17,6 +17,7 @@ class TestPricingRule(unittest.TestCase):
|
||||
"doctype": "Pricing Rule",
|
||||
"apply_on": "Item Code",
|
||||
"item_code": "_Test Item",
|
||||
"selling": 1,
|
||||
"price_or_discount": "Discount Percentage",
|
||||
"price": 0,
|
||||
"discount_percentage": 10,
|
||||
@ -29,13 +30,15 @@ class TestPricingRule(unittest.TestCase):
|
||||
"company": "_Test Company",
|
||||
"price_list": "_Test Price List",
|
||||
"currency": "_Test Currency",
|
||||
"doctype": "Sales Order",
|
||||
"parenttype": "Sales Order",
|
||||
"conversion_rate": 1,
|
||||
"price_list_currency": "_Test Currency",
|
||||
"plc_conversion_rate": 1,
|
||||
"order_type": "Sales",
|
||||
"transaction_type": "selling",
|
||||
"customer": "_Test Customer",
|
||||
"doctype": "Sales Order Item",
|
||||
"name": None
|
||||
})
|
||||
details = get_item_details(args)
|
||||
self.assertEquals(details.get("discount_percentage"), 10)
|
||||
@ -71,7 +74,7 @@ class TestPricingRule(unittest.TestCase):
|
||||
self.assertEquals(details.get("discount_percentage"), 5)
|
||||
|
||||
frappe.db.sql("update `tabPricing Rule` set priority=NULL where campaign='_Test Campaign'")
|
||||
from erpnext.stock.get_item_details import MultiplePricingRuleConflict
|
||||
from erpnext.accounts.doctype.pricing_rule.pricing_rule import MultiplePricingRuleConflict
|
||||
self.assertRaises(MultiplePricingRuleConflict, get_item_details, args)
|
||||
|
||||
args.item_code = "_Test Item 2"
|
||||
|
@ -231,6 +231,14 @@
|
||||
"print_hide": 1,
|
||||
"read_only": 0
|
||||
},
|
||||
{
|
||||
"fieldname": "ignore_pricing_rule",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Pricing Rule",
|
||||
"no_copy": 1,
|
||||
"permlevel": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "items",
|
||||
"fieldtype": "Section Break",
|
||||
@ -744,7 +752,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2014-06-04 08:45:25.582170",
|
||||
"modified": "2014-06-19 15:50:50.898237",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Purchase Invoice",
|
||||
@ -823,6 +831,12 @@
|
||||
"role": "Auditor",
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"role": "Accounts Manager",
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only_onload": 1,
|
||||
|
@ -241,6 +241,14 @@
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "ignore_pricing_rule",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Pricing Rule",
|
||||
"no_copy": 1,
|
||||
"permlevel": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "items",
|
||||
"fieldtype": "Section Break",
|
||||
@ -1180,7 +1188,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2014-05-27 03:49:17.806077",
|
||||
"modified": "2014-06-19 16:01:19.720382",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Accounts",
|
||||
"name": "Sales Invoice",
|
||||
@ -1225,6 +1233,12 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Customer"
|
||||
},
|
||||
{
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"role": "Accounts Manager",
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only_onload": 1,
|
||||
|
@ -197,6 +197,14 @@
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "ignore_pricing_rule",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Pricing Rule",
|
||||
"no_copy": 1,
|
||||
"permlevel": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "items",
|
||||
"fieldtype": "Section Break",
|
||||
@ -636,7 +644,7 @@
|
||||
"icon": "icon-file-text",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2014-05-27 03:49:15.948363",
|
||||
"modified": "2014-06-19 15:58:06.375217",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Purchase Order",
|
||||
@ -696,6 +704,12 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Supplier"
|
||||
},
|
||||
{
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"role": "Purchase Manager",
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only_onload": 1,
|
||||
|
@ -187,12 +187,13 @@ class PurchaseOrder(BuyingController):
|
||||
def on_update(self):
|
||||
pass
|
||||
|
||||
def set_missing_values(source, target):
|
||||
target.ignore_pricing_rule = 1
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_purchase_receipt(source_name, target_doc=None):
|
||||
def set_missing_values(source, target):
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
||||
def update_item(obj, target, source_parent):
|
||||
target.qty = flt(obj.qty) - flt(obj.received_qty)
|
||||
target.stock_qty = (flt(obj.qty) - flt(obj.received_qty)) * flt(obj.conversion_factor)
|
||||
@ -226,10 +227,6 @@ def make_purchase_receipt(source_name, target_doc=None):
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_purchase_invoice(source_name, target_doc=None):
|
||||
def set_missing_values(source, target):
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
||||
def update_item(obj, target, source_parent):
|
||||
target.amount = flt(obj.amount) - flt(obj.billed_amt)
|
||||
target.base_amount = target.amount * flt(source_parent.conversion_rate)
|
||||
|
@ -196,6 +196,14 @@
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "ignore_pricing_rule",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Pricing Rule",
|
||||
"no_copy": 1,
|
||||
"permlevel": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "items",
|
||||
"fieldtype": "Section Break",
|
||||
@ -562,7 +570,7 @@
|
||||
"icon": "icon-shopping-cart",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2014-05-27 03:49:20.226683",
|
||||
"modified": "2014-06-19 15:54:27.919675",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Buying",
|
||||
"name": "Supplier Quotation",
|
||||
@ -640,6 +648,12 @@
|
||||
"role": "Supplier",
|
||||
"submit": 0,
|
||||
"write": 0
|
||||
},
|
||||
{
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"role": "Purchase Manager",
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only_onload": 1,
|
||||
|
@ -54,6 +54,7 @@ class SupplierQuotation(BuyingController):
|
||||
@frappe.whitelist()
|
||||
def make_purchase_order(source_name, target_doc=None):
|
||||
def set_missing_values(source, target):
|
||||
target.ignore_pricing_rule = 1
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("get_schedule_dates")
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
@ -89,14 +89,14 @@ class AccountsController(TransactionBase):
|
||||
"""set missing item values"""
|
||||
from erpnext.stock.get_item_details import get_item_details
|
||||
if hasattr(self, "fname"):
|
||||
parent_dict = {"doctype": self.doctype}
|
||||
parent_dict = {}
|
||||
for fieldname in self.meta.get_valid_columns():
|
||||
parent_dict[fieldname] = self.get(fieldname)
|
||||
|
||||
for item in self.get(self.fname):
|
||||
if item.get("item_code"):
|
||||
args = item.as_dict()
|
||||
args.update(parent_dict)
|
||||
args = parent_dict.copy()
|
||||
args.update(item.as_dict())
|
||||
ret = get_item_details(args)
|
||||
|
||||
for fieldname, value in ret.items():
|
||||
|
@ -62,3 +62,4 @@ erpnext.patches.v4_0.update_other_charges_in_custom_purchase_print_formats
|
||||
erpnext.patches.v4_0.create_price_list_if_missing
|
||||
execute:frappe.db.sql("update `tabItem` set end_of_life=null where end_of_life='0000-00-00'") #2014-06-16
|
||||
erpnext.patches.v4_0.update_users_report_view_settings
|
||||
erpnext.patches.v4_0.set_pricing_rule_for_buying_or_selling
|
||||
|
@ -0,0 +1,12 @@
|
||||
# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors
|
||||
# License: GNU General Public License v3. See license.txt
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
|
||||
def execute():
|
||||
frappe.db.sql("""update `tabPricing Rule` set selling=1 where ifnull(applicable_for, '') in
|
||||
('', 'Customer', 'Customer Group', 'Territory', 'Sales Partner', 'Campaign')""")
|
||||
|
||||
frappe.db.sql("""update `tabPricing Rule` set buying=1 where ifnull(applicable_for, '') in
|
||||
('', 'Supplier', 'Supplier Type')""")
|
@ -116,8 +116,8 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
||||
barcode: item.barcode,
|
||||
serial_no: item.serial_no,
|
||||
warehouse: item.warehouse,
|
||||
doctype: me.frm.doc.doctype,
|
||||
docname: me.frm.doc.name,
|
||||
parenttype: me.frm.doc.doctype,
|
||||
parent: me.frm.doc.name,
|
||||
customer: me.frm.doc.customer,
|
||||
supplier: me.frm.doc.supplier,
|
||||
currency: me.frm.doc.currency,
|
||||
@ -130,7 +130,10 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
||||
order_type: me.frm.doc.order_type,
|
||||
is_pos: cint(me.frm.doc.is_pos),
|
||||
is_subcontracted: me.frm.doc.is_subcontracted,
|
||||
transaction_date: me.frm.doc.transaction_date
|
||||
transaction_date: me.frm.doc.transaction_date,
|
||||
ignore_pricing_rule: me.frm.doc.ignore_pricing_rule,
|
||||
doctype: item.doctype,
|
||||
name: item.name
|
||||
}
|
||||
},
|
||||
callback: function(r) {
|
||||
@ -196,7 +199,7 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
||||
}
|
||||
|
||||
this.frm.script_manager.trigger("currency");
|
||||
this.apply_pricing_rule()
|
||||
this.apply_pricing_rule();
|
||||
}
|
||||
},
|
||||
|
||||
@ -229,7 +232,12 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
||||
this.frm.set_value("plc_conversion_rate", this.frm.doc.conversion_rate);
|
||||
}
|
||||
if(flt(this.frm.doc.conversion_rate)>0.0) {
|
||||
this.apply_pricing_rule();
|
||||
if(this.frm.doc.ignore_pricing_rule) {
|
||||
this.calculate_taxes_and_totals();
|
||||
} else {
|
||||
this.apply_pricing_rule();
|
||||
}
|
||||
|
||||
}
|
||||
},
|
||||
|
||||
@ -283,12 +291,11 @@ 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.apply_pricing_rule();
|
||||
}
|
||||
},
|
||||
|
||||
qty: function(doc, cdt, cdn) {
|
||||
this.apply_pricing_rule(frappe.get_doc(cdt, cdn));
|
||||
this.apply_pricing_rule(frappe.get_doc(cdt, cdn), true);
|
||||
},
|
||||
|
||||
// tax rate
|
||||
@ -331,51 +338,71 @@ erpnext.TransactionController = erpnext.stock.StockController.extend({
|
||||
this.calculate_taxes_and_totals();
|
||||
},
|
||||
|
||||
apply_pricing_rule: function(item) {
|
||||
ignore_pricing_rule: function() {
|
||||
this.apply_pricing_rule();
|
||||
},
|
||||
|
||||
apply_pricing_rule: function(item, calculate_taxes_and_totals) {
|
||||
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);
|
||||
}
|
||||
var item_list = this._get_item_list(item);
|
||||
var args = {
|
||||
"item_list": item_list,
|
||||
"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,
|
||||
"ignore_pricing_rule": me.frm.doc.ignore_pricing_rule,
|
||||
"parenttype": me.frm.doc.doctype,
|
||||
"parent": me.frm.doc.name
|
||||
};
|
||||
return this.frm.call({
|
||||
method: "erpnext.accounts.doctype.pricing_rule.pricing_rule.apply_pricing_rule",
|
||||
args: { args: args },
|
||||
callback: function(r) {
|
||||
if (!r.exc) {
|
||||
$.each(r.message, function(i, d) {
|
||||
$.each(d, function(k, v) {
|
||||
if (["doctype", "name"].indexOf(k)===-1) {
|
||||
frappe.model.set_value(d.doctype, d.name, k, v);
|
||||
}
|
||||
});
|
||||
});
|
||||
if(calculate_taxes_and_totals) me.calculate_taxes_and_totals();
|
||||
}
|
||||
}
|
||||
});
|
||||
},
|
||||
|
||||
_get_item_list: function(item) {
|
||||
var item_list = [];
|
||||
var append_item = function(d) {
|
||||
item_list.push({
|
||||
"doctype": d.doctype,
|
||||
"name": d.name,
|
||||
"item_code": d.item_code,
|
||||
"item_group": d.item_group,
|
||||
"brand": d.brand,
|
||||
"qty": d.qty
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
if(item) {
|
||||
_apply_pricing_rule(item);
|
||||
if (item) {
|
||||
append_item(item);
|
||||
} else {
|
||||
$.each(this.get_item_doclist(), function(n, item) {
|
||||
_apply_pricing_rule(item);
|
||||
$.each(this.get_item_doclist(), function(i, d) {
|
||||
append_item(d);
|
||||
});
|
||||
}
|
||||
return item_list;
|
||||
},
|
||||
|
||||
included_in_print_rate: function(doc, cdt, cdn) {
|
||||
|
@ -274,6 +274,14 @@
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "ignore_pricing_rule",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Pricing Rule",
|
||||
"no_copy": 1,
|
||||
"permlevel": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "items",
|
||||
"fieldtype": "Section Break",
|
||||
@ -818,7 +826,7 @@
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"max_attachments": 1,
|
||||
"modified": "2014-05-27 03:49:16.670976",
|
||||
"modified": "2014-06-19 15:59:30.019826",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Quotation",
|
||||
@ -896,6 +904,12 @@
|
||||
"role": "Maintenance User",
|
||||
"submit": 1,
|
||||
"write": 1
|
||||
},
|
||||
{
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"role": "Sales Manager",
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only_onload": 1,
|
||||
|
@ -102,7 +102,7 @@ def _make_sales_order(source_name, target_doc=None, ignore_permissions=False):
|
||||
if customer:
|
||||
target.customer = customer.name
|
||||
target.customer_name = customer.customer_name
|
||||
|
||||
target.ignore_pricing_rule = 1
|
||||
target.ignore_permissions = ignore_permissions
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
@ -285,6 +285,14 @@
|
||||
"print_hide": 1,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "ignore_pricing_rule",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Pricing Rule",
|
||||
"no_copy": 1,
|
||||
"permlevel": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "items",
|
||||
"fieldtype": "Section Break",
|
||||
@ -874,7 +882,7 @@
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"issingle": 0,
|
||||
"modified": "2014-05-27 08:39:19.027965",
|
||||
"modified": "2014-06-19 16:00:06.626037",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Selling",
|
||||
"name": "Sales Order",
|
||||
@ -953,6 +961,12 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Material User"
|
||||
},
|
||||
{
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"role": "Sales Manager",
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only_onload": 1,
|
||||
|
@ -245,9 +245,6 @@ class SalesOrder(SellingController):
|
||||
def get_portal_page(self):
|
||||
return "order" if self.docstatus==1 else None
|
||||
|
||||
def set_missing_values(source, target):
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_material_request(source_name, target_doc=None):
|
||||
@ -274,6 +271,11 @@ def make_material_request(source_name, target_doc=None):
|
||||
|
||||
@frappe.whitelist()
|
||||
def make_delivery_note(source_name, target_doc=None):
|
||||
def set_missing_values(source, target):
|
||||
target.ignore_pricing_rule = 1
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
||||
def update_item(source, target, source_parent):
|
||||
target.base_amount = (flt(source.qty) - flt(source.delivered_qty)) * flt(source.base_rate)
|
||||
target.amount = (flt(source.qty) - flt(source.delivered_qty)) * flt(source.rate)
|
||||
@ -312,6 +314,7 @@ def make_delivery_note(source_name, target_doc=None):
|
||||
def make_sales_invoice(source_name, target_doc=None):
|
||||
def set_missing_values(source, target):
|
||||
target.is_pos = 0
|
||||
target.ignore_pricing_rule = 1
|
||||
target.run_method("set_missing_values")
|
||||
target.run_method("calculate_taxes_and_totals")
|
||||
|
||||
|
@ -275,6 +275,14 @@
|
||||
"read_only": 0,
|
||||
"reqd": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "ignore_pricing_rule",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Pricing Rule",
|
||||
"no_copy": 1,
|
||||
"permlevel": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "items",
|
||||
"fieldtype": "Section Break",
|
||||
@ -999,7 +1007,7 @@
|
||||
"idx": 1,
|
||||
"in_create": 0,
|
||||
"is_submittable": 1,
|
||||
"modified": "2014-05-27 03:49:09.721622",
|
||||
"modified": "2014-06-19 16:00:47.326127",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Delivery Note",
|
||||
@ -1073,6 +1081,12 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Customer"
|
||||
},
|
||||
{
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"role": "Material Manager",
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only_onload": 1,
|
||||
|
@ -280,6 +280,7 @@ def make_sales_invoice(source_name, target_doc=None):
|
||||
|
||||
def update_accounts(source, target):
|
||||
target.is_pos = 0
|
||||
target.ignore_pricing_rule = 1
|
||||
target.run_method("set_missing_values")
|
||||
|
||||
if len(target.get("entries")) == 0:
|
||||
|
@ -17,7 +17,7 @@ class TestItem(unittest.TestCase):
|
||||
item.is_stock_item = "Yes"
|
||||
item.default_warehouse = None
|
||||
self.assertRaises(WarehouseNotSet, item.insert)
|
||||
|
||||
|
||||
def test_get_item_details(self):
|
||||
from erpnext.stock.get_item_details import get_item_details
|
||||
to_check = {
|
||||
@ -41,23 +41,23 @@ class TestItem(unittest.TestCase):
|
||||
"uom": "_Test UOM",
|
||||
"conversion_factor": 1.0,
|
||||
}
|
||||
|
||||
|
||||
make_test_records("Item Price")
|
||||
|
||||
|
||||
details = get_item_details({
|
||||
"item_code": "_Test Item",
|
||||
"company": "_Test Company",
|
||||
"price_list": "_Test Price List",
|
||||
"currency": "_Test Currency",
|
||||
"doctype": "Sales Order",
|
||||
"parenttype": "Sales Order",
|
||||
"conversion_rate": 1,
|
||||
"price_list_currency": "_Test Currency",
|
||||
"plc_conversion_rate": 1,
|
||||
"order_type": "Sales",
|
||||
"transaction_type": "selling"
|
||||
})
|
||||
|
||||
|
||||
for key, value in to_check.iteritems():
|
||||
self.assertEquals(value, details.get(key))
|
||||
|
||||
test_records = frappe.get_test_records('Item')
|
||||
test_records = frappe.get_test_records('Item')
|
||||
|
@ -195,6 +195,14 @@
|
||||
"permlevel": 0,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "ignore_pricing_rule",
|
||||
"fieldtype": "Check",
|
||||
"label": "Ignore Pricing Rule",
|
||||
"no_copy": 1,
|
||||
"permlevel": 1,
|
||||
"print_hide": 1
|
||||
},
|
||||
{
|
||||
"fieldname": "items",
|
||||
"fieldtype": "Section Break",
|
||||
@ -754,7 +762,7 @@
|
||||
"icon": "icon-truck",
|
||||
"idx": 1,
|
||||
"is_submittable": 1,
|
||||
"modified": "2014-05-27 03:49:16.302198",
|
||||
"modified": "2014-06-19 15:58:37.932064",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Purchase Receipt",
|
||||
@ -821,6 +829,12 @@
|
||||
"read": 1,
|
||||
"report": 1,
|
||||
"role": "Supplier"
|
||||
},
|
||||
{
|
||||
"permlevel": 1,
|
||||
"read": 1,
|
||||
"role": "Material Manager",
|
||||
"write": 1
|
||||
}
|
||||
],
|
||||
"read_only_onload": 1,
|
||||
|
@ -287,6 +287,7 @@ def make_purchase_invoice(source_name, target_doc=None):
|
||||
frappe.throw(_("All items have already been invoiced"))
|
||||
|
||||
doc = frappe.get_doc(target)
|
||||
doc.ignore_pricing_rule = 1
|
||||
doc.run_method("set_missing_values")
|
||||
doc.run_method("calculate_taxes_and_totals")
|
||||
|
||||
|
@ -6,8 +6,7 @@ import frappe
|
||||
from frappe import _, throw
|
||||
from frappe.utils import flt, cint, add_days
|
||||
import json
|
||||
|
||||
class MultiplePricingRuleConflict(frappe.ValidationError): pass
|
||||
from erpnext.accounts.doctype.pricing_rule.pricing_rule import get_pricing_rule_for_item
|
||||
|
||||
@frappe.whitelist()
|
||||
def get_item_details(args):
|
||||
@ -20,14 +19,15 @@ def get_item_details(args):
|
||||
"selling_price_list": None,
|
||||
"price_list_currency": None,
|
||||
"plc_conversion_rate": 1.0,
|
||||
"doctype": "",
|
||||
"docname": "",
|
||||
"parenttype": "",
|
||||
"parent": "",
|
||||
"supplier": None,
|
||||
"transaction_date": None,
|
||||
"conversion_rate": 1.0,
|
||||
"buying_price_list": None,
|
||||
"is_subcontracted": "Yes" / "No",
|
||||
"transaction_type": "selling"
|
||||
"transaction_type": "selling",
|
||||
"ignore_pricing_rule": 0/1
|
||||
}
|
||||
"""
|
||||
|
||||
@ -37,7 +37,8 @@ def get_item_details(args):
|
||||
args = frappe._dict(args)
|
||||
|
||||
if not args.get("transaction_type"):
|
||||
if args.get("doctype")=="Material Request" or frappe.get_meta(args.get("doctype")).get_field("supplier"):
|
||||
if args.get("parenttype")=="Material Request" or \
|
||||
frappe.get_meta(args.get("parenttype")).get_field("supplier"):
|
||||
args.transaction_type = "buying"
|
||||
else:
|
||||
args.transaction_type = "selling"
|
||||
@ -73,9 +74,9 @@ def get_item_details(args):
|
||||
if args.get(key) is None:
|
||||
args[key] = value
|
||||
|
||||
out.update(apply_pricing_rule(args))
|
||||
out.update(get_pricing_rule_for_item(args))
|
||||
|
||||
if args.get("doctype") in ("Sales Invoice", "Delivery Note"):
|
||||
if args.get("parenttype") in ("Sales Invoice", "Delivery Note"):
|
||||
if item_doc.has_serial_no == "Yes" and not args.serial_no:
|
||||
out.serial_no = get_serial_nos_by_fifo(args, item_doc)
|
||||
|
||||
@ -113,7 +114,7 @@ def validate_item_details(args, item):
|
||||
elif item.is_sales_item != "Yes":
|
||||
throw(_("Item {0} must be a Sales Item").format(item.name))
|
||||
|
||||
elif args.transaction_type == "buying" and args.doctype != "Material Request":
|
||||
elif args.transaction_type == "buying" and args.parenttype != "Material Request":
|
||||
# validate if purchase item or subcontracted item
|
||||
if item.is_purchase_item != "Yes":
|
||||
throw(_("Item {0} must be a Purchase Item").format(item.name))
|
||||
@ -144,7 +145,7 @@ def get_basic_details(args, item_doc):
|
||||
"item_tax_rate": json.dumps(dict(([d.tax_type, d.tax_rate] for d in
|
||||
item_doc.get("item_tax")))),
|
||||
"uom": item.stock_uom,
|
||||
"min_order_qty": flt(item.min_order_qty) if args.doctype == "Material Request" else "",
|
||||
"min_order_qty": flt(item.min_order_qty) if args.parenttype == "Material Request" else "",
|
||||
"conversion_factor": 1.0,
|
||||
"qty": 1.0,
|
||||
"price_list_rate": 0.0,
|
||||
@ -162,7 +163,7 @@ def get_basic_details(args, item_doc):
|
||||
return out
|
||||
|
||||
def get_price_list_rate(args, item_doc, out):
|
||||
meta = frappe.get_meta(args.doctype)
|
||||
meta = frappe.get_meta(args.parenttype)
|
||||
|
||||
if meta.get_field("currency"):
|
||||
validate_price_list(args)
|
||||
@ -179,7 +180,7 @@ def get_price_list_rate(args, item_doc, out):
|
||||
if not out.price_list_rate and args.transaction_type == "buying":
|
||||
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
||||
out.update(get_last_purchase_details(item_doc.name,
|
||||
args.docname, args.conversion_rate))
|
||||
args.parent, args.conversion_rate))
|
||||
|
||||
def validate_price_list(args):
|
||||
if args.get("price_list"):
|
||||
@ -248,142 +249,6 @@ def get_pos_settings(company):
|
||||
|
||||
return pos_settings and pos_settings[0] or None
|
||||
|
||||
@frappe.whitelist()
|
||||
def apply_pricing_rule(args):
|
||||
if isinstance(args, basestring):
|
||||
args = json.loads(args)
|
||||
|
||||
args = frappe._dict(args)
|
||||
out = frappe._dict()
|
||||
if args.get("doctype") == "Material Request" or not args.get("item_code"): return out
|
||||
|
||||
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 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 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)
|
||||
|
||||
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.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))
|
||||
|
||||
if parent_groups:
|
||||
if allow_blank: parent_groups.append('')
|
||||
condition = " ifnull("+field+", '') in ('" + "', '".join(parent_groups)+"')"
|
||||
|
||||
return condition
|
||||
|
||||
|
||||
conditions = ""
|
||||
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+", '') = ''"
|
||||
|
||||
for doctype in ["Customer Group", "Territory"]:
|
||||
group_condition = _get_tree_conditions(doctype)
|
||||
if group_condition:
|
||||
conditions += " and " + group_condition
|
||||
|
||||
conditions += " and ifnull(for_price_list, '') in (%(price_list)s, '')"
|
||||
|
||||
if args.get("transaction_date"):
|
||||
conditions += """ and %(transaction_date)s between ifnull(valid_from, '2000-01-01')
|
||||
and ifnull(valid_upto, '2500-12-31')"""
|
||||
|
||||
return frappe.db.sql("""select * from `tabPricing Rule`
|
||||
where (item_code=%(item_code)s or {item_group_condition} or brand=%(brand)s)
|
||||
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, as_dict=1)
|
||||
|
||||
def filter_pricing_rules(args, pricing_rules):
|
||||
# filter for qty
|
||||
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:
|
||||
max_priority = max([cint(p.priority) for p in pricing_rules])
|
||||
if max_priority:
|
||||
pricing_rules = filter(lambda x: cint(x.priority)==max_priority, pricing_rules)
|
||||
|
||||
# apply internal priority
|
||||
all_fields = ["item_code", "item_group", "brand", "customer", "customer_group", "territory",
|
||||
"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)
|
||||
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) \
|
||||
or pricing_rules
|
||||
|
||||
if len(pricing_rules) > 1:
|
||||
frappe.throw(_("Multiple Price Rule exists with same criteria, please resolve \
|
||||
conflict by assigning priority. Price Rules: {0}")
|
||||
.format("\n".join([d.name for d in pricing_rules])), MultiplePricingRuleConflict)
|
||||
elif pricing_rules:
|
||||
return pricing_rules[0]
|
||||
|
||||
def if_all_rules_same(pricing_rules, fields):
|
||||
all_rules_same = True
|
||||
val = [pricing_rules[0][k] for k in fields]
|
||||
for p in pricing_rules[1:]:
|
||||
if val != [p[k] for k in fields]:
|
||||
all_rules_same = False
|
||||
break
|
||||
|
||||
return all_rules_same
|
||||
|
||||
def apply_internal_priority(pricing_rules, field_set, args):
|
||||
filtered_rules = []
|
||||
for field in field_set:
|
||||
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
|
||||
|
||||
def get_serial_nos_by_fifo(args, item_doc):
|
||||
return "\n".join(frappe.db.sql_list("""select name from `tabSerial No`
|
||||
|
Loading…
x
Reference in New Issue
Block a user