mirror of
https://github.com/frappe/erpnext.git
synced 2026-08-11 21:51:48 +00:00
chore: resolve conflict
This commit is contained in:
@@ -2646,282 +2646,17 @@ class TestSalesOrder(AccountsTestMixin, FrappeTestCase):
|
||||
so = make_sales_order(item_code=fg_item, qty=10, rate=50, warehouse=fg_warehouse, do_not_save=1)
|
||||
self.assertRaises(frappe.ValidationError, so.save)
|
||||
|
||||
<<<<<<< HEAD
|
||||
=======
|
||||
@ERPNextTestSuite.change_settings(
|
||||
"Stock Settings", {"enable_stock_reservation": 1, "use_serial_batch_fields": 0}
|
||||
)
|
||||
def test_product_bundle_reservation(self):
|
||||
pb_item = make_item("Product Bundle Item", {"is_stock_item": 0})
|
||||
simple_item = make_item("Simple Item", {"is_stock_item": 1})
|
||||
sb_item = make_item(
|
||||
"Serial Batch Item",
|
||||
{
|
||||
"is_stock_item": 1,
|
||||
"has_serial_no": 1,
|
||||
"has_batch_no": 1,
|
||||
"create_new_batch": 1,
|
||||
"batch_number_series": "BAT-TSBIFRM-.#####",
|
||||
"serial_no_series": "SN-TSBIFRM-.#####",
|
||||
},
|
||||
)
|
||||
make_product_bundle(pb_item.name, [simple_item.name, sb_item.name])
|
||||
def test_sales_team_allocated_percentage_tolerates_floating_point_drift(self):
|
||||
# 10.0 + 58.02 + 31.98 accumulates to 100.00000000000001 in binary floating point
|
||||
so = make_sales_order(do_not_save=True)
|
||||
for sales_person, percentage in (
|
||||
("_Test Sales Person", 10.0),
|
||||
("_Test Sales Person 1", 58.02),
|
||||
("_Test Sales Person 2", 31.98),
|
||||
):
|
||||
so.append("sales_team", {"sales_person": sales_person, "allocated_percentage": percentage})
|
||||
so.save()
|
||||
|
||||
warehouse = "_Test Warehouse - _TC"
|
||||
|
||||
make_stock_entry(
|
||||
item_code=simple_item.name,
|
||||
target=warehouse,
|
||||
qty=10,
|
||||
)
|
||||
|
||||
# two different stock entries on purpose to get two batches
|
||||
make_stock_entry(
|
||||
item_code=sb_item.name,
|
||||
target=warehouse,
|
||||
qty=5,
|
||||
)
|
||||
make_stock_entry(
|
||||
item_code=sb_item.name,
|
||||
target=warehouse,
|
||||
qty=5,
|
||||
)
|
||||
|
||||
so = make_sales_order(item_code=pb_item.name, do_not_submit=1)
|
||||
so.reserve_stock = 1
|
||||
for item in so.packed_items:
|
||||
item.reserve_stock = 1
|
||||
so.submit()
|
||||
|
||||
from erpnext.stock.doctype.stock_reservation_entry.stock_reservation_entry import (
|
||||
get_sre_reserved_batch_nos_details,
|
||||
get_sre_reserved_qty_for_voucher_detail_no,
|
||||
get_sre_reserved_serial_nos_details,
|
||||
)
|
||||
|
||||
for item in so.packed_items:
|
||||
self.assertEqual(
|
||||
get_sre_reserved_qty_for_voucher_detail_no(item.item_code, "Sales Order", so.name, item.name),
|
||||
item.qty,
|
||||
)
|
||||
|
||||
sre_serial_nos = list(get_sre_reserved_serial_nos_details(sb_item.name, warehouse).keys())
|
||||
sre_batch_nos = list(get_sre_reserved_batch_nos_details(sb_item.name, warehouse).keys())
|
||||
|
||||
dn = make_delivery_note(so.name, kwargs={"for_reserved_stock": True})
|
||||
dn.save()
|
||||
|
||||
self.assertTrue(dn.packed_items[1].serial_and_batch_bundle)
|
||||
|
||||
from erpnext.stock.serial_batch_bundle import get_batches_from_bundle, get_serial_nos
|
||||
|
||||
serial_nos_in_bundle = get_serial_nos(dn.packed_items[1].serial_and_batch_bundle)
|
||||
batches_in_bundle = list(get_batches_from_bundle(dn.packed_items[1].serial_and_batch_bundle).keys())
|
||||
|
||||
self.assertEqual(sre_serial_nos, serial_nos_in_bundle)
|
||||
self.assertEqual(sre_batch_nos, batches_in_bundle)
|
||||
|
||||
dn.items[0].qty = 5
|
||||
dn.save()
|
||||
sabb_doc = frappe.get_doc("Serial and Batch Bundle", dn.packed_items[1].serial_and_batch_bundle)
|
||||
sabb_doc.entries = sabb_doc.entries[:5]
|
||||
sabb_doc.company = dn.company
|
||||
sabb_doc.save()
|
||||
dn.submit()
|
||||
|
||||
serial_nos = set(sre_serial_nos) - set(get_serial_nos(sabb_doc.name))
|
||||
batch_nos = set(sre_batch_nos) - set(get_batches_from_bundle(sabb_doc.name).keys())
|
||||
|
||||
dn1 = make_delivery_note(so.name, kwargs={"for_reserved_stock": True})
|
||||
dn1.save()
|
||||
|
||||
self.assertTrue(dn1.packed_items[1].serial_and_batch_bundle)
|
||||
|
||||
from erpnext.stock.serial_batch_bundle import get_batches_from_bundle, get_serial_nos
|
||||
|
||||
serial_nos_in_bundle = set(get_serial_nos(dn1.packed_items[1].serial_and_batch_bundle))
|
||||
batches_in_bundle = set(get_batches_from_bundle(dn1.packed_items[1].serial_and_batch_bundle).keys())
|
||||
|
||||
self.assertEqual(serial_nos, serial_nos_in_bundle)
|
||||
self.assertEqual(batch_nos, batches_in_bundle)
|
||||
|
||||
dn.cancel()
|
||||
|
||||
# test the same thing with sales invoice as well
|
||||
|
||||
si = make_sales_invoice(so.name)
|
||||
si.update_stock = 1
|
||||
si.save()
|
||||
|
||||
self.assertTrue(si.packed_items[1].serial_and_batch_bundle)
|
||||
|
||||
from erpnext.stock.serial_batch_bundle import get_batches_from_bundle, get_serial_nos
|
||||
|
||||
serial_nos_in_bundle = get_serial_nos(si.packed_items[1].serial_and_batch_bundle)
|
||||
batches_in_bundle = list(get_batches_from_bundle(si.packed_items[1].serial_and_batch_bundle).keys())
|
||||
|
||||
self.assertEqual(sre_serial_nos, serial_nos_in_bundle)
|
||||
self.assertEqual(sre_batch_nos, batches_in_bundle)
|
||||
|
||||
si.items[0].qty = 5
|
||||
si.save()
|
||||
sabb_doc = frappe.get_doc("Serial and Batch Bundle", si.packed_items[1].serial_and_batch_bundle)
|
||||
sabb_doc.entries = sabb_doc.entries[:5]
|
||||
sabb_doc.company = si.company
|
||||
sabb_doc.save()
|
||||
si.submit()
|
||||
|
||||
serial_nos = set(sre_serial_nos) - set(get_serial_nos(sabb_doc.name))
|
||||
batch_nos = set(sre_batch_nos) - set(get_batches_from_bundle(sabb_doc.name).keys())
|
||||
|
||||
si1 = make_delivery_note(so.name, kwargs={"for_reserved_stock": True})
|
||||
si1.save()
|
||||
|
||||
self.assertTrue(si1.packed_items[1].serial_and_batch_bundle)
|
||||
|
||||
from erpnext.stock.serial_batch_bundle import get_batches_from_bundle, get_serial_nos
|
||||
|
||||
serial_nos_in_bundle = set(get_serial_nos(si1.packed_items[1].serial_and_batch_bundle))
|
||||
batches_in_bundle = set(get_batches_from_bundle(si1.packed_items[1].serial_and_batch_bundle).keys())
|
||||
|
||||
self.assertEqual(serial_nos, serial_nos_in_bundle)
|
||||
self.assertEqual(batch_nos, batches_in_bundle)
|
||||
|
||||
def test_sales_team_contribution_follows_grant_commission(self):
|
||||
"""Sales-person allocation tracks the grant-commission-eligible amount, not the gross total.
|
||||
|
||||
The Item "Grant Commission" flag includes an item in both Sales Partner and Sales Person
|
||||
commission, so each sales person's allocated_amount is a share of
|
||||
amount_eligible_for_commission rather than net_total.
|
||||
"""
|
||||
frappe.db.set_value("Item", "_Test Item", "grant_commission", 1)
|
||||
frappe.db.set_value("Item", "_Test FG Item", "grant_commission", 0)
|
||||
try:
|
||||
so = make_sales_order(
|
||||
do_not_save=True,
|
||||
item_list=[
|
||||
{"item_code": "_Test Item", "warehouse": "_Test Warehouse - _TC", "qty": 10, "rate": 100},
|
||||
{
|
||||
"item_code": "_Test FG Item",
|
||||
"warehouse": "_Test Warehouse - _TC",
|
||||
"qty": 10,
|
||||
"rate": 100,
|
||||
},
|
||||
],
|
||||
)
|
||||
so.append(
|
||||
"sales_team",
|
||||
{"sales_person": "_Test Sales Person 1", "allocated_percentage": 60, "commission_rate": 10},
|
||||
)
|
||||
so.append(
|
||||
"sales_team",
|
||||
{"sales_person": "_Test Sales Person 2", "allocated_percentage": 40, "commission_rate": 0},
|
||||
)
|
||||
so.save()
|
||||
|
||||
self.assertEqual(so.net_total, 2000)
|
||||
self.assertEqual(so.amount_eligible_for_commission, 1000) # only the grant_commission item
|
||||
|
||||
first, second = so.sales_team
|
||||
# allocation follows the eligible amount (1000), not net_total (2000)
|
||||
self.assertEqual(first.allocated_amount, 600)
|
||||
self.assertEqual(first.incentives, 60) # 600 * 10%
|
||||
self.assertEqual(second.allocated_amount, 400)
|
||||
self.assertEqual(second.incentives, 0)
|
||||
finally:
|
||||
# grant_commission defaults to 1 for both items; restore
|
||||
frappe.db.set_value("Item", "_Test Item", "grant_commission", 1)
|
||||
frappe.db.set_value("Item", "_Test FG Item", "grant_commission", 1)
|
||||
|
||||
def test_sales_team_allocated_percentage_must_total_100(self):
|
||||
with self.subTest("partial allocation is rejected"):
|
||||
so = make_sales_order(do_not_save=True)
|
||||
so.append("sales_team", {"sales_person": "_Test Sales Person 1", "allocated_percentage": 60})
|
||||
self.assertRaises(frappe.ValidationError, so.save)
|
||||
|
||||
with self.subTest("allocation totalling 100 is accepted"):
|
||||
so = make_sales_order(do_not_save=True)
|
||||
so.append("sales_team", {"sales_person": "_Test Sales Person 1", "allocated_percentage": 60})
|
||||
so.append("sales_team", {"sales_person": "_Test Sales Person 2", "allocated_percentage": 40})
|
||||
so.save()
|
||||
self.assertEqual(sum(d.allocated_percentage for d in so.sales_team), 100)
|
||||
|
||||
with self.subTest("floating-point drift in the total is tolerated"):
|
||||
# 10.0 + 58.02 + 31.98 accumulates to 100.00000000000001 in binary floating point
|
||||
so = make_sales_order(do_not_save=True)
|
||||
for sales_person, percentage in (
|
||||
("_Test Sales Person", 10.0),
|
||||
("_Test Sales Person 1", 58.02),
|
||||
("_Test Sales Person 2", 31.98),
|
||||
):
|
||||
so.append("sales_team", {"sales_person": sales_person, "allocated_percentage": percentage})
|
||||
so.save()
|
||||
|
||||
def test_sales_team_disabled_sales_person_rejected(self):
|
||||
frappe.db.set_value("Sales Person", "_Test Sales Person 2", "enabled", 0)
|
||||
try:
|
||||
so = make_sales_order(do_not_save=True)
|
||||
so.append("sales_team", {"sales_person": "_Test Sales Person 2", "allocated_percentage": 100})
|
||||
self.assertRaises(frappe.ValidationError, so.save)
|
||||
finally:
|
||||
frappe.db.set_value("Sales Person", "_Test Sales Person 2", "enabled", 1)
|
||||
|
||||
def test_sales_partner_commission(self):
|
||||
"""Sales Partner commission: total_commission = amount_eligible_for_commission * rate / 100."""
|
||||
frappe.db.set_value("Item", "_Test Item", "grant_commission", 1)
|
||||
try:
|
||||
so = make_sales_order(qty=10, rate=100, do_not_save=True)
|
||||
so.sales_partner = "_Test Sales Partner India - 1"
|
||||
so.commission_rate = 7
|
||||
so.save()
|
||||
|
||||
self.assertEqual(so.amount_eligible_for_commission, 1000)
|
||||
self.assertEqual(so.total_commission, 70) # 1000 * 7%
|
||||
|
||||
with self.subTest("commission rate above 100 is rejected"):
|
||||
so.commission_rate = 101
|
||||
self.assertRaises(frappe.ValidationError, so.save)
|
||||
finally:
|
||||
frappe.db.set_value("Item", "_Test Item", "grant_commission", 1)
|
||||
|
||||
def test_commission_fields_not_copied_on_duplicate(self):
|
||||
"""Commission rate/amount fields are no_copy; only the sales partner carries to a copy."""
|
||||
frappe.db.set_value("Item", "_Test Item", "grant_commission", 1)
|
||||
try:
|
||||
so = make_sales_order(qty=10, rate=100, do_not_save=True)
|
||||
so.sales_partner = "_Test Sales Partner India - 1"
|
||||
so.commission_rate = 7
|
||||
so.save()
|
||||
self.assertEqual(so.total_commission, 70)
|
||||
|
||||
# ignore_no_copy=False mirrors UI "Duplicate"/amend, which honour no_copy
|
||||
duplicate = frappe.copy_doc(so, ignore_no_copy=False)
|
||||
self.assertEqual(duplicate.sales_partner, "_Test Sales Partner India - 1")
|
||||
self.assertFalse(duplicate.commission_rate)
|
||||
self.assertFalse(duplicate.total_commission)
|
||||
self.assertFalse(duplicate.amount_eligible_for_commission)
|
||||
finally:
|
||||
frappe.db.set_value("Item", "_Test Item", "grant_commission", 1)
|
||||
|
||||
def test_commission_rate_carried_through_mapper(self):
|
||||
"""commission_rate is no_copy, but Make Delivery Note / Sales Invoice still carries it."""
|
||||
from erpnext.selling.doctype.sales_order.mapper import make_delivery_note, make_sales_invoice
|
||||
|
||||
original = frappe.db.get_value("Item", "_Test Item", "grant_commission")
|
||||
frappe.db.set_value("Item", "_Test Item", "grant_commission", 1)
|
||||
try:
|
||||
so = make_sales_order(qty=10, rate=100, do_not_save=True)
|
||||
so.sales_partner = "_Test Sales Partner India - 1"
|
||||
so.commission_rate = 7
|
||||
so.submit()
|
||||
|
||||
# carried to the mapped (unsaved) documents even though the field is no_copy
|
||||
self.assertEqual(make_delivery_note(so.name).commission_rate, 7)
|
||||
self.assertEqual(make_sales_invoice(so.name).commission_rate, 7)
|
||||
finally:
|
||||
frappe.db.set_value("Item", "_Test Item", "grant_commission", original)
|
||||
|
||||
>>>>>>> 4afba94d1c (test: sales team allocation totalling 100 in floating point)
|
||||
|
||||
def compare_payment_schedules(doc, doc1, doc2):
|
||||
for index, schedule in enumerate(doc1.get("payment_schedule")):
|
||||
|
||||
Reference in New Issue
Block a user