Additional fields in Item Price (#14540)
* [IMPROVEMENT] Item Price New Fields and Features * [IMPROVEMENT] Item Price - Item Price insert against Qty, Supplier/Customer, Validup/Validfrom - Stock Setting to accept Default Price List for Purchase or Sales Item - Move Item Section in Item Price * Fetch default Item Price based on Customer as null * test fixes * Code cleanup and fixed the issue of incorrect item price fetched against the customer * Removed min qty from packing_increment calculation * Removed auto_update_price_list_rate from the stock settings * Revert sales_order.json changes * Removed sales, purchase price list from stock settings because this fields are already available in selling, buying settings * Removed unnecessory file * Fixed item price validation code
This commit is contained in:
parent
7d9a1db97a
commit
e45ec661ea
@ -49,6 +49,9 @@ frappe.ui.form.on("Purchase Order", {
|
||||
|
||||
onload: function(frm) {
|
||||
set_schedule_date(frm);
|
||||
if (!frm.doc.transaction_date){
|
||||
frm.set_value('transaction_date', frappe.datetime.get_today())
|
||||
}
|
||||
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
return erpnext.queries.warehouse(frm.doc);
|
||||
|
@ -93,7 +93,9 @@ erpnext.buying.BuyingController = erpnext.TransactionController.extend({
|
||||
|
||||
supplier: function() {
|
||||
var me = this;
|
||||
erpnext.utils.get_party_details(this.frm, null, null, function(){me.apply_pricing_rule()});
|
||||
erpnext.utils.get_party_details(this.frm, null, null, function(){
|
||||
me.apply_price_list();
|
||||
});
|
||||
},
|
||||
|
||||
supplier_address: function() {
|
||||
|
@ -342,6 +342,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
conversion_factor: item.conversion_factor,
|
||||
weight_per_unit: item.weight_per_unit,
|
||||
weight_uom: item.weight_uom,
|
||||
uom : item.uom,
|
||||
pos_profile: me.frm.doc.doctype == 'Sales Invoice' ? me.frm.doc.pos_profile : ''
|
||||
}
|
||||
},
|
||||
@ -1016,6 +1017,7 @@ erpnext.TransactionController = erpnext.taxes_and_totals.extend({
|
||||
"item_group": d.item_group,
|
||||
"brand": d.brand,
|
||||
"qty": d.qty,
|
||||
"uom": d.uom,
|
||||
"parenttype": d.parenttype,
|
||||
"parent": d.parent,
|
||||
"pricing_rule": d.pricing_rule,
|
||||
|
@ -30,6 +30,9 @@ frappe.ui.form.on("Sales Order", {
|
||||
}
|
||||
},
|
||||
onload: function(frm) {
|
||||
if (!frm.doc.transaction_date){
|
||||
frm.set_value('transaction_date', frappe.datetime.get_today())
|
||||
}
|
||||
erpnext.queries.setup_queries(frm, "Warehouse", function() {
|
||||
return erpnext.queries.warehouse(frm.doc);
|
||||
});
|
||||
|
@ -96,8 +96,9 @@ erpnext.selling.SellingController = erpnext.TransactionController.extend({
|
||||
|
||||
customer: function() {
|
||||
var me = this;
|
||||
erpnext.utils.get_party_details(this.frm, null, null,
|
||||
function(){ me.apply_pricing_rule() });
|
||||
erpnext.utils.get_party_details(this.frm, null, null, function() {
|
||||
me.apply_price_list();
|
||||
});
|
||||
},
|
||||
|
||||
customer_address: function() {
|
||||
@ -429,4 +430,4 @@ frappe.ui.form.on(cur_frm.doctype,"project", function(frm) {
|
||||
})
|
||||
}
|
||||
}
|
||||
})
|
||||
})
|
||||
|
@ -11,6 +11,7 @@ frappe.ui.form.on("Item Price", {
|
||||
// Fetch item details
|
||||
frm.add_fetch("item_code", "item_name", "item_name");
|
||||
frm.add_fetch("item_code", "description", "item_description");
|
||||
frm.add_fetch("item_code", "stock_uom", "uom");
|
||||
|
||||
frm.set_df_property("bulk_import_help", "options",
|
||||
'<a href="#data-import-tool/Item Price">' + __("Import in Bulk") + '</a>');
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -3,41 +3,60 @@
|
||||
|
||||
from __future__ import unicode_literals
|
||||
import frappe
|
||||
from frappe import throw, _
|
||||
from frappe import _
|
||||
|
||||
|
||||
class ItemPriceDuplicateItem(frappe.ValidationError): pass
|
||||
|
||||
|
||||
from frappe.model.document import Document
|
||||
|
||||
|
||||
class ItemPrice(Document):
|
||||
|
||||
def validate(self):
|
||||
self.validate_item()
|
||||
self.validate_price_list()
|
||||
self.check_duplicate_item()
|
||||
self.validate_dates()
|
||||
self.update_price_list_details()
|
||||
self.update_item_details()
|
||||
self.check_duplicates()
|
||||
|
||||
def validate_item(self):
|
||||
if not frappe.db.exists("Item", self.item_code):
|
||||
throw(_("Item {0} not found").format(self.item_code))
|
||||
frappe.throw(_("Item {0} not found").format(self.item_code))
|
||||
|
||||
def validate_price_list(self):
|
||||
enabled = frappe.db.get_value("Price List", self.price_list, "enabled")
|
||||
if not enabled:
|
||||
throw(_("Price List {0} is disabled").format(self.price_list))
|
||||
|
||||
def check_duplicate_item(self):
|
||||
if frappe.db.sql("""select name from `tabItem Price`
|
||||
where item_code=%s and price_list=%s and name!=%s""", (self.item_code, self.price_list, self.name)):
|
||||
|
||||
frappe.throw(_("Item {0} appears multiple times in Price List {1}").format(self.item_code, self.price_list),
|
||||
ItemPriceDuplicateItem)
|
||||
def validate_dates(self):
|
||||
if self.valid_from and self.valid_upto:
|
||||
if self.valid_from > self.valid_upto:
|
||||
frappe.throw(_("Valid From Date must be lesser than Valid Upto Date."))
|
||||
|
||||
def update_price_list_details(self):
|
||||
self.buying, self.selling, self.currency = \
|
||||
frappe.db.get_value("Price List", {"name": self.price_list, "enabled": 1},
|
||||
["buying", "selling", "currency"])
|
||||
frappe.db.get_value("Price List",
|
||||
{"name": self.price_list, "enabled": 1},
|
||||
["buying", "selling", "currency"])
|
||||
|
||||
def update_item_details(self):
|
||||
self.item_name, self.item_description = frappe.db.get_value("Item",
|
||||
self.item_code, ["item_name", "description"])
|
||||
self.item_name, self.item_description = frappe.db.get_value("Item",self.item_code,["item_name", "description"])
|
||||
|
||||
def check_duplicates(self):
|
||||
conditions = "where item_code=%(item_code)s and price_list=%(price_list)s and name != %(name)s"
|
||||
|
||||
for field in ['uom', 'min_qty', 'valid_from',
|
||||
'valid_upto', 'packing_unit', 'customer', 'supplier']:
|
||||
if self.get(field):
|
||||
conditions += " and {0} = %({1})s".format(field, field)
|
||||
|
||||
price_list_rate = frappe.db.sql("""
|
||||
SELECT price_list_rate
|
||||
FROM `tabItem Price`
|
||||
{conditions} """.format(conditions=conditions), self.as_dict())
|
||||
|
||||
if price_list_rate :
|
||||
frappe.throw(_("Item Price appears multiple times based on Price List, Supplier/Customer, Currency, Item, UOM, Qty and Dates."), ItemPriceDuplicateItem)
|
||||
|
||||
def before_save(self):
|
||||
if self.selling:
|
||||
self.reference = self.customer
|
||||
if self.buying:
|
||||
self.reference = self.supplier
|
||||
|
@ -19,4 +19,4 @@ QUnit.test("test item price", function(assert) {
|
||||
() => frappe.timeout(0.3),
|
||||
() => done()
|
||||
]);
|
||||
});
|
||||
});
|
||||
|
@ -4,11 +4,144 @@
|
||||
from __future__ import unicode_literals
|
||||
import unittest
|
||||
import frappe
|
||||
from frappe.test_runner import make_test_records_for_doctype
|
||||
from erpnext.stock.get_item_details import get_price_list_rate_for, process_args
|
||||
from erpnext.stock.doctype.item_price.item_price import ItemPriceDuplicateItem
|
||||
|
||||
|
||||
class TestItemPrice(unittest.TestCase):
|
||||
def setUp(self):
|
||||
frappe.db.sql("delete from `tabItem Price`")
|
||||
make_test_records_for_doctype("Item Price", force=True)
|
||||
|
||||
class TestItem(unittest.TestCase):
|
||||
def test_duplicate_item(self):
|
||||
from erpnext.stock.doctype.item_price.item_price import ItemPriceDuplicateItem
|
||||
doc = frappe.copy_doc(test_records[0])
|
||||
self.assertRaises(ItemPriceDuplicateItem, doc.save)
|
||||
|
||||
test_records = frappe.get_test_records('Item Price')
|
||||
def test_addition_of_new_fields(self):
|
||||
# Based on https://github.com/frappe/erpnext/issues/8456
|
||||
test_fields_existance = [
|
||||
'supplier', 'customer', 'uom', 'min_qty', 'lead_time_days',
|
||||
'packing_unit', 'valid_from', 'valid_upto', 'note'
|
||||
]
|
||||
doc_fields = frappe.copy_doc(test_records[1]).__dict__.keys()
|
||||
|
||||
for test_field in test_fields_existance:
|
||||
self.assertTrue(test_field in doc_fields)
|
||||
|
||||
def test_dates_validation_error(self):
|
||||
doc = frappe.copy_doc(test_records[1])
|
||||
# Enter invalid dates valid_from >= valid_upto
|
||||
doc.valid_from = "2017-04-20"
|
||||
doc.valid_upto = "2017-04-17"
|
||||
# Valid Upto Date can not be less/equal than Valid From Date
|
||||
self.assertRaises(frappe.ValidationError, doc.save)
|
||||
|
||||
def test_price_in_a_qty(self):
|
||||
# Check correct price at this quantity
|
||||
doc = frappe.copy_doc(test_records[2])
|
||||
|
||||
args = {
|
||||
"price_list": doc.price_list,
|
||||
"min_qty": doc.min_qty,
|
||||
"customer": doc.customer,
|
||||
"uom": "_Test UOM",
|
||||
"transaction_date": '2017-04-18',
|
||||
"qty": 10
|
||||
}
|
||||
|
||||
price = get_price_list_rate_for(process_args(args), doc.item_code)
|
||||
self.assertEqual(price, 20.0)
|
||||
|
||||
def test_price_with_no_qty(self):
|
||||
# Check correct price when no quantity
|
||||
doc = frappe.copy_doc(test_records[2])
|
||||
args = {
|
||||
"price_list": doc.price_list,
|
||||
"min_qty": 30,
|
||||
"customer": doc.customer,
|
||||
"uom": "_Test UOM",
|
||||
"transaction_date": '2017-04-18',
|
||||
}
|
||||
|
||||
price = get_price_list_rate_for(args, doc.item_code)
|
||||
self.assertEqual(price, None)
|
||||
|
||||
|
||||
def test_prices_at_date(self):
|
||||
# Check correct price at first date
|
||||
doc = frappe.copy_doc(test_records[2])
|
||||
|
||||
args = {
|
||||
"price_list": doc.price_list,
|
||||
"min_qty": doc.min_qty,
|
||||
"customer": "_Test Customer",
|
||||
"uom": "_Test UOM",
|
||||
"transaction_date": '2017-04-18',
|
||||
"qty": 7
|
||||
}
|
||||
|
||||
price = get_price_list_rate_for(args, doc.item_code)
|
||||
self.assertEqual(price, 20)
|
||||
|
||||
def test_prices_at_invalid_date(self):
|
||||
#Check correct price at invalid date
|
||||
doc = frappe.copy_doc(test_records[3])
|
||||
|
||||
args = {
|
||||
"price_list": doc.price_list,
|
||||
"min_qty": doc.min_qty,
|
||||
"qty": 7,
|
||||
"uom": "_Test UOM",
|
||||
"transaction_date": "01-15-2019"
|
||||
}
|
||||
|
||||
price = get_price_list_rate_for(args, doc.item_code)
|
||||
self.assertEqual(price, None)
|
||||
|
||||
def test_prices_outside_of_date(self):
|
||||
#Check correct price when outside of the date
|
||||
doc = frappe.copy_doc(test_records[4])
|
||||
|
||||
args = {
|
||||
"price_list": doc.price_list,
|
||||
"min_qty": doc.min_qty,
|
||||
"customer": "_Test Customer",
|
||||
"uom": "_Test UOM",
|
||||
"transaction_date": "2017-04-25",
|
||||
"qty": 7,
|
||||
}
|
||||
|
||||
price = get_price_list_rate_for(args, doc.item_code)
|
||||
self.assertEqual(price, None)
|
||||
|
||||
def test_lowest_price_when_no_date_provided(self):
|
||||
#Check lowest price when no date provided
|
||||
doc = frappe.copy_doc(test_records[1])
|
||||
|
||||
args = {
|
||||
"price_list": doc.price_list,
|
||||
"min_qty": doc.min_qty,
|
||||
"uom": "_Test UOM",
|
||||
"qty": 7,
|
||||
}
|
||||
|
||||
price = get_price_list_rate_for(args, doc.item_code)
|
||||
self.assertEqual(price, 10)
|
||||
|
||||
|
||||
def test_invalid_item(self):
|
||||
doc = frappe.copy_doc(test_records[1])
|
||||
# Enter invalid item code
|
||||
doc.item_code = "This is not an item code"
|
||||
# Valid item codes must already exist
|
||||
self.assertRaises(frappe.ValidationError, doc.save)
|
||||
|
||||
def test_invalid_price_list(self):
|
||||
doc = frappe.copy_doc(test_records[1])
|
||||
# Check for invalid price list
|
||||
doc.price_list = "This is not a price list"
|
||||
# Valid price list must already exist
|
||||
self.assertRaises(frappe.ValidationError, doc.save)
|
||||
|
||||
test_records = frappe.get_test_records('Item Price')
|
||||
|
@ -3,24 +3,47 @@
|
||||
"doctype": "Item Price",
|
||||
"item_code": "_Test Item",
|
||||
"price_list": "_Test Price List",
|
||||
"price_list_rate": 100
|
||||
"price_list_rate": 100,
|
||||
"min_qty": 2,
|
||||
"valid_from": "2017-04-18",
|
||||
"valid_upto": "2017-04-26"
|
||||
},
|
||||
{
|
||||
"doctype": "Item Price",
|
||||
"item_code": "_Test Item",
|
||||
"price_list": "_Test Price List Rest of the World",
|
||||
"price_list_rate": 10
|
||||
"price_list_rate": 10,
|
||||
"min_qty": 5
|
||||
},
|
||||
{
|
||||
"doctype": "Item Price",
|
||||
"item_code": "_Test Item 2",
|
||||
"price_list": "_Test Price List Rest of the World",
|
||||
"price_list_rate": 20
|
||||
"price_list_rate": 20,
|
||||
"valid_from": "2017-04-18",
|
||||
"valid_upto": "2017-04-26",
|
||||
"min_qty": 7,
|
||||
"customer": "_Test Customer",
|
||||
"uom": "_Test UOM"
|
||||
},
|
||||
{
|
||||
"doctype": "Item Price",
|
||||
"item_code": "_Test Item Home Desktop 100",
|
||||
"price_list": "_Test Price List",
|
||||
"price_list_rate": 1000
|
||||
"price_list_rate": 1000,
|
||||
"min_qty" : 10,
|
||||
"valid_from": "2017-04-10",
|
||||
"valid_upto": "2017-04-17",
|
||||
"min_qty": 2
|
||||
},
|
||||
{
|
||||
"doctype": "Item Price",
|
||||
"item_code": "_Test Item Home Desktop Manufactured",
|
||||
"price_list": "_Test Price List",
|
||||
"price_list_rate": 1000,
|
||||
"min_qty" : 10,
|
||||
"valid_from": "2017-04-10",
|
||||
"valid_upto": "2017-04-17",
|
||||
"min_qty": 2
|
||||
}
|
||||
]
|
||||
|
@ -42,6 +42,7 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -70,6 +71,7 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -101,6 +103,7 @@
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -131,6 +134,7 @@
|
||||
"reqd": 1,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -160,6 +164,7 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -189,6 +194,7 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -219,6 +225,7 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -247,6 +254,7 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
},
|
||||
{
|
||||
@ -278,6 +286,7 @@
|
||||
"reqd": 0,
|
||||
"search_index": 0,
|
||||
"set_only_once": 0,
|
||||
"translatable": 0,
|
||||
"unique": 0
|
||||
}
|
||||
],
|
||||
@ -292,7 +301,7 @@
|
||||
"issingle": 0,
|
||||
"istable": 0,
|
||||
"max_attachments": 1,
|
||||
"modified": "2017-12-01 16:55:00.243382",
|
||||
"modified": "2018-03-30 11:56:28.243161",
|
||||
"modified_by": "Administrator",
|
||||
"module": "Stock",
|
||||
"name": "Price List",
|
||||
|
@ -261,13 +261,14 @@ def get_basic_details(args, item):
|
||||
"is_fixed_asset": item.is_fixed_asset,
|
||||
"weight_per_unit":item.weight_per_unit,
|
||||
"weight_uom":item.weight_uom,
|
||||
"last_purchase_rate": item.last_purchase_rate if args.get("doctype") in ["Purchase Order"] else 0
|
||||
"last_purchase_rate": item.last_purchase_rate if args.get("doctype") in ["Purchase Order"] else 0,
|
||||
"transaction_date": args.get("transaction_date")
|
||||
})
|
||||
|
||||
if item.enable_deferred_revenue:
|
||||
service_end_date = add_months(args.transaction_date, item.no_of_months)
|
||||
out.update({
|
||||
"enable_deferred_revenue": item.enable_deferred_revenue,
|
||||
"enable_deferred_revenue": item.enable_deferred_revenue,
|
||||
"deferred_revenue_account": get_default_deferred_revenue_account(args, item),
|
||||
"service_start_date": args.transaction_date,
|
||||
"service_end_date": service_end_date
|
||||
@ -338,11 +339,7 @@ def get_price_list_rate(args, item_doc, out):
|
||||
if meta.get_field("currency") and args.price_list:
|
||||
validate_conversion_rate(args, meta)
|
||||
|
||||
price_list_rate = get_price_list_rate_for(args.price_list, item_doc.name)
|
||||
|
||||
# variant
|
||||
if not price_list_rate and item_doc.variant_of:
|
||||
price_list_rate = get_price_list_rate_for(args.price_list, item_doc.variant_of)
|
||||
price_list_rate = get_price_list_rate_for(args, item_doc.name) or 0
|
||||
|
||||
# insert in database
|
||||
if not price_list_rate:
|
||||
@ -350,10 +347,12 @@ def get_price_list_rate(args, item_doc, out):
|
||||
insert_item_price(args)
|
||||
return {}
|
||||
|
||||
# variant
|
||||
if not price_list_rate and item_doc.variant_of:
|
||||
price_list_rate = get_price_list_rate_for(args, item_doc.variant_of)
|
||||
|
||||
out.price_list_rate = flt(price_list_rate) * flt(args.plc_conversion_rate) \
|
||||
/ flt(args.conversion_rate)
|
||||
if not args.price_list_uom_dependant:
|
||||
out.price_list_rate = flt(out.price_list_rate * (flt(args.conversion_factor) or 1.0))
|
||||
|
||||
if not out.price_list_rate and args.transaction_type=="buying":
|
||||
from erpnext.stock.doctype.item.item import get_last_purchase_details
|
||||
@ -365,8 +364,8 @@ def insert_item_price(args):
|
||||
if frappe.db.get_value("Price List", args.price_list, "currency") == args.currency \
|
||||
and cint(frappe.db.get_single_value("Stock Settings", "auto_insert_price_list_rate_if_missing")):
|
||||
if frappe.has_permission("Item Price", "write"):
|
||||
price_list_rate = args.rate / args.conversion_factor \
|
||||
if args.get("conversion_factor") else args.rate
|
||||
price_list_rate = (args.rate / args.get('conversion_factor')
|
||||
if args.get("conversion_factor") else args.rate)
|
||||
|
||||
item_price = frappe.get_doc({
|
||||
"doctype": "Item Price",
|
||||
@ -376,7 +375,8 @@ def insert_item_price(args):
|
||||
"price_list_rate": price_list_rate
|
||||
})
|
||||
|
||||
name = frappe.db.get_value('Item Price', {'item_code': args.item_code, 'price_list': args.price_list, 'currency': args.currency}, 'name')
|
||||
name = frappe.db.get_value('Item Price',
|
||||
{'item_code': args.item_code, 'price_list': args.price_list, 'currency': args.currency}, 'name')
|
||||
|
||||
if name:
|
||||
item_price = frappe.get_doc('Item Price', name)
|
||||
@ -389,9 +389,103 @@ def insert_item_price(args):
|
||||
frappe.msgprint(_("Item Price added for {0} in Price List {1}").format(args.item_code,
|
||||
args.price_list))
|
||||
|
||||
def get_price_list_rate_for(price_list, item_code):
|
||||
return frappe.db.get_value("Item Price",
|
||||
{"price_list": price_list, "item_code": item_code}, "price_list_rate")
|
||||
def get_item_price(args, item_code):
|
||||
"""
|
||||
Get name, price_list_rate from Item Price based on conditions
|
||||
Check if the Derised qty is within the increment of the packing list.
|
||||
:param args: dict (or frappe._dict) with mandatory fields price_list, uom
|
||||
optional fields min_qty, transaction_date, customer, supplier
|
||||
:param item_code: str, Item Doctype field item_code
|
||||
"""
|
||||
|
||||
args['item_code'] = item_code
|
||||
conditions = "where (customer is null or customer = '') and (supplier is null or supplier = '')"
|
||||
if args.get("customer"):
|
||||
conditions = "where customer=%(customer)s"
|
||||
|
||||
if args.get("supplier"):
|
||||
conditions = "where supplier=%(supplier)s"
|
||||
|
||||
conditions += """ and item_code=%(item_code)s
|
||||
and price_list=%(price_list)s
|
||||
and ifnull(uom, '') in ('', %(uom)s)"""
|
||||
|
||||
if args.get('min_qty'):
|
||||
conditions += " and ifnull(min_qty, 0) <= %(min_qty)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 name, price_list_rate, uom
|
||||
from `tabItem Price` {conditions}
|
||||
order by uom desc, min_qty desc """.format(conditions=conditions), args)
|
||||
|
||||
def get_price_list_rate_for(args, item_code):
|
||||
"""
|
||||
Return Price Rate based on min_qty of each Item Price Rate.\
|
||||
For example, desired qty is 10 and Item Price Rates exists
|
||||
for min_qty 9 and min_qty 20. It returns Item Price Rate for qty 9 as
|
||||
the best fit in the range of avaliable min_qtyies
|
||||
|
||||
:param customer: link to Customer DocType
|
||||
:param supplier: link to Supplier DocType
|
||||
:param price_list: str (Standard Buying or Standard Selling)
|
||||
:param item_code: str, Item Doctype field item_code
|
||||
:param qty: Derised Qty
|
||||
:param transaction_date: Date of the price
|
||||
"""
|
||||
item_price_args = {
|
||||
"item_code": item_code,
|
||||
"price_list": args.get('price_list'),
|
||||
"customer": args.get('customer'),
|
||||
"supplier": args.get('supplier'),
|
||||
"uom": args.get('uom'),
|
||||
"min_qty": args.get('qty'),
|
||||
"transaction_date": args.get('transaction_date'),
|
||||
}
|
||||
|
||||
item_price_data = 0
|
||||
price_list_rate = get_item_price(item_price_args, item_code)
|
||||
if price_list_rate:
|
||||
desired_qty = args.get("qty")
|
||||
if check_packing_list(price_list_rate[0][0], desired_qty, item_code):
|
||||
item_price_data = price_list_rate
|
||||
else:
|
||||
for field in ["customer", "supplier", "min_qty"]:
|
||||
del item_price_args[field]
|
||||
|
||||
general_price_list_rate = get_item_price(item_price_args, item_code)
|
||||
if not general_price_list_rate and args.get("uom") != args.get("stock_uom"):
|
||||
item_price_args["args"] = args.get("stock_uom")
|
||||
general_price_list_rate = get_item_price(item_price_args, item_code)
|
||||
|
||||
if general_price_list_rate:
|
||||
item_price_data = general_price_list_rate
|
||||
|
||||
if item_price_data:
|
||||
if item_price_data[0][2] == args.get("uom"):
|
||||
return item_price_data[0][1]
|
||||
elif not args.get('price_list_uom_dependant'):
|
||||
return flt(item_price_data[0][1] * flt(args.get("conversion_factor", 1)))
|
||||
else:
|
||||
return item_price_data[0][1]
|
||||
|
||||
def check_packing_list(price_list_rate_name, desired_qty, item_code):
|
||||
"""
|
||||
Check if the Derised qty is within the increment of the packing list.
|
||||
:param price_list_rate_name: Name of Item Price
|
||||
:param desired_qty: Derised Qt
|
||||
:param item_code: str, Item Doctype field item_code
|
||||
:param qty: Derised Qt
|
||||
"""
|
||||
|
||||
item_price = frappe.get_doc("Item Price", price_list_rate_name)
|
||||
if desired_qty:
|
||||
packing_increment = desired_qty % item_price.packing_unit
|
||||
|
||||
if packing_increment == 0:
|
||||
return True
|
||||
|
||||
def validate_price_list(args):
|
||||
if args.get("price_list"):
|
||||
|
Loading…
x
Reference in New Issue
Block a user