From 405d1528c3d8dcff120003ffaacaf24d429c806a Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 2 Oct 2023 09:28:42 +0530 Subject: [PATCH 01/11] test: use fixtures for sales and purchase invoice (cherry picked from commit c322e5f38140b1fab8f940db542e25c2b122ab54) # Conflicts: # erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py --- .../accounts/doctype/sales_invoice/test_sales_invoice.py | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index e0a7ff002bb..55fecc560e3 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -6,8 +6,12 @@ import unittest import frappe from frappe.model.dynamic_links import get_dynamic_link_map +<<<<<<< HEAD from frappe.model.naming import make_autoname from frappe.tests.utils import change_settings +======= +from frappe.tests.utils import FrappeTestCase, change_settings +>>>>>>> c322e5f381 (test: use fixtures for sales and purchase invoice) from frappe.utils import add_days, flt, getdate, nowdate, today import erpnext @@ -38,7 +42,7 @@ from erpnext.stock.doctype.stock_reconciliation.test_stock_reconciliation import from erpnext.stock.utils import get_incoming_rate, get_stock_balance -class TestSalesInvoice(unittest.TestCase): +class TestSalesInvoice(FrappeTestCase): def setUp(self): from erpnext.stock.doctype.stock_ledger_entry.test_stock_ledger_entry import create_items @@ -46,6 +50,9 @@ class TestSalesInvoice(unittest.TestCase): create_internal_parties() setup_accounts() + def tearDown(self): + frappe.db.rollback() + def make(self): w = frappe.copy_doc(test_records[0]) w.is_pos = 0 From 9d6b434d1f30acac9315cdbeac75266158b0998d Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 2 Oct 2023 10:56:39 +0530 Subject: [PATCH 02/11] refactor(test): unset accounts frozen date (cherry picked from commit fc50b174eb5f37a40b522f7e073d11260e0c12c8) --- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 55fecc560e3..ca6d83f4cef 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -49,10 +49,14 @@ class TestSalesInvoice(FrappeTestCase): create_items(["_Test Internal Transfer Item"], uoms=[{"uom": "Box", "conversion_factor": 10}]) create_internal_parties() setup_accounts() + self.remove_accounts_frozen_date() def tearDown(self): frappe.db.rollback() + def remove_accounts_frozen_date(self): + frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) + def make(self): w = frappe.copy_doc(test_records[0]) w.is_pos = 0 From 485cb7dd280b3f218c3bdf5ef723a36a0f9dbb67 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 2 Oct 2023 13:12:21 +0530 Subject: [PATCH 03/11] refactor(test): use @change_settings in sales invoice (cherry picked from commit 58065f31b1e2e550661a47b4442f6861406ebec5) # Conflicts: # erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py --- .../sales_invoice/test_sales_invoice.py | 27 ++++++++++++------- 1 file changed, 18 insertions(+), 9 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index ca6d83f4cef..08d991c0035 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -49,14 +49,10 @@ class TestSalesInvoice(FrappeTestCase): create_items(["_Test Internal Transfer Item"], uoms=[{"uom": "Box", "conversion_factor": 10}]) create_internal_parties() setup_accounts() - self.remove_accounts_frozen_date() def tearDown(self): frappe.db.rollback() - def remove_accounts_frozen_date(self): - frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) - def make(self): w = frappe.copy_doc(test_records[0]) w.is_pos = 0 @@ -3083,8 +3079,12 @@ class TestSalesInvoice(FrappeTestCase): si.commission_rate = commission_rate self.assertRaises(frappe.ValidationError, si.save) + @change_settings("Accounts Settings", {"acc_frozen_upto": add_days(getdate(), 1)}) def test_sales_invoice_submission_post_account_freezing_date(self): +<<<<<<< HEAD frappe.db.set_value("Accounts Settings", None, "acc_frozen_upto", add_days(getdate(), 1)) +======= +>>>>>>> 58065f31b1 (refactor(test): use @change_settings in sales invoice) si = create_sales_invoice(do_not_save=True) si.posting_date = add_days(getdate(), 1) si.save() @@ -3093,8 +3093,11 @@ class TestSalesInvoice(FrappeTestCase): si.posting_date = getdate() si.submit() +<<<<<<< HEAD frappe.db.set_value("Accounts Settings", None, "acc_frozen_upto", None) +======= +>>>>>>> 58065f31b1 (refactor(test): use @change_settings in sales invoice) def test_over_billing_case_against_delivery_note(self): """ Test a case where duplicating the item with qty = 1 in the invoice @@ -3123,6 +3126,13 @@ class TestSalesInvoice(FrappeTestCase): frappe.db.set_value("Accounts Settings", None, "over_billing_allowance", over_billing_allowance) + @change_settings( + "Accounts Settings", + { + "book_deferred_entries_via_journal_entry": 1, + "submit_journal_entries": 1, + }, + ) def test_multi_currency_deferred_revenue_via_journal_entry(self): deferred_account = create_account( account_name="Deferred Revenue", @@ -3130,11 +3140,6 @@ class TestSalesInvoice(FrappeTestCase): company="_Test Company", ) - acc_settings = frappe.get_single("Accounts Settings") - acc_settings.book_deferred_entries_via_journal_entry = 1 - acc_settings.submit_journal_entries = 1 - acc_settings.save() - item = create_item("_Test Item for Deferred Accounting") item.enable_deferred_expense = 1 item.item_defaults[0].deferred_revenue_account = deferred_account @@ -3200,12 +3205,16 @@ class TestSalesInvoice(FrappeTestCase): self.assertEqual(expected_gle[i][2], gle.debit) self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date) +<<<<<<< HEAD acc_settings = frappe.get_single("Accounts Settings") acc_settings.book_deferred_entries_via_journal_entry = 0 acc_settings.submit_journal_entries = 0 acc_settings.save() frappe.db.set_value("Accounts Settings", None, "acc_frozen_upto", None) +======= + frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) +>>>>>>> 58065f31b1 (refactor(test): use @change_settings in sales invoice) def test_standalone_serial_no_return(self): si = create_sales_invoice( From 91a5bd86151e72e93e2ab8db86aaa718f169a6f1 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 2 Oct 2023 14:57:31 +0530 Subject: [PATCH 04/11] refactor(test): fix broken test cases in Sales Invoice (cherry picked from commit 8ebe5733ac61b6291b22901dbbf070093200706f) # Conflicts: # erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py --- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 08d991c0035..528fc6f6c26 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -49,6 +49,7 @@ class TestSalesInvoice(FrappeTestCase): create_items(["_Test Internal Transfer Item"], uoms=[{"uom": "Box", "conversion_factor": 10}]) create_internal_parties() setup_accounts() + frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) def tearDown(self): frappe.db.rollback() @@ -3205,6 +3206,7 @@ class TestSalesInvoice(FrappeTestCase): self.assertEqual(expected_gle[i][2], gle.debit) self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date) +<<<<<<< HEAD <<<<<<< HEAD acc_settings = frappe.get_single("Accounts Settings") acc_settings.book_deferred_entries_via_journal_entry = 0 @@ -3216,6 +3218,8 @@ class TestSalesInvoice(FrappeTestCase): frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) >>>>>>> 58065f31b1 (refactor(test): use @change_settings in sales invoice) +======= +>>>>>>> 8ebe5733ac (refactor(test): fix broken test cases in Sales Invoice) def test_standalone_serial_no_return(self): si = create_sales_invoice( item_code="_Test Serialized Item With Series", update_stock=True, is_return=True, qty=-1 From 5699a8daa29c67e2e219838d25ed7f7813efda62 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 11 Oct 2023 20:18:59 +0530 Subject: [PATCH 05/11] refactor(test): use @change_settings to fix failing test cases (cherry picked from commit de9baef84a77f5bb2aa94f200147d0689462b9c3) --- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 528fc6f6c26..6aae93388d8 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -180,6 +180,7 @@ class TestSalesInvoice(FrappeTestCase): self.assertRaises(frappe.LinkExistsError, si.cancel) unlink_payment_on_cancel_of_invoice() + @change_settings("Accounts Settings", {"unlink_payment_on_cancellation_of_invoice": 1}) def test_payment_entry_unlink_against_standalone_credit_note(self): from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry @@ -1301,6 +1302,7 @@ class TestSalesInvoice(FrappeTestCase): dn.submit() return dn + @change_settings("Accounts Settings", {"unlink_payment_on_cancellation_of_invoice": 1}) def test_sales_invoice_with_advance(self): from erpnext.accounts.doctype.journal_entry.test_journal_entry import ( test_records as jv_test_records, From b97fdbe6fce93ec52e688a2be692a254dc13f651 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 15 Oct 2023 05:56:52 +0530 Subject: [PATCH 06/11] refactor(test): use test fixture in subscription (cherry picked from commit 3bdf4f628c40d4e8ac19a41c738a8ba382d90d99) # Conflicts: # erpnext/accounts/doctype/subscription/test_subscription.py --- .../doctype/subscription/test_subscription.py | 525 ++++++++++++++++++ 1 file changed, 525 insertions(+) diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py index c911e7fe12d..4acddfec7e2 100644 --- a/erpnext/accounts/doctype/subscription/test_subscription.py +++ b/erpnext/accounts/doctype/subscription/test_subscription.py @@ -4,6 +4,7 @@ import unittest import frappe +from frappe.tests.utils import FrappeTestCase from frappe.utils.data import ( add_days, add_months, @@ -19,8 +20,532 @@ from erpnext.accounts.doctype.subscription.subscription import get_prorata_facto test_dependencies = ("UOM", "Item Group", "Item") +<<<<<<< HEAD def create_plan(): if not frappe.db.exists("Subscription Plan", "_Test Plan Name"): +======= +class TestSubscription(FrappeTestCase): + def setUp(self): + make_plans() + create_parties() + reset_settings() + frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) + + def tearDown(self): + frappe.db.rollback() + + def test_create_subscription_with_trial_with_correct_period(self): + subscription = create_subscription( + trial_period_start=nowdate(), trial_period_end=add_months(nowdate(), 1) + ) + self.assertEqual(subscription.trial_period_start, nowdate()) + self.assertEqual(subscription.trial_period_end, add_months(nowdate(), 1)) + self.assertEqual( + add_days(subscription.trial_period_end, 1), get_date_str(subscription.current_invoice_start) + ) + self.assertEqual( + add_to_date(subscription.current_invoice_start, months=1, days=-1), + get_date_str(subscription.current_invoice_end), + ) + self.assertEqual(subscription.invoices, []) + self.assertEqual(subscription.status, "Trialling") + + def test_create_subscription_without_trial_with_correct_period(self): + subscription = create_subscription() + self.assertEqual(subscription.trial_period_start, None) + self.assertEqual(subscription.trial_period_end, None) + self.assertEqual(subscription.current_invoice_start, nowdate()) + self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1)) + # No invoice is created + self.assertEqual(len(subscription.invoices), 0) + self.assertEqual(subscription.status, "Active") + + def test_create_subscription_trial_with_wrong_dates(self): + subscription = create_subscription( + trial_period_start=add_days(nowdate(), 30), trial_period_end=nowdate(), do_not_save=True + ) + self.assertRaises(frappe.ValidationError, subscription.save) + + def test_invoice_is_generated_at_end_of_billing_period(self): + subscription = create_subscription(start_date="2018-01-01") + self.assertEqual(subscription.status, "Active") + self.assertEqual(subscription.current_invoice_start, "2018-01-01") + self.assertEqual(subscription.current_invoice_end, "2018-01-31") + + subscription.process(posting_date="2018-01-31") + self.assertEqual(len(subscription.invoices), 1) + self.assertEqual(subscription.current_invoice_start, "2018-02-01") + self.assertEqual(subscription.current_invoice_end, "2018-02-28") + self.assertEqual(subscription.status, "Unpaid") + + def test_status_goes_back_to_active_after_invoice_is_paid(self): + subscription = create_subscription( + start_date="2018-01-01", generate_invoice_at="Beginning of the current subscription period" + ) + subscription.process(posting_date="2018-01-01") # generate first invoice + self.assertEqual(len(subscription.invoices), 1) + + # Status is unpaid as Days until Due is zero and grace period is Zero + self.assertEqual(subscription.status, "Unpaid") + + subscription.get_current_invoice() + current_invoice = subscription.get_current_invoice() + + self.assertIsNotNone(current_invoice) + + current_invoice.db_set("outstanding_amount", 0) + current_invoice.db_set("status", "Paid") + subscription.process() + + self.assertEqual(subscription.status, "Active") + self.assertEqual(subscription.current_invoice_start, add_months(subscription.start_date, 1)) + self.assertEqual(len(subscription.invoices), 1) + + def test_subscription_cancel_after_grace_period(self): + settings = frappe.get_single("Subscription Settings") + settings.cancel_after_grace = 1 + settings.save() + + subscription = create_subscription(start_date="2018-01-01") + self.assertEqual(subscription.status, "Active") + + subscription.process(posting_date="2018-01-31") # generate first invoice + # This should change status to Cancelled since grace period is 0 + # And is backdated subscription so subscription will be cancelled after processing + self.assertEqual(subscription.status, "Cancelled") + + def test_subscription_unpaid_after_grace_period(self): + settings = frappe.get_single("Subscription Settings") + default_grace_period_action = settings.cancel_after_grace + settings.cancel_after_grace = 0 + settings.save() + + subscription = create_subscription(start_date="2018-01-01") + subscription.process(posting_date="2018-01-31") # generate first invoice + + # Status is unpaid as Days until Due is zero and grace period is Zero + self.assertEqual(subscription.status, "Unpaid") + + settings.cancel_after_grace = default_grace_period_action + settings.save() + + def test_subscription_invoice_days_until_due(self): + _date = add_months(nowdate(), -1) + subscription = create_subscription(start_date=_date, days_until_due=10) + + subscription.process(posting_date=subscription.current_invoice_end) # generate first invoice + self.assertEqual(len(subscription.invoices), 1) + self.assertEqual(subscription.status, "Active") + + def test_subscription_is_past_due_doesnt_change_within_grace_period(self): + settings = frappe.get_single("Subscription Settings") + grace_period = settings.grace_period + settings.grace_period = 1000 + settings.save() + + subscription = create_subscription(start_date=add_days(nowdate(), -1000)) + + subscription.process(posting_date=subscription.current_invoice_end) # generate first invoice + self.assertEqual(subscription.status, "Past Due Date") + + subscription.process() + # Grace period is 1000 days so status should remain as Past Due Date + self.assertEqual(subscription.status, "Past Due Date") + + subscription.process() + self.assertEqual(subscription.status, "Past Due Date") + + subscription.process() + self.assertEqual(subscription.status, "Past Due Date") + + settings.grace_period = grace_period + settings.save() + + def test_subscription_remains_active_during_invoice_period(self): + subscription = create_subscription() # no changes expected + + self.assertEqual(subscription.status, "Active") + self.assertEqual(subscription.current_invoice_start, nowdate()) + self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1)) + self.assertEqual(len(subscription.invoices), 0) + + subscription.process() # no changes expected still + self.assertEqual(subscription.status, "Active") + self.assertEqual(subscription.current_invoice_start, nowdate()) + self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1)) + self.assertEqual(len(subscription.invoices), 0) + + subscription.process() # no changes expected yet still + self.assertEqual(subscription.status, "Active") + self.assertEqual(subscription.current_invoice_start, nowdate()) + self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1)) + self.assertEqual(len(subscription.invoices), 0) + + def test_subscription_cancellation(self): + subscription = create_subscription() + subscription.cancel_subscription() + + self.assertEqual(subscription.status, "Cancelled") + + def test_subscription_cancellation_invoices(self): + settings = frappe.get_single("Subscription Settings") + to_prorate = settings.prorate + settings.prorate = 1 + settings.save() + + subscription = create_subscription() + + self.assertEqual(subscription.status, "Active") + + subscription.cancel_subscription() + # Invoice must have been generated + self.assertEqual(len(subscription.invoices), 1) + + invoice = subscription.get_current_invoice() + diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1) + plan_days = flt( + date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1 + ) + prorate_factor = flt(diff / plan_days) + + self.assertEqual( + flt( + get_prorata_factor( + subscription.current_invoice_end, + subscription.current_invoice_start, + cint(subscription.generate_invoice_at == "Beginning of the current subscription period"), + ), + 2, + ), + flt(prorate_factor, 2), + ) + self.assertEqual(flt(invoice.grand_total, 2), flt(prorate_factor * 900, 2)) + self.assertEqual(subscription.status, "Cancelled") + + settings.prorate = to_prorate + settings.save() + + def test_subscription_cancellation_invoices_with_prorata_false(self): + settings = frappe.get_single("Subscription Settings") + to_prorate = settings.prorate + settings.prorate = 0 + settings.save() + + subscription = create_subscription() + subscription.cancel_subscription() + invoice = subscription.get_current_invoice() + + self.assertEqual(invoice.grand_total, 900) + + settings.prorate = to_prorate + settings.save() + + def test_subscription_cancellation_invoices_with_prorata_true(self): + settings = frappe.get_single("Subscription Settings") + to_prorate = settings.prorate + settings.prorate = 1 + settings.save() + + subscription = create_subscription() + subscription.cancel_subscription() + + invoice = subscription.get_current_invoice() + diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1) + plan_days = flt( + date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1 + ) + prorate_factor = flt(diff / plan_days) + + self.assertEqual(flt(invoice.grand_total, 2), flt(prorate_factor * 900, 2)) + + settings.prorate = to_prorate + settings.save() + + def test_subscription_cancellation_and_process(self): + settings = frappe.get_single("Subscription Settings") + default_grace_period_action = settings.cancel_after_grace + settings.cancel_after_grace = 1 + settings.save() + + subscription = create_subscription(start_date="2018-01-01") + subscription.process() # generate first invoice + + # Generate an invoice for the cancelled period + subscription.cancel_subscription() + self.assertEqual(subscription.status, "Cancelled") + self.assertEqual(len(subscription.invoices), 1) + + subscription.process() + self.assertEqual(subscription.status, "Cancelled") + self.assertEqual(len(subscription.invoices), 1) + + subscription.process() + self.assertEqual(subscription.status, "Cancelled") + self.assertEqual(len(subscription.invoices), 1) + + settings.cancel_after_grace = default_grace_period_action + settings.save() + + def test_subscription_restart_and_process(self): + settings = frappe.get_single("Subscription Settings") + default_grace_period_action = settings.cancel_after_grace + settings.grace_period = 0 + settings.cancel_after_grace = 0 + settings.save() + + subscription = create_subscription(start_date="2018-01-01") + subscription.process(posting_date="2018-01-31") # generate first invoice + + # Status is unpaid as Days until Due is zero and grace period is Zero + self.assertEqual(subscription.status, "Unpaid") + + subscription.cancel_subscription() + self.assertEqual(subscription.status, "Cancelled") + + subscription.restart_subscription() + self.assertEqual(subscription.status, "Active") + self.assertEqual(len(subscription.invoices), 1) + + subscription.process() + self.assertEqual(subscription.status, "Unpaid") + self.assertEqual(len(subscription.invoices), 1) + + subscription.process() + self.assertEqual(subscription.status, "Unpaid") + self.assertEqual(len(subscription.invoices), 1) + + settings.cancel_after_grace = default_grace_period_action + settings.save() + + def test_subscription_unpaid_back_to_active(self): + settings = frappe.get_single("Subscription Settings") + default_grace_period_action = settings.cancel_after_grace + settings.cancel_after_grace = 0 + settings.save() + + subscription = create_subscription( + start_date="2018-01-01", generate_invoice_at="Beginning of the current subscription period" + ) + subscription.process(subscription.current_invoice_start) # generate first invoice + # This should change status to Unpaid since grace period is 0 + self.assertEqual(subscription.status, "Unpaid") + + invoice = subscription.get_current_invoice() + invoice.db_set("outstanding_amount", 0) + invoice.db_set("status", "Paid") + + subscription.process() + self.assertEqual(subscription.status, "Active") + + # A new invoice is generated + subscription.process(posting_date=subscription.current_invoice_start) + self.assertEqual(subscription.status, "Unpaid") + + settings.cancel_after_grace = default_grace_period_action + settings.save() + + def test_restart_active_subscription(self): + subscription = create_subscription() + self.assertRaises(frappe.ValidationError, subscription.restart_subscription) + + def test_subscription_invoice_discount_percentage(self): + subscription = create_subscription(additional_discount_percentage=10) + subscription.cancel_subscription() + + invoice = subscription.get_current_invoice() + + self.assertEqual(invoice.additional_discount_percentage, 10) + self.assertEqual(invoice.apply_discount_on, "Grand Total") + + def test_subscription_invoice_discount_amount(self): + subscription = create_subscription(additional_discount_amount=11) + subscription.cancel_subscription() + + invoice = subscription.get_current_invoice() + + self.assertEqual(invoice.discount_amount, 11) + self.assertEqual(invoice.apply_discount_on, "Grand Total") + + def test_prepaid_subscriptions(self): + # Create a non pre-billed subscription, processing should not create + # invoices. + subscription = create_subscription() + subscription.process() + self.assertEqual(len(subscription.invoices), 0) + + # Change the subscription type to prebilled and process it. + # Prepaid invoice should be generated + subscription.generate_invoice_at = "Beginning of the current subscription period" + subscription.save() + subscription.process() + + self.assertEqual(len(subscription.invoices), 1) + + def test_prepaid_subscriptions_with_prorate_true(self): + settings = frappe.get_single("Subscription Settings") + to_prorate = settings.prorate + settings.prorate = 1 + settings.save() + + subscription = create_subscription( + generate_invoice_at="Beginning of the current subscription period" + ) + subscription.process() + subscription.cancel_subscription() + + self.assertEqual(len(subscription.invoices), 1) + + current_inv = subscription.get_current_invoice() + self.assertEqual(current_inv.status, "Unpaid") + + prorate_factor = 1 + + self.assertEqual(flt(current_inv.grand_total, 2), flt(prorate_factor * 900, 2)) + + settings.prorate = to_prorate + settings.save() + + def test_subscription_with_follow_calendar_months(self): + subscription = frappe.new_doc("Subscription") + subscription.company = "_Test Company" + subscription.party_type = "Supplier" + subscription.party = "_Test Supplier" + subscription.generate_invoice_at = "Beginning of the current subscription period" + subscription.follow_calendar_months = 1 + + # select subscription start date as "2018-01-15" + subscription.start_date = "2018-01-15" + subscription.end_date = "2018-07-15" + subscription.append("plans", {"plan": "_Test Plan Name 4", "qty": 1}) + subscription.save() + + # even though subscription starts at "2018-01-15" and Billing interval is Month and count 3 + # First invoice will end at "2018-03-31" instead of "2018-04-14" + self.assertEqual(get_date_str(subscription.current_invoice_end), "2018-03-31") + + def test_subscription_generate_invoice_past_due(self): + subscription = create_subscription( + start_date="2018-01-01", + party_type="Supplier", + party="_Test Supplier", + generate_invoice_at="Beginning of the current subscription period", + generate_new_invoices_past_due_date=1, + plans=[{"plan": "_Test Plan Name 4", "qty": 1}], + ) + + # Process subscription and create first invoice + # Subscription status will be unpaid since due date has already passed + subscription.process(posting_date="2018-01-01") + self.assertEqual(len(subscription.invoices), 1) + self.assertEqual(subscription.status, "Unpaid") + + # Now the Subscription is unpaid + # Even then new invoice should be created as we have enabled `generate_new_invoices_past_due_date` in + # subscription and the interval between the subscriptions is 3 months + subscription.process(posting_date="2018-04-01") + self.assertEqual(len(subscription.invoices), 2) + + def test_subscription_without_generate_invoice_past_due(self): + subscription = create_subscription( + start_date="2018-01-01", + generate_invoice_at="Beginning of the current subscription period", + plans=[{"plan": "_Test Plan Name 4", "qty": 1}], + ) + + # Process subscription and create first invoice + # Subscription status will be unpaid since due date has already passed + subscription.process() + self.assertEqual(len(subscription.invoices), 1) + self.assertEqual(subscription.status, "Unpaid") + + subscription.process() + self.assertEqual(len(subscription.invoices), 1) + + def test_multi_currency_subscription(self): + subscription = create_subscription( + start_date="2018-01-01", + generate_invoice_at="Beginning of the current subscription period", + plans=[{"plan": "_Test Plan Multicurrency", "qty": 1}], + party="_Test Subscription Customer", + ) + + subscription.process() + self.assertEqual(len(subscription.invoices), 1) + self.assertEqual(subscription.status, "Unpaid") + + # Check the currency of the created invoice + currency = frappe.db.get_value("Sales Invoice", subscription.invoices[0].name, "currency") + self.assertEqual(currency, "USD") + + def test_subscription_recovery(self): + """Test if Subscription recovers when start/end date run out of sync with created invoices.""" + subscription = create_subscription( + start_date="2021-01-01", + submit_invoice=0, + generate_new_invoices_past_due_date=1, + party="_Test Subscription Customer", + ) + + # create invoices for the first two moths + subscription.process(posting_date="2021-01-31") + + subscription.process(posting_date="2021-02-28") + + self.assertEqual(len(subscription.invoices), 2) + self.assertEqual( + getdate(frappe.db.get_value("Sales Invoice", subscription.invoices[0].name, "from_date")), + getdate("2021-01-01"), + ) + self.assertEqual( + getdate(frappe.db.get_value("Sales Invoice", subscription.invoices[1].name, "from_date")), + getdate("2021-02-01"), + ) + + # recreate most recent invoice + subscription.process(posting_date="2022-01-31") + + self.assertEqual(len(subscription.invoices), 2) + self.assertEqual( + getdate(frappe.db.get_value("Sales Invoice", subscription.invoices[0].name, "from_date")), + getdate("2021-01-01"), + ) + self.assertEqual( + getdate(frappe.db.get_value("Sales Invoice", subscription.invoices[1].name, "from_date")), + getdate("2021-02-01"), + ) + + def test_subscription_invoice_generation_before_days(self): + subscription = create_subscription( + start_date="2023-01-01", + generate_invoice_at="Days before the current subscription period", + number_of_days=10, + generate_new_invoices_past_due_date=1, + ) + + subscription.process(posting_date="2022-12-22") + self.assertEqual(len(subscription.invoices), 1) + + subscription.process(posting_date="2023-01-22") + self.assertEqual(len(subscription.invoices), 2) + + +def make_plans(): + create_plan(plan_name="_Test Plan Name", cost=900) + create_plan(plan_name="_Test Plan Name 2", cost=1999) + create_plan( + plan_name="_Test Plan Name 3", cost=1999, billing_interval="Day", billing_interval_count=14 + ) + create_plan( + plan_name="_Test Plan Name 4", cost=20000, billing_interval="Month", billing_interval_count=3 + ) + create_plan( + plan_name="_Test Plan Multicurrency", cost=50, billing_interval="Month", currency="USD" + ) + + +def create_plan(**kwargs): + if not frappe.db.exists("Subscription Plan", kwargs.get("plan_name")): +>>>>>>> 3bdf4f628c (refactor(test): use test fixture in subscription) plan = frappe.new_doc("Subscription Plan") plan.plan_name = "_Test Plan Name" plan.item = "_Test Non Stock Item" From 33becb7b325046d1b17ab6c0362219bcbb94bd53 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 15 Oct 2023 06:35:22 +0530 Subject: [PATCH 07/11] refactor(test): use test fixture in purchase invoice (cherry picked from commit a2e064d214ffb9f012f2144bee14cd467e935241) --- .../doctype/purchase_invoice/test_purchase_invoice.py | 7 +++++-- 1 file changed, 5 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 47126d3846f..60892e9fc84 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -5,7 +5,7 @@ import unittest import frappe -from frappe.tests.utils import change_settings +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, cint, flt, getdate, nowdate, today import erpnext @@ -33,7 +33,7 @@ test_dependencies = ["Item", "Cost Center", "Payment Term", "Payment Terms Templ test_ignore = ["Serial No"] -class TestPurchaseInvoice(unittest.TestCase, StockTestMixin): +class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): @classmethod def setUpClass(self): unlink_payment_on_cancel_of_invoice() @@ -43,6 +43,9 @@ class TestPurchaseInvoice(unittest.TestCase, StockTestMixin): def tearDownClass(self): unlink_payment_on_cancel_of_invoice(0) + def tearDown(self): + frappe.db.rollback() + def test_purchase_invoice_received_qty(self): """ 1. Test if received qty is validated against accepted + rejected From d78316869b5e13321f5ac3266b6eed19272fa550 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 15 Oct 2023 07:11:11 +0530 Subject: [PATCH 08/11] refactor(test): make use of @change_settings in PI test cases (cherry picked from commit 0207d6e7c996cd6c1b04f2ba171fdf3d6ccfa130) --- .../doctype/purchase_invoice/test_purchase_invoice.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py index 60892e9fc84..170a163b45f 100644 --- a/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py @@ -420,6 +420,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): self.assertEqual(tax.tax_amount, expected_values[i][1]) self.assertEqual(tax.total, expected_values[i][2]) + @change_settings("Accounts Settings", {"unlink_payment_on_cancellation_of_invoice": 1}) def test_purchase_invoice_with_advance(self): from erpnext.accounts.doctype.journal_entry.test_journal_entry import ( test_records as jv_test_records, @@ -474,6 +475,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): ) ) + @change_settings("Accounts Settings", {"unlink_payment_on_cancellation_of_invoice": 1}) def test_invoice_with_advance_and_multi_payment_terms(self): from erpnext.accounts.doctype.journal_entry.test_journal_entry import ( test_records as jv_test_records, @@ -1212,6 +1214,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): acc_settings.submit_journal_entriessubmit_journal_entries = 0 acc_settings.save() + @change_settings("Accounts Settings", {"unlink_payment_on_cancellation_of_invoice": 1}) def test_gain_loss_with_advance_entry(self): unlink_enabled = frappe.db.get_value( "Accounts Settings", "Accounts Settings", "unlink_payment_on_cancel_of_invoice" @@ -1414,6 +1417,7 @@ class TestPurchaseInvoice(FrappeTestCase, StockTestMixin): ) frappe.db.set_value("Company", "_Test Company", "exchange_gain_loss_account", original_account) + @change_settings("Accounts Settings", {"unlink_payment_on_cancellation_of_invoice": 1}) def test_purchase_invoice_advance_taxes(self): from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry From 8d1eac89e3f858b07bc9c27e0948a550c9e16c89 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 15 Oct 2023 08:07:29 +0530 Subject: [PATCH 09/11] refactor(test): make sure TDS Payable is available for testing (cherry picked from commit fbabf4ac2e96c473884c94e59b715d14dee3f960) --- .../accounts/doctype/sales_invoice/test_sales_invoice.py | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 6aae93388d8..ceeed34c821 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -2784,6 +2784,13 @@ class TestSalesInvoice(FrappeTestCase): company="_Test Company", ) + tds_payable_account = create_account( + account_name="TDS Payable", + account_type="Tax", + parent_account="Duties and Taxes - _TC", + company="_Test Company", + ) + si = create_sales_invoice(parent_cost_center="Main - _TC", do_not_save=1) si.apply_discount_on = "Grand Total" si.additional_discount_account = additional_discount_account From 7f903532f396445be30fe57af61ff7bb88c649e5 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 15 Oct 2023 10:40:57 +0530 Subject: [PATCH 10/11] chore: resovle conflicts --- .../sales_invoice/test_sales_invoice.py | 27 - .../doctype/subscription/test_subscription.py | 530 +----------------- 2 files changed, 5 insertions(+), 552 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index ceeed34c821..272382e8c18 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -6,12 +6,8 @@ import unittest import frappe from frappe.model.dynamic_links import get_dynamic_link_map -<<<<<<< HEAD from frappe.model.naming import make_autoname -from frappe.tests.utils import change_settings -======= from frappe.tests.utils import FrappeTestCase, change_settings ->>>>>>> c322e5f381 (test: use fixtures for sales and purchase invoice) from frappe.utils import add_days, flt, getdate, nowdate, today import erpnext @@ -3091,10 +3087,6 @@ class TestSalesInvoice(FrappeTestCase): @change_settings("Accounts Settings", {"acc_frozen_upto": add_days(getdate(), 1)}) def test_sales_invoice_submission_post_account_freezing_date(self): -<<<<<<< HEAD - frappe.db.set_value("Accounts Settings", None, "acc_frozen_upto", add_days(getdate(), 1)) -======= ->>>>>>> 58065f31b1 (refactor(test): use @change_settings in sales invoice) si = create_sales_invoice(do_not_save=True) si.posting_date = add_days(getdate(), 1) si.save() @@ -3103,11 +3095,6 @@ class TestSalesInvoice(FrappeTestCase): si.posting_date = getdate() si.submit() -<<<<<<< HEAD - frappe.db.set_value("Accounts Settings", None, "acc_frozen_upto", None) - -======= ->>>>>>> 58065f31b1 (refactor(test): use @change_settings in sales invoice) def test_over_billing_case_against_delivery_note(self): """ Test a case where duplicating the item with qty = 1 in the invoice @@ -3215,20 +3202,6 @@ class TestSalesInvoice(FrappeTestCase): self.assertEqual(expected_gle[i][2], gle.debit) self.assertEqual(getdate(expected_gle[i][3]), gle.posting_date) -<<<<<<< HEAD -<<<<<<< HEAD - acc_settings = frappe.get_single("Accounts Settings") - acc_settings.book_deferred_entries_via_journal_entry = 0 - acc_settings.submit_journal_entries = 0 - acc_settings.save() - - frappe.db.set_value("Accounts Settings", None, "acc_frozen_upto", None) -======= - frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) ->>>>>>> 58065f31b1 (refactor(test): use @change_settings in sales invoice) - -======= ->>>>>>> 8ebe5733ac (refactor(test): fix broken test cases in Sales Invoice) def test_standalone_serial_no_return(self): si = create_sales_invoice( item_code="_Test Serialized Item With Series", update_stock=True, is_return=True, qty=-1 diff --git a/erpnext/accounts/doctype/subscription/test_subscription.py b/erpnext/accounts/doctype/subscription/test_subscription.py index 4acddfec7e2..89ba0c8055e 100644 --- a/erpnext/accounts/doctype/subscription/test_subscription.py +++ b/erpnext/accounts/doctype/subscription/test_subscription.py @@ -20,532 +20,8 @@ from erpnext.accounts.doctype.subscription.subscription import get_prorata_facto test_dependencies = ("UOM", "Item Group", "Item") -<<<<<<< HEAD def create_plan(): if not frappe.db.exists("Subscription Plan", "_Test Plan Name"): -======= -class TestSubscription(FrappeTestCase): - def setUp(self): - make_plans() - create_parties() - reset_settings() - frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) - - def tearDown(self): - frappe.db.rollback() - - def test_create_subscription_with_trial_with_correct_period(self): - subscription = create_subscription( - trial_period_start=nowdate(), trial_period_end=add_months(nowdate(), 1) - ) - self.assertEqual(subscription.trial_period_start, nowdate()) - self.assertEqual(subscription.trial_period_end, add_months(nowdate(), 1)) - self.assertEqual( - add_days(subscription.trial_period_end, 1), get_date_str(subscription.current_invoice_start) - ) - self.assertEqual( - add_to_date(subscription.current_invoice_start, months=1, days=-1), - get_date_str(subscription.current_invoice_end), - ) - self.assertEqual(subscription.invoices, []) - self.assertEqual(subscription.status, "Trialling") - - def test_create_subscription_without_trial_with_correct_period(self): - subscription = create_subscription() - self.assertEqual(subscription.trial_period_start, None) - self.assertEqual(subscription.trial_period_end, None) - self.assertEqual(subscription.current_invoice_start, nowdate()) - self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1)) - # No invoice is created - self.assertEqual(len(subscription.invoices), 0) - self.assertEqual(subscription.status, "Active") - - def test_create_subscription_trial_with_wrong_dates(self): - subscription = create_subscription( - trial_period_start=add_days(nowdate(), 30), trial_period_end=nowdate(), do_not_save=True - ) - self.assertRaises(frappe.ValidationError, subscription.save) - - def test_invoice_is_generated_at_end_of_billing_period(self): - subscription = create_subscription(start_date="2018-01-01") - self.assertEqual(subscription.status, "Active") - self.assertEqual(subscription.current_invoice_start, "2018-01-01") - self.assertEqual(subscription.current_invoice_end, "2018-01-31") - - subscription.process(posting_date="2018-01-31") - self.assertEqual(len(subscription.invoices), 1) - self.assertEqual(subscription.current_invoice_start, "2018-02-01") - self.assertEqual(subscription.current_invoice_end, "2018-02-28") - self.assertEqual(subscription.status, "Unpaid") - - def test_status_goes_back_to_active_after_invoice_is_paid(self): - subscription = create_subscription( - start_date="2018-01-01", generate_invoice_at="Beginning of the current subscription period" - ) - subscription.process(posting_date="2018-01-01") # generate first invoice - self.assertEqual(len(subscription.invoices), 1) - - # Status is unpaid as Days until Due is zero and grace period is Zero - self.assertEqual(subscription.status, "Unpaid") - - subscription.get_current_invoice() - current_invoice = subscription.get_current_invoice() - - self.assertIsNotNone(current_invoice) - - current_invoice.db_set("outstanding_amount", 0) - current_invoice.db_set("status", "Paid") - subscription.process() - - self.assertEqual(subscription.status, "Active") - self.assertEqual(subscription.current_invoice_start, add_months(subscription.start_date, 1)) - self.assertEqual(len(subscription.invoices), 1) - - def test_subscription_cancel_after_grace_period(self): - settings = frappe.get_single("Subscription Settings") - settings.cancel_after_grace = 1 - settings.save() - - subscription = create_subscription(start_date="2018-01-01") - self.assertEqual(subscription.status, "Active") - - subscription.process(posting_date="2018-01-31") # generate first invoice - # This should change status to Cancelled since grace period is 0 - # And is backdated subscription so subscription will be cancelled after processing - self.assertEqual(subscription.status, "Cancelled") - - def test_subscription_unpaid_after_grace_period(self): - settings = frappe.get_single("Subscription Settings") - default_grace_period_action = settings.cancel_after_grace - settings.cancel_after_grace = 0 - settings.save() - - subscription = create_subscription(start_date="2018-01-01") - subscription.process(posting_date="2018-01-31") # generate first invoice - - # Status is unpaid as Days until Due is zero and grace period is Zero - self.assertEqual(subscription.status, "Unpaid") - - settings.cancel_after_grace = default_grace_period_action - settings.save() - - def test_subscription_invoice_days_until_due(self): - _date = add_months(nowdate(), -1) - subscription = create_subscription(start_date=_date, days_until_due=10) - - subscription.process(posting_date=subscription.current_invoice_end) # generate first invoice - self.assertEqual(len(subscription.invoices), 1) - self.assertEqual(subscription.status, "Active") - - def test_subscription_is_past_due_doesnt_change_within_grace_period(self): - settings = frappe.get_single("Subscription Settings") - grace_period = settings.grace_period - settings.grace_period = 1000 - settings.save() - - subscription = create_subscription(start_date=add_days(nowdate(), -1000)) - - subscription.process(posting_date=subscription.current_invoice_end) # generate first invoice - self.assertEqual(subscription.status, "Past Due Date") - - subscription.process() - # Grace period is 1000 days so status should remain as Past Due Date - self.assertEqual(subscription.status, "Past Due Date") - - subscription.process() - self.assertEqual(subscription.status, "Past Due Date") - - subscription.process() - self.assertEqual(subscription.status, "Past Due Date") - - settings.grace_period = grace_period - settings.save() - - def test_subscription_remains_active_during_invoice_period(self): - subscription = create_subscription() # no changes expected - - self.assertEqual(subscription.status, "Active") - self.assertEqual(subscription.current_invoice_start, nowdate()) - self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1)) - self.assertEqual(len(subscription.invoices), 0) - - subscription.process() # no changes expected still - self.assertEqual(subscription.status, "Active") - self.assertEqual(subscription.current_invoice_start, nowdate()) - self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1)) - self.assertEqual(len(subscription.invoices), 0) - - subscription.process() # no changes expected yet still - self.assertEqual(subscription.status, "Active") - self.assertEqual(subscription.current_invoice_start, nowdate()) - self.assertEqual(subscription.current_invoice_end, add_to_date(nowdate(), months=1, days=-1)) - self.assertEqual(len(subscription.invoices), 0) - - def test_subscription_cancellation(self): - subscription = create_subscription() - subscription.cancel_subscription() - - self.assertEqual(subscription.status, "Cancelled") - - def test_subscription_cancellation_invoices(self): - settings = frappe.get_single("Subscription Settings") - to_prorate = settings.prorate - settings.prorate = 1 - settings.save() - - subscription = create_subscription() - - self.assertEqual(subscription.status, "Active") - - subscription.cancel_subscription() - # Invoice must have been generated - self.assertEqual(len(subscription.invoices), 1) - - invoice = subscription.get_current_invoice() - diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1) - plan_days = flt( - date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1 - ) - prorate_factor = flt(diff / plan_days) - - self.assertEqual( - flt( - get_prorata_factor( - subscription.current_invoice_end, - subscription.current_invoice_start, - cint(subscription.generate_invoice_at == "Beginning of the current subscription period"), - ), - 2, - ), - flt(prorate_factor, 2), - ) - self.assertEqual(flt(invoice.grand_total, 2), flt(prorate_factor * 900, 2)) - self.assertEqual(subscription.status, "Cancelled") - - settings.prorate = to_prorate - settings.save() - - def test_subscription_cancellation_invoices_with_prorata_false(self): - settings = frappe.get_single("Subscription Settings") - to_prorate = settings.prorate - settings.prorate = 0 - settings.save() - - subscription = create_subscription() - subscription.cancel_subscription() - invoice = subscription.get_current_invoice() - - self.assertEqual(invoice.grand_total, 900) - - settings.prorate = to_prorate - settings.save() - - def test_subscription_cancellation_invoices_with_prorata_true(self): - settings = frappe.get_single("Subscription Settings") - to_prorate = settings.prorate - settings.prorate = 1 - settings.save() - - subscription = create_subscription() - subscription.cancel_subscription() - - invoice = subscription.get_current_invoice() - diff = flt(date_diff(nowdate(), subscription.current_invoice_start) + 1) - plan_days = flt( - date_diff(subscription.current_invoice_end, subscription.current_invoice_start) + 1 - ) - prorate_factor = flt(diff / plan_days) - - self.assertEqual(flt(invoice.grand_total, 2), flt(prorate_factor * 900, 2)) - - settings.prorate = to_prorate - settings.save() - - def test_subscription_cancellation_and_process(self): - settings = frappe.get_single("Subscription Settings") - default_grace_period_action = settings.cancel_after_grace - settings.cancel_after_grace = 1 - settings.save() - - subscription = create_subscription(start_date="2018-01-01") - subscription.process() # generate first invoice - - # Generate an invoice for the cancelled period - subscription.cancel_subscription() - self.assertEqual(subscription.status, "Cancelled") - self.assertEqual(len(subscription.invoices), 1) - - subscription.process() - self.assertEqual(subscription.status, "Cancelled") - self.assertEqual(len(subscription.invoices), 1) - - subscription.process() - self.assertEqual(subscription.status, "Cancelled") - self.assertEqual(len(subscription.invoices), 1) - - settings.cancel_after_grace = default_grace_period_action - settings.save() - - def test_subscription_restart_and_process(self): - settings = frappe.get_single("Subscription Settings") - default_grace_period_action = settings.cancel_after_grace - settings.grace_period = 0 - settings.cancel_after_grace = 0 - settings.save() - - subscription = create_subscription(start_date="2018-01-01") - subscription.process(posting_date="2018-01-31") # generate first invoice - - # Status is unpaid as Days until Due is zero and grace period is Zero - self.assertEqual(subscription.status, "Unpaid") - - subscription.cancel_subscription() - self.assertEqual(subscription.status, "Cancelled") - - subscription.restart_subscription() - self.assertEqual(subscription.status, "Active") - self.assertEqual(len(subscription.invoices), 1) - - subscription.process() - self.assertEqual(subscription.status, "Unpaid") - self.assertEqual(len(subscription.invoices), 1) - - subscription.process() - self.assertEqual(subscription.status, "Unpaid") - self.assertEqual(len(subscription.invoices), 1) - - settings.cancel_after_grace = default_grace_period_action - settings.save() - - def test_subscription_unpaid_back_to_active(self): - settings = frappe.get_single("Subscription Settings") - default_grace_period_action = settings.cancel_after_grace - settings.cancel_after_grace = 0 - settings.save() - - subscription = create_subscription( - start_date="2018-01-01", generate_invoice_at="Beginning of the current subscription period" - ) - subscription.process(subscription.current_invoice_start) # generate first invoice - # This should change status to Unpaid since grace period is 0 - self.assertEqual(subscription.status, "Unpaid") - - invoice = subscription.get_current_invoice() - invoice.db_set("outstanding_amount", 0) - invoice.db_set("status", "Paid") - - subscription.process() - self.assertEqual(subscription.status, "Active") - - # A new invoice is generated - subscription.process(posting_date=subscription.current_invoice_start) - self.assertEqual(subscription.status, "Unpaid") - - settings.cancel_after_grace = default_grace_period_action - settings.save() - - def test_restart_active_subscription(self): - subscription = create_subscription() - self.assertRaises(frappe.ValidationError, subscription.restart_subscription) - - def test_subscription_invoice_discount_percentage(self): - subscription = create_subscription(additional_discount_percentage=10) - subscription.cancel_subscription() - - invoice = subscription.get_current_invoice() - - self.assertEqual(invoice.additional_discount_percentage, 10) - self.assertEqual(invoice.apply_discount_on, "Grand Total") - - def test_subscription_invoice_discount_amount(self): - subscription = create_subscription(additional_discount_amount=11) - subscription.cancel_subscription() - - invoice = subscription.get_current_invoice() - - self.assertEqual(invoice.discount_amount, 11) - self.assertEqual(invoice.apply_discount_on, "Grand Total") - - def test_prepaid_subscriptions(self): - # Create a non pre-billed subscription, processing should not create - # invoices. - subscription = create_subscription() - subscription.process() - self.assertEqual(len(subscription.invoices), 0) - - # Change the subscription type to prebilled and process it. - # Prepaid invoice should be generated - subscription.generate_invoice_at = "Beginning of the current subscription period" - subscription.save() - subscription.process() - - self.assertEqual(len(subscription.invoices), 1) - - def test_prepaid_subscriptions_with_prorate_true(self): - settings = frappe.get_single("Subscription Settings") - to_prorate = settings.prorate - settings.prorate = 1 - settings.save() - - subscription = create_subscription( - generate_invoice_at="Beginning of the current subscription period" - ) - subscription.process() - subscription.cancel_subscription() - - self.assertEqual(len(subscription.invoices), 1) - - current_inv = subscription.get_current_invoice() - self.assertEqual(current_inv.status, "Unpaid") - - prorate_factor = 1 - - self.assertEqual(flt(current_inv.grand_total, 2), flt(prorate_factor * 900, 2)) - - settings.prorate = to_prorate - settings.save() - - def test_subscription_with_follow_calendar_months(self): - subscription = frappe.new_doc("Subscription") - subscription.company = "_Test Company" - subscription.party_type = "Supplier" - subscription.party = "_Test Supplier" - subscription.generate_invoice_at = "Beginning of the current subscription period" - subscription.follow_calendar_months = 1 - - # select subscription start date as "2018-01-15" - subscription.start_date = "2018-01-15" - subscription.end_date = "2018-07-15" - subscription.append("plans", {"plan": "_Test Plan Name 4", "qty": 1}) - subscription.save() - - # even though subscription starts at "2018-01-15" and Billing interval is Month and count 3 - # First invoice will end at "2018-03-31" instead of "2018-04-14" - self.assertEqual(get_date_str(subscription.current_invoice_end), "2018-03-31") - - def test_subscription_generate_invoice_past_due(self): - subscription = create_subscription( - start_date="2018-01-01", - party_type="Supplier", - party="_Test Supplier", - generate_invoice_at="Beginning of the current subscription period", - generate_new_invoices_past_due_date=1, - plans=[{"plan": "_Test Plan Name 4", "qty": 1}], - ) - - # Process subscription and create first invoice - # Subscription status will be unpaid since due date has already passed - subscription.process(posting_date="2018-01-01") - self.assertEqual(len(subscription.invoices), 1) - self.assertEqual(subscription.status, "Unpaid") - - # Now the Subscription is unpaid - # Even then new invoice should be created as we have enabled `generate_new_invoices_past_due_date` in - # subscription and the interval between the subscriptions is 3 months - subscription.process(posting_date="2018-04-01") - self.assertEqual(len(subscription.invoices), 2) - - def test_subscription_without_generate_invoice_past_due(self): - subscription = create_subscription( - start_date="2018-01-01", - generate_invoice_at="Beginning of the current subscription period", - plans=[{"plan": "_Test Plan Name 4", "qty": 1}], - ) - - # Process subscription and create first invoice - # Subscription status will be unpaid since due date has already passed - subscription.process() - self.assertEqual(len(subscription.invoices), 1) - self.assertEqual(subscription.status, "Unpaid") - - subscription.process() - self.assertEqual(len(subscription.invoices), 1) - - def test_multi_currency_subscription(self): - subscription = create_subscription( - start_date="2018-01-01", - generate_invoice_at="Beginning of the current subscription period", - plans=[{"plan": "_Test Plan Multicurrency", "qty": 1}], - party="_Test Subscription Customer", - ) - - subscription.process() - self.assertEqual(len(subscription.invoices), 1) - self.assertEqual(subscription.status, "Unpaid") - - # Check the currency of the created invoice - currency = frappe.db.get_value("Sales Invoice", subscription.invoices[0].name, "currency") - self.assertEqual(currency, "USD") - - def test_subscription_recovery(self): - """Test if Subscription recovers when start/end date run out of sync with created invoices.""" - subscription = create_subscription( - start_date="2021-01-01", - submit_invoice=0, - generate_new_invoices_past_due_date=1, - party="_Test Subscription Customer", - ) - - # create invoices for the first two moths - subscription.process(posting_date="2021-01-31") - - subscription.process(posting_date="2021-02-28") - - self.assertEqual(len(subscription.invoices), 2) - self.assertEqual( - getdate(frappe.db.get_value("Sales Invoice", subscription.invoices[0].name, "from_date")), - getdate("2021-01-01"), - ) - self.assertEqual( - getdate(frappe.db.get_value("Sales Invoice", subscription.invoices[1].name, "from_date")), - getdate("2021-02-01"), - ) - - # recreate most recent invoice - subscription.process(posting_date="2022-01-31") - - self.assertEqual(len(subscription.invoices), 2) - self.assertEqual( - getdate(frappe.db.get_value("Sales Invoice", subscription.invoices[0].name, "from_date")), - getdate("2021-01-01"), - ) - self.assertEqual( - getdate(frappe.db.get_value("Sales Invoice", subscription.invoices[1].name, "from_date")), - getdate("2021-02-01"), - ) - - def test_subscription_invoice_generation_before_days(self): - subscription = create_subscription( - start_date="2023-01-01", - generate_invoice_at="Days before the current subscription period", - number_of_days=10, - generate_new_invoices_past_due_date=1, - ) - - subscription.process(posting_date="2022-12-22") - self.assertEqual(len(subscription.invoices), 1) - - subscription.process(posting_date="2023-01-22") - self.assertEqual(len(subscription.invoices), 2) - - -def make_plans(): - create_plan(plan_name="_Test Plan Name", cost=900) - create_plan(plan_name="_Test Plan Name 2", cost=1999) - create_plan( - plan_name="_Test Plan Name 3", cost=1999, billing_interval="Day", billing_interval_count=14 - ) - create_plan( - plan_name="_Test Plan Name 4", cost=20000, billing_interval="Month", billing_interval_count=3 - ) - create_plan( - plan_name="_Test Plan Multicurrency", cost=50, billing_interval="Month", currency="USD" - ) - - -def create_plan(**kwargs): - if not frappe.db.exists("Subscription Plan", kwargs.get("plan_name")): ->>>>>>> 3bdf4f628c (refactor(test): use test fixture in subscription) plan = frappe.new_doc("Subscription Plan") plan.plan_name = "_Test Plan Name" plan.item = "_Test Non Stock Item" @@ -615,10 +91,14 @@ def create_parties(): customer.insert() -class TestSubscription(unittest.TestCase): +class TestSubscription(FrappeTestCase): def setUp(self): create_plan() create_parties() + frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) + + def tearDown(self): + frappe.db.rollback() def test_create_subscription_with_trial_with_correct_period(self): subscription = frappe.new_doc("Subscription") From d1f6d62d72c9543996ef638d3d3005b36fc054c4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Sun, 15 Oct 2023 12:19:34 +0530 Subject: [PATCH 11/11] chore: fix flaky test case --- .../test_bank_reconciliation_statement.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/report/bank_reconciliation_statement/test_bank_reconciliation_statement.py b/erpnext/accounts/report/bank_reconciliation_statement/test_bank_reconciliation_statement.py index d7c871608ec..b1be53ba73f 100644 --- a/erpnext/accounts/report/bank_reconciliation_statement/test_bank_reconciliation_statement.py +++ b/erpnext/accounts/report/bank_reconciliation_statement/test_bank_reconciliation_statement.py @@ -23,6 +23,7 @@ class TestBankReconciliationStatement(FrappeTestCase): "Payment Entry", ]: frappe.db.delete(dt) + frappe.db.set_single_value("Accounts Settings", "acc_frozen_upto", None) def test_loan_entries_in_bank_reco_statement(self): create_loan_accounts()