fix: cannot merge pos invoice if validate selling price is checked (#23593)
* fix: cannot merge pos invoice if validate selling price is checked * fix: validate selling price * fix: test * chore: add test * fix: error message
This commit is contained in:
parent
4164d08d17
commit
3daad224ad
@ -7,6 +7,7 @@ import frappe
|
|||||||
import unittest, copy, time
|
import unittest, copy, time
|
||||||
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
|
from erpnext.accounts.doctype.pos_profile.test_pos_profile import make_pos_profile
|
||||||
from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
|
from erpnext.accounts.doctype.pos_invoice.pos_invoice import make_sales_return
|
||||||
|
from erpnext.stock.doctype.stock_entry.stock_entry_utils import make_stock_entry
|
||||||
|
|
||||||
class TestPOSInvoice(unittest.TestCase):
|
class TestPOSInvoice(unittest.TestCase):
|
||||||
def test_timestamp_change(self):
|
def test_timestamp_change(self):
|
||||||
@ -307,8 +308,9 @@ class TestPOSInvoice(unittest.TestCase):
|
|||||||
merge_pos_invoices()
|
merge_pos_invoices()
|
||||||
|
|
||||||
pos_inv.load_from_db()
|
pos_inv.load_from_db()
|
||||||
sales_invoice = frappe.get_doc("Sales Invoice", pos_inv.consolidated_invoice)
|
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
|
||||||
self.assertEqual(sales_invoice.grand_total, 3500)
|
self.assertEqual(rounded_total, 3500)
|
||||||
|
frappe.set_user("Administrator")
|
||||||
|
|
||||||
def test_merging_into_sales_invoice_with_discount_and_inclusive_tax(self):
|
def test_merging_into_sales_invoice_with_discount_and_inclusive_tax(self):
|
||||||
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
||||||
@ -348,8 +350,55 @@ class TestPOSInvoice(unittest.TestCase):
|
|||||||
merge_pos_invoices()
|
merge_pos_invoices()
|
||||||
|
|
||||||
pos_inv.load_from_db()
|
pos_inv.load_from_db()
|
||||||
sales_invoice = frappe.get_doc("Sales Invoice", pos_inv.consolidated_invoice)
|
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv.consolidated_invoice, "rounded_total")
|
||||||
self.assertEqual(sales_invoice.rounded_total, 840)
|
self.assertEqual(rounded_total, 840)
|
||||||
|
frappe.set_user("Administrator")
|
||||||
|
|
||||||
|
def test_merging_with_validate_selling_price(self):
|
||||||
|
from erpnext.accounts.doctype.pos_closing_entry.test_pos_closing_entry import init_user_and_profile
|
||||||
|
from erpnext.accounts.doctype.pos_invoice_merge_log.pos_invoice_merge_log import merge_pos_invoices
|
||||||
|
|
||||||
|
if not frappe.db.get_single_value("Selling Settings", "validate_selling_price"):
|
||||||
|
frappe.db.set_value("Selling Settings", "Selling Settings", "validate_selling_price", 1)
|
||||||
|
|
||||||
|
make_stock_entry(item_code="_Test Item", target="_Test Warehouse - _TC", qty=1, basic_rate=300)
|
||||||
|
frappe.db.sql("delete from `tabPOS Invoice`")
|
||||||
|
test_user, pos_profile = init_user_and_profile()
|
||||||
|
pos_inv = create_pos_invoice(rate=300, do_not_submit=1)
|
||||||
|
pos_inv.append('payments', {
|
||||||
|
'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 300
|
||||||
|
})
|
||||||
|
pos_inv.append('taxes', {
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": "_Test Account Service Tax - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "Service Tax",
|
||||||
|
"rate": 14,
|
||||||
|
'included_in_print_rate': 1
|
||||||
|
})
|
||||||
|
self.assertRaises(frappe.ValidationError, pos_inv.submit)
|
||||||
|
|
||||||
|
pos_inv2 = create_pos_invoice(rate=400, do_not_submit=1)
|
||||||
|
pos_inv2.append('payments', {
|
||||||
|
'mode_of_payment': 'Cash', 'account': 'Cash - _TC', 'amount': 400
|
||||||
|
})
|
||||||
|
pos_inv2.append('taxes', {
|
||||||
|
"charge_type": "On Net Total",
|
||||||
|
"account_head": "_Test Account Service Tax - _TC",
|
||||||
|
"cost_center": "_Test Cost Center - _TC",
|
||||||
|
"description": "Service Tax",
|
||||||
|
"rate": 14,
|
||||||
|
'included_in_print_rate': 1
|
||||||
|
})
|
||||||
|
pos_inv2.submit()
|
||||||
|
|
||||||
|
merge_pos_invoices()
|
||||||
|
|
||||||
|
pos_inv2.load_from_db()
|
||||||
|
rounded_total = frappe.db.get_value("Sales Invoice", pos_inv2.consolidated_invoice, "rounded_total")
|
||||||
|
self.assertEqual(rounded_total, 400)
|
||||||
|
frappe.set_user("Administrator")
|
||||||
|
frappe.db.set_value("Selling Settings", "Selling Settings", "validate_selling_price", 0)
|
||||||
|
|
||||||
def create_pos_invoice(**args):
|
def create_pos_invoice(**args):
|
||||||
args = frappe._dict(args)
|
args = frappe._dict(args)
|
||||||
|
|||||||
@ -3,7 +3,7 @@
|
|||||||
|
|
||||||
from __future__ import unicode_literals
|
from __future__ import unicode_literals
|
||||||
import frappe
|
import frappe
|
||||||
from frappe.utils import cint, flt, cstr, comma_or
|
from frappe.utils import cint, flt, cstr, comma_or, get_link_to_form
|
||||||
from frappe import _, throw
|
from frappe import _, throw
|
||||||
from erpnext.stock.get_item_details import get_bin_details
|
from erpnext.stock.get_item_details import get_bin_details
|
||||||
from erpnext.stock.utils import get_incoming_rate
|
from erpnext.stock.utils import get_incoming_rate
|
||||||
@ -173,22 +173,26 @@ class SellingController(StockController):
|
|||||||
|
|
||||||
def validate_selling_price(self):
|
def validate_selling_price(self):
|
||||||
def throw_message(idx, item_name, rate, ref_rate_field):
|
def throw_message(idx, item_name, rate, ref_rate_field):
|
||||||
frappe.throw(_("""Row #{}: Selling rate for item {} is lower than its {}. Selling rate should be atleast {}""")
|
bold_net_rate = frappe.bold("net rate")
|
||||||
.format(idx, item_name, ref_rate_field, rate))
|
msg = (_("""Row #{}: Selling rate for item {} is lower than its {}. Selling {} should be atleast {}""")
|
||||||
|
.format(idx, frappe.bold(item_name), frappe.bold(ref_rate_field), bold_net_rate, frappe.bold(rate)))
|
||||||
|
msg += "<br><br>"
|
||||||
|
msg += (_("""You can alternatively disable selling price validation in {} to bypass this validation.""")
|
||||||
|
.format(get_link_to_form("Selling Settings", "Selling Settings")))
|
||||||
|
frappe.throw(msg, title=_("Invalid Selling Price"))
|
||||||
|
|
||||||
if not frappe.db.get_single_value("Selling Settings", "validate_selling_price"):
|
if not frappe.db.get_single_value("Selling Settings", "validate_selling_price"):
|
||||||
return
|
return
|
||||||
|
|
||||||
if hasattr(self, "is_return") and self.is_return:
|
if hasattr(self, "is_return") and self.is_return:
|
||||||
return
|
return
|
||||||
|
|
||||||
for it in self.get("items"):
|
for it in self.get("items"):
|
||||||
if not it.item_code:
|
if not it.item_code:
|
||||||
continue
|
continue
|
||||||
|
|
||||||
last_purchase_rate, is_stock_item = frappe.get_cached_value("Item", it.item_code, ["last_purchase_rate", "is_stock_item"])
|
last_purchase_rate, is_stock_item = frappe.get_cached_value("Item", it.item_code, ["last_purchase_rate", "is_stock_item"])
|
||||||
last_purchase_rate_in_sales_uom = last_purchase_rate / (it.conversion_factor or 1)
|
last_purchase_rate_in_sales_uom = last_purchase_rate * (it.conversion_factor or 1)
|
||||||
if flt(it.base_rate) < flt(last_purchase_rate_in_sales_uom):
|
if flt(it.base_net_rate) < flt(last_purchase_rate_in_sales_uom):
|
||||||
throw_message(it.idx, frappe.bold(it.item_name), last_purchase_rate_in_sales_uom, "last purchase rate")
|
throw_message(it.idx, frappe.bold(it.item_name), last_purchase_rate_in_sales_uom, "last purchase rate")
|
||||||
|
|
||||||
last_valuation_rate = frappe.db.sql("""
|
last_valuation_rate = frappe.db.sql("""
|
||||||
@ -197,8 +201,8 @@ class SellingController(StockController):
|
|||||||
ORDER BY posting_date DESC, posting_time DESC, creation DESC LIMIT 1
|
ORDER BY posting_date DESC, posting_time DESC, creation DESC LIMIT 1
|
||||||
""", (it.item_code, it.warehouse))
|
""", (it.item_code, it.warehouse))
|
||||||
if last_valuation_rate:
|
if last_valuation_rate:
|
||||||
last_valuation_rate_in_sales_uom = last_valuation_rate[0][0] / (it.conversion_factor or 1)
|
last_valuation_rate_in_sales_uom = last_valuation_rate[0][0] * (it.conversion_factor or 1)
|
||||||
if is_stock_item and flt(it.base_rate) < flt(last_valuation_rate_in_sales_uom) \
|
if is_stock_item and flt(it.base_net_rate) < flt(last_valuation_rate_in_sales_uom) \
|
||||||
and not self.get('is_internal_customer'):
|
and not self.get('is_internal_customer'):
|
||||||
throw_message(it.idx, frappe.bold(it.item_name), last_valuation_rate_in_sales_uom, "valuation rate")
|
throw_message(it.idx, frappe.bold(it.item_name), last_valuation_rate_in_sales_uom, "valuation rate")
|
||||||
|
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user