diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index 41f88e8a9a54f7b3e615a21d81287fe831ecb2c3..2ae4d9e05d000598a4d29f9eee8bbc22dd5c62ed 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -931,40 +931,46 @@ class SalesInvoice(SellingController): ) def validate_with_previous_doc(self): - super().validate_with_previous_doc( - { - "Sales Order": { - "ref_dn_field": "sales_order", - "compare_fields": [ - ["customer", "="], - ["company", "="], - ["project", "="], - ["currency", "="], - ], - }, - "Sales Order Item": { - "ref_dn_field": "so_detail", - "compare_fields": [["item_code", "="], ["uom", "="], ["conversion_factor", "="]], - "is_child_table": True, - "allow_duplicate_prev_row_id": True, - }, - "Delivery Note": { - "ref_dn_field": "delivery_note", - "compare_fields": [ - ["customer", "="], - ["company", "="], - ["project", "="], - ["currency", "="], - ], - }, - "Delivery Note Item": { - "ref_dn_field": "dn_detail", - "compare_fields": [["item_code", "="], ["uom", "="], ["conversion_factor", "="]], - "is_child_table": True, - "allow_duplicate_prev_row_id": True, - }, - } - ) + # @dokos + validation_conditions = { + "Sales Order": { + "ref_dn_field": "sales_order", + "compare_fields": [ + ["customer", "="], + ["company", "="], + ["currency", "="], + ], + }, + "Sales Order Item": { + "ref_dn_field": "so_detail", + "compare_fields": [["item_code", "="], ["uom", "="], ["conversion_factor", "="]], + "is_child_table": True, + "allow_duplicate_prev_row_id": True, + }, + "Delivery Note": { + "ref_dn_field": "delivery_note", + "compare_fields": [ + ["customer", "="], + ["company", "="], + ["currency", "="], + ], + }, + "Delivery Note Item": { + "ref_dn_field": "dn_detail", + "compare_fields": [["item_code", "="], ["uom", "="], ["conversion_factor", "="]], + "is_child_table": True, + "allow_duplicate_prev_row_id": True, + }, + } + + if frappe.db.get_single_value("Selling Settings", "validate_project_in_so_si"): + validation_conditions["Sales Order"]["compare_fields"].append(["project", "="]) + validation_conditions["Sales Order Item"]["compare_fields"].append(["project", "="]) + validation_conditions["Delivery Note"]["compare_fields"].append(["project", "="]) + validation_conditions["Delivery Note Item"]["compare_fields"].append(["project", "="]) + + super().validate_with_previous_doc(validation_conditions) + # @dokos if ( cint(frappe.db.get_single_value("Selling Settings", "maintain_same_sales_rate")) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index 56fc4b0d4ffbe64023e11b62b3ed67b343a079a8..4ad3a01a1f281ba21045ea0c5dcbf1e036f43014 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -927,7 +927,7 @@ class TestSalesInvoice(FrappeTestCase): ] ) - for i, gle in enumerate(gl_entries): + for _i, gle in enumerate(gl_entries): self.assertEqual(expected_values[gle.account][0], gle.account) self.assertEqual(expected_values[gle.account][1], gle.debit) self.assertEqual(expected_values[gle.account][2], gle.credit) @@ -1336,7 +1336,7 @@ class TestSalesInvoice(FrappeTestCase): expected_values = dict( (d[0], d) for d in [["Debtors - TCP1", 100.0, 0.0], ["Sales - TCP1", 0.0, 100.0]] ) - for i, gle in enumerate(gl_entries): + for _i, gle in enumerate(gl_entries): self.assertEqual(expected_values[gle.account][0], gle.account) self.assertEqual(expected_values[gle.account][1], gle.debit) self.assertEqual(expected_values[gle.account][2], gle.credit) @@ -1360,7 +1360,7 @@ class TestSalesInvoice(FrappeTestCase): [test_records[1]["items"][0]["income_account"], 0.0, 100.0], ] ) - for i, gle in enumerate(gl_entries): + for _i, gle in enumerate(gl_entries): self.assertEqual(expected_values[gle.account][0], gle.account) self.assertEqual(expected_values[gle.account][1], gle.debit) self.assertEqual(expected_values[gle.account][2], gle.credit) @@ -1774,7 +1774,7 @@ class TestSalesInvoice(FrappeTestCase): "credit", "credit_in_account_currency", ): - for i, gle in enumerate(gl_entries): + for _i, gle in enumerate(gl_entries): self.assertEqual(expected_values[gle.account][field], gle[field]) # cancel @@ -2921,7 +2921,7 @@ class TestSalesInvoice(FrappeTestCase): company="_Test Company", ) - tds_payable_account = create_account( + create_account( account_name="TDS Payable", account_type="Tax", parent_account="Duties and Taxes - _TC", @@ -3436,7 +3436,7 @@ class TestSalesInvoice(FrappeTestCase): self.assertEqual(len(journals), 1) je_type = frappe.get_cached_value("Journal Entry", journals[0], "voucher_type") self.assertEqual(je_type, "Exchange Gain Or Loss") - ledger_outstanding = frappe.db.get_all( + frappe.db.get_all( "Payment Ledger Entry", filters={"against_voucher_no": si.name, "delinked": 0}, fields=["sum(amount), sum(amount_in_account_currency)"], @@ -3788,6 +3788,53 @@ class TestSalesInvoice(FrappeTestCase): ] self.assertEqual(expected, actual) + @change_settings("Selling Settings", {"validate_project_in_so_si": 1}) + def test_project_validation_in_so_si(self): + from erpnext.projects.doctype.project.test_project import make_project + 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 + + project = make_project( + { + "project_name": "Sales Order Project", + "project_template_name": "Test Project Template", + "start_date": "2024-01-01", + } + ) + + sales_order = make_sales_order( + item_code="138-CMS Shoe", qty=1, price_list_rate=500, do_not_submit=True + ) + sales_order.items[0].project = project.name + sales_order.submit() + + sales_invoice = make_sales_invoice(sales_order.name) + sales_invoice.submit() + + self.assertEqual(sales_invoice.items[0].project, project.name) + + si_project = make_project( + { + "project_name": "Sales Invoice Project", + "project_template_name": "Test Project Template", + "start_date": "2024-01-01", + } + ) + + sales_order = make_sales_order( + item_code="138-CMS Shoe", qty=1, price_list_rate=500, do_not_submit=True + ) + sales_order.items[0].project = project.name + sales_order.submit() + + sales_invoice = make_sales_invoice(sales_order.name) + sales_invoice.items[0].project = si_project.name + + self.assertRaises(frappe.exceptions.ValidationError, sales_invoice.submit) + + with change_settings("Selling Settings", {"validate_project_in_so_si": 0}): + sales_invoice.submit() + def set_advance_flag(company, default_account): frappe.db.set_value( diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 28ad71bd0a88f69c24440e2387849cae0ab96966..35a08005ec0107972cab80b61e3ab387287bd25b 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -35,7 +35,8 @@ "create_tasks_from_sales_order", "hide_tax_id", "enable_discount_accounting", - "enable_cutoff_date_on_bulk_delivery_note_creation" + "enable_cutoff_date_on_bulk_delivery_note_creation", + "validate_project_in_so_si" ], "fields": [ { @@ -223,6 +224,12 @@ "fieldname": "enable_cutoff_date_on_bulk_delivery_note_creation", "fieldtype": "Check", "label": "Enable Cut-Off Date on Bulk Delivery Note Creation" + }, + { + "default": "1", + "fieldname": "validate_project_in_so_si", + "fieldtype": "Check", + "label": "Force identical project in sales orders and sales invoices header and line items" } ], "icon": "fa fa-cog", @@ -230,7 +237,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2024-03-27 13:10:38.633352", + "modified": "2024-07-05 18:39:50.173353", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.py b/erpnext/selling/doctype/selling_settings/selling_settings.py index cc1332dc0058650198f5798c646ed616b0b8117c..0f1538cdfcd686487af6bcd014c3c7927c21d2e1 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.py +++ b/erpnext/selling/doctype/selling_settings/selling_settings.py @@ -39,6 +39,7 @@ class SellingSettings(Document): enable_cutoff_date_on_bulk_delivery_note_creation: DF.Check enable_discount_accounting: DF.Check hide_tax_id: DF.Check + validate_project_in_so_si: DF.Check maintain_same_rate_action: DF.Literal["Stop", "Warn"] maintain_same_sales_rate: DF.Check role_to_override_stop_action: DF.Link | None