From 48b5567af46d301e1103627ac773adf980792cf9 Mon Sep 17 00:00:00 2001 From: David Date: Sat, 1 Jun 2024 16:42:42 +0200 Subject: [PATCH 1/2] fix: loyalty points application on si --- .../doctype/sales_invoice/sales_invoice.py | 20 ++----------------- .../doctype/sales_order/sales_order.py | 1 + 2 files changed, 3 insertions(+), 18 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 6e8f1b2bbf2..4c90c908db3 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -315,17 +315,6 @@ class SalesInvoice(SellingController): if not self.is_opening: self.is_opening = "No" - if self.redeem_loyalty_points: - lp = frappe.get_doc("Loyalty Program", self.loyalty_program) - self.loyalty_redemption_account = ( - lp.expense_account if not self.loyalty_redemption_account else self.loyalty_redemption_account - ) - self.loyalty_redemption_cost_center = ( - lp.cost_center - if not self.loyalty_redemption_cost_center - else self.loyalty_redemption_cost_center - ) - self.set_against_income_account() self.validate_time_sheets_are_submitted() self.validate_multiple_billing("Delivery Note", "dn_detail", "amount") @@ -344,12 +333,7 @@ class SalesInvoice(SellingController): if self.is_pos and self.is_return: self.verify_payment_amount_is_negative() - if ( - self.redeem_loyalty_points - and self.loyalty_program - and self.loyalty_points - and not self.is_consolidated - ): + if self.redeem_loyalty_points and self.loyalty_points and not self.is_consolidated: validate_loyalty_points(self, self.loyalty_points) self.reset_default_field_value("set_warehouse", "items", "warehouse") @@ -1444,7 +1428,7 @@ class SalesInvoice(SellingController): asset.set_status("Sold" if self.docstatus == 1 else None) def make_loyalty_point_redemption_gle(self, gl_entries): - if cint(self.redeem_loyalty_points): + if cint(self.redeem_loyalty_points and self.loyalty_points and not self.is_consolidated): gl_entries.append( self.get_gl_dict( { diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index 9bd13184521..2299f2765fa 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -1091,6 +1091,7 @@ def make_sales_invoice(source_name, target_doc=None, ignore_permissions=False): # set the redeem loyalty points if provided via shopping cart if source.loyalty_points and source.order_type == "Shopping Cart": target.redeem_loyalty_points = 1 + target.loyalty_points = source.loyalty_points target.debit_to = get_party_account("Customer", source.customer, source.company) From 74fb070959ebc45a65a920df34e970e1f17565a7 Mon Sep 17 00:00:00 2001 From: David Date: Thu, 5 Sep 2024 16:57:33 +0200 Subject: [PATCH 2/2] test: loyalty points redemption from shopping cart --- .../sales_invoice/test_sales_invoice.py | 59 +++++++++++++++++++ 1 file changed, 59 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index e94b27b0545..6542f6c7f9e 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -3724,6 +3724,65 @@ class TestSalesInvoice(FrappeTestCase): check_gl_entries(self, pe.name, expected_gle, nowdate(), voucher_type="Payment Entry") set_advance_flag(company="_Test Company", flag=0, default_account="") + def test_loyalty_points_redemption_with_shopping_cart(self): + from erpnext.accounts.doctype.loyalty_program.test_loyalty_program import ( + create_records, + create_sales_invoice_record, + ) + from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice + from erpnext.selling.doctype.sales_order.test_sales_order import make_sales_order + + # Set up loyalty program + create_records() + frappe.db.set_value("Customer", "Test Loyalty Customer", "loyalty_program", "Test Single Loyalty") + create_sales_invoice_record(10).insert().submit() + + # Create a sales order + so = make_sales_order(qty=10, do_not_save=True, customer="Test Loyalty Customer") + so.name = "_T-Sales Order LP-0001" + so.order_type = "Shopping Cart" + so.loyalty_points = 50 + so.loyalty_amount = 50 + so.insert() + so.submit() + + # Create sales invoice from the sales order + si = make_sales_invoice(so.name) + from frappe.model.trace import traced_field_context + + with traced_field_context(si.__class__, "loyalty_program", forbidden_values=[None]): + si.insert() + si.submit() + + # Check if loyalty points are applied correctly + self.assertEqual(si.loyalty_program, "Test Single Loyalty") + self.assertEqual(si.loyalty_points, 50) + self.assertEqual(si.loyalty_amount, 50) + + # Check GL entries for loyalty points redemption + gl_entries = frappe.get_all( + "GL Entry", + filters={"voucher_type": "Sales Invoice", "voucher_no": si.name}, + fields=["account", "debit", "credit"], + ) + + loyalty_account = frappe.db.get_value("Loyalty Program", "Test Single Loyalty", "expense_account") + expected_gl_entries = [ + {"account": si.debit_to, "debit": si.grand_total, "credit": 0}, + {"account": si.items[0].income_account, "debit": 0, "credit": si.net_total}, + {"account": loyalty_account, "debit": 50, "credit": 0}, + ] + + for entry in expected_gl_entries: + self.assertTrue( + any( + gl_entry.account == entry["account"] + and gl_entry.debit == entry["debit"] + and gl_entry.credit == entry["credit"] + for gl_entry in gl_entries + ) + ) + def test_pulling_advance_based_on_debit_to(self): from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry