From cca5fbd81a77c6594ecb1b9cf6ef3a84b7580ee5 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Fri, 17 Jan 2025 11:41:52 +0530 Subject: [PATCH 1/6] feat: add company level validation for accounting dimension (cherry picked from commit 60efd3e2195a1e87cade172786ce38917fe9ab8f) # Conflicts: # erpnext/controllers/accounts_controller.py --- .../accounting_dimension.json | 3 +- erpnext/controllers/accounts_controller.py | 63 ++++++++++++++++++- 2 files changed, 64 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json index 5858f10bb0b..f05d20a0a49 100644 --- a/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json +++ b/erpnext/accounts/doctype/accounting_dimension/accounting_dimension.json @@ -31,7 +31,8 @@ "label": "Reference Document Type", "options": "DocType", "read_only_depends_on": "eval:!doc.__islocal", - "reqd": 1 + "reqd": 1, + "search_index": 1 }, { "default": "0", diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index ecbf1177ee4..65dfc380fd7 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -8,7 +8,7 @@ from collections import defaultdict import frappe from frappe import _, bold, qb, throw from frappe.model.workflow import get_workflow_name, is_transition_condition_satisfied -from frappe.query_builder import Criterion +from frappe.query_builder import Criterion, DocType from frappe.query_builder.custom import ConstantColumn from frappe.query_builder.functions import Abs, Sum from frappe.utils import ( @@ -250,6 +250,15 @@ class AccountsController(TransactionBase): apply_pricing_rule_on_transaction(self) self.set_total_in_words() +<<<<<<< HEAD +======= + self.set_default_letter_head() + self.validate_company_in_accounting_dimension() + + def set_default_letter_head(self): + if hasattr(self, "letter_head") and not self.letter_head: + self.letter_head = frappe.db.get_value("Company", self.company, "default_letter_head") +>>>>>>> 60efd3e219 (feat: add company level validation for accounting dimension) def init_internal_values(self): # init all the internal values as 0 on sa @@ -355,6 +364,58 @@ class AccountsController(TransactionBase): (sle.voucher_type == self.doctype) & (sle.voucher_no == self.name) ).run() +<<<<<<< HEAD +======= + def remove_serial_and_batch_bundle(self): + bundles = frappe.get_all( + "Serial and Batch Bundle", + filters={"voucher_type": self.doctype, "voucher_no": self.name, "docstatus": ("!=", 1)}, + ) + + for bundle in bundles: + frappe.delete_doc("Serial and Batch Bundle", bundle.name) + + batches = frappe.get_all( + "Batch", filters={"reference_doctype": self.doctype, "reference_name": self.name} + ) + for row in batches: + frappe.delete_doc("Batch", row.name) + + def validate_company_in_accounting_dimension(self): + doc_field = DocType("DocField") + accounting_dimension = DocType("Accounting Dimension") + query = ( + frappe.qb.from_(accounting_dimension) + .select(accounting_dimension.document_type) + .join(doc_field) + .on(doc_field.parent == accounting_dimension.document_type) + .where(doc_field.fieldname == "company") + ).run(as_list=True) + + dimension_list = sum(query, ["Project"]) + self.validate_company(dimension_list) + + if childs := self.get_all_children(): + for child in childs: + self.validate_company(dimension_list, child) + + def validate_company(self, dimension_list, child=None): + for dimension in dimension_list: + if not child: + dimension_value = self.get(frappe.scrub(dimension)) + else: + dimension_value = child.get(frappe.scrub(dimension)) + + if dimension_value: + company = frappe.get_cached_value(dimension, dimension_value, "company") + if company and company != self.company: + frappe.throw( + _("{0}: {1} does not belong to the Company: {2}").format( + dimension, frappe.bold(dimension_value), self.company + ) + ) + +>>>>>>> 60efd3e219 (feat: add company level validation for accounting dimension) def validate_return_against_account(self): if self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.is_return and self.return_against: cr_dr_account_field = "debit_to" if self.doctype == "Sales Invoice" else "credit_to" From 2fb1aaa5c33a1b395bd980138defe41b82a6d387 Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Fri, 17 Jan 2025 11:45:51 +0530 Subject: [PATCH 2/6] test: add new unit test for company validation in accounting dimension (cherry picked from commit c94091d68ffc1453b9042f6f2f675d81dcd76849) # Conflicts: # erpnext/controllers/tests/test_accounts_controller.py --- .../tests/test_accounts_controller.py | 260 +++++++++++++++++- 1 file changed, 245 insertions(+), 15 deletions(-) diff --git a/erpnext/controllers/tests/test_accounts_controller.py b/erpnext/controllers/tests/test_accounts_controller.py index a184009b1e1..4be13be81fe 100644 --- a/erpnext/controllers/tests/test_accounts_controller.py +++ b/erpnext/controllers/tests/test_accounts_controller.py @@ -14,6 +14,11 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_ent from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.party import get_party_account +<<<<<<< HEAD +======= +from erpnext.buying.doctype.purchase_order.test_purchase_order import prepare_data_for_internal_transfer +from erpnext.projects.doctype.project.test_project import make_project +>>>>>>> c94091d68f (test: add new unit test for company validation in accounting dimension) from erpnext.stock.doctype.item.test_item import create_item @@ -1344,32 +1349,32 @@ class TestAccountsController(FrappeTestCase): # Invoices si1 = self.create_sales_invoice(qty=1, rate=rate_in_account_currency, do_not_submit=True) - si1.department = "Management" + si1.department = "Management - _TC" si1.save().submit() si2 = self.create_sales_invoice(qty=1, rate=rate_in_account_currency, do_not_submit=True) - si2.department = "Operations" + si2.department = "Operations - _TC" si2.save().submit() # Payments cr_note1 = self.create_sales_invoice(qty=-1, conversion_rate=75, rate=1, do_not_save=True) - cr_note1.department = "Management" + cr_note1.department = "Management - _TC" cr_note1.is_return = 1 cr_note1.save().submit() cr_note2 = self.create_sales_invoice(qty=-1, conversion_rate=75, rate=1, do_not_save=True) - cr_note2.department = "Legal" + cr_note2.department = "Legal - _TC" cr_note2.is_return = 1 cr_note2.save().submit() pe1 = get_payment_entry(si1.doctype, si1.name) pe1.references = [] - pe1.department = "Research & Development" + pe1.department = "Research & Development - _TC" pe1.save().submit() pe2 = get_payment_entry(si1.doctype, si1.name) pe2.references = [] - pe2.department = "Management" + pe2.department = "Management - _TC" pe2.save().submit() je1 = self.create_journal_entry( @@ -1382,7 +1387,7 @@ class TestAccountsController(FrappeTestCase): ) je1.accounts[0].party_type = "Customer" je1.accounts[0].party = self.customer - je1.accounts[0].department = "Management" + je1.accounts[0].department = "Management - _TC" je1.save().submit() # assert dimension filter's result @@ -1391,17 +1396,17 @@ class TestAccountsController(FrappeTestCase): self.assertEqual(len(pr.invoices), 2) self.assertEqual(len(pr.payments), 5) - pr.department = "Legal" + pr.department = "Legal - _TC" pr.get_unreconciled_entries() self.assertEqual(len(pr.invoices), 0) self.assertEqual(len(pr.payments), 1) - pr.department = "Management" + pr.department = "Management - _TC" pr.get_unreconciled_entries() self.assertEqual(len(pr.invoices), 1) self.assertEqual(len(pr.payments), 3) - pr.department = "Research & Development" + pr.department = "Research & Development - _TC" pr.get_unreconciled_entries() self.assertEqual(len(pr.invoices), 0) self.assertEqual(len(pr.payments), 1) @@ -1413,17 +1418,17 @@ class TestAccountsController(FrappeTestCase): # Invoice si = self.create_sales_invoice(qty=1, rate=rate_in_account_currency, do_not_submit=True) - si.department = "Management" + si.department = "Management - _TC" si.save().submit() # Payment cr_note = self.create_sales_invoice(qty=-1, conversion_rate=75, rate=1, do_not_save=True) - cr_note.department = "Management" + cr_note.department = "Management - _TC" cr_note.is_return = 1 cr_note.save().submit() pr = self.create_payment_reconciliation() - pr.department = "Management" + pr.department = "Management - _TC" pr.get_unreconciled_entries() self.assertEqual(len(pr.invoices), 1) self.assertEqual(len(pr.payments), 1) @@ -1456,7 +1461,7 @@ class TestAccountsController(FrappeTestCase): # Sales Invoice in Foreign Currency self.setup_dimensions() rate_in_account_currency = 1 - dpt = "Research & Development" + dpt = "Research & Development - _TC" si = self.create_sales_invoice(qty=1, rate=rate_in_account_currency, do_not_save=True) si.department = dpt @@ -1492,7 +1497,7 @@ class TestAccountsController(FrappeTestCase): def test_93_dimension_inheritance_on_advance(self): self.setup_dimensions() - dpt = "Research & Development" + dpt = "Research & Development - _TC" adv = self.create_payment_entry(amount=1, source_exc_rate=85) adv.department = dpt @@ -1739,3 +1744,228 @@ class TestAccountsController(FrappeTestCase): # Exchange Gain/Loss Journal should've been cancelled exc_je_for_je1 = self.get_journals_for(je1.doctype, je1.name) self.assertEqual(exc_je_for_je1, []) +<<<<<<< HEAD +======= + + def test_70_advance_payment_against_sales_invoice_in_foreign_currency(self): + """ + Customer advance booked under Liability + """ + self.setup_advance_accounts_in_party_master() + + adv = self.create_payment_entry(amount=1, source_exc_rate=83) + adv.save() # explicit 'save' is needed to trigger set_liability_account() + self.assertEqual(adv.paid_from, self.advance_received_usd) + adv.submit() + + si = self.create_sales_invoice(qty=1, conversion_rate=80, rate=1, do_not_submit=True) + si.debit_to = self.debtors_usd + si.save().submit() + self.assert_ledger_outstanding(si.doctype, si.name, 80.0, 1.0) + + pr = self.create_payment_reconciliation() + pr.receivable_payable_account = self.debtors_usd + pr.default_advance_account = self.advance_received_usd + pr.get_unreconciled_entries() + self.assertEqual(pr.invoices[0].invoice_number, si.name) + self.assertEqual(pr.payments[0].reference_name, adv.name) + + # Allocate and Reconcile + invoices = [x.as_dict() for x in pr.invoices] + payments = [x.as_dict() for x in pr.payments] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.reconcile() + self.assertEqual(len(pr.invoices), 0) + self.assertEqual(len(pr.payments), 0) + self.assert_ledger_outstanding(si.doctype, si.name, 0.0, 0.0) + + # Exc Gain/Loss journal should've been creatad + exc_je_for_si = self.get_journals_for(si.doctype, si.name) + exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) + self.assertEqual(len(exc_je_for_si), 1) + self.assertEqual(len(exc_je_for_adv), 1) + self.assertEqual(exc_je_for_si, exc_je_for_adv) + + adv.reload() + adv.cancel() + si.reload() + self.assert_ledger_outstanding(si.doctype, si.name, 80.0, 1.0) + # Exc Gain/Loss journal should've been cancelled + exc_je_for_si = self.get_journals_for(si.doctype, si.name) + exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) + self.assertEqual(len(exc_je_for_si), 0) + self.assertEqual(len(exc_je_for_adv), 0) + + self.remove_advance_accounts_from_party_master() + + def test_71_advance_payment_against_purchase_invoice_in_foreign_currency(self): + """ + Supplier advance booked under Asset + """ + self.setup_advance_accounts_in_party_master() + + usd_amount = 1 + inr_amount = 85 + exc_rate = 85 + adv = create_payment_entry( + company=self.company, + payment_type="Pay", + party_type="Supplier", + party=self.supplier, + paid_from=self.cash, + paid_to=self.advance_paid_usd, + paid_amount=inr_amount, + ) + adv.source_exchange_rate = 1 + adv.target_exchange_rate = exc_rate + adv.received_amount = usd_amount + adv.paid_amount = exc_rate * usd_amount + adv.posting_date = nowdate() + adv.save() + # Make sure that advance account is still set + self.assertEqual(adv.paid_to, self.advance_paid_usd) + adv.submit() + + pi = self.create_purchase_invoice(qty=1, conversion_rate=83, rate=1) + self.assertEqual(pi.credit_to, self.creditors_usd) + self.assert_ledger_outstanding(pi.doctype, pi.name, 83.0, 1.0) + + pr = self.create_payment_reconciliation() + pr.party_type = "Supplier" + pr.party = self.supplier + pr.receivable_payable_account = self.creditors_usd + pr.default_advance_account = self.advance_paid_usd + pr.get_unreconciled_entries() + self.assertEqual(pr.invoices[0].invoice_number, pi.name) + self.assertEqual(pr.payments[0].reference_name, adv.name) + + # Allocate and Reconcile + invoices = [x.as_dict() for x in pr.invoices] + payments = [x.as_dict() for x in pr.payments] + pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) + pr.reconcile() + self.assertEqual(len(pr.invoices), 0) + self.assertEqual(len(pr.payments), 0) + self.assert_ledger_outstanding(pi.doctype, pi.name, 0.0, 0.0) + + # Exc Gain/Loss journal should've been creatad + exc_je_for_pi = self.get_journals_for(pi.doctype, pi.name) + exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) + self.assertEqual(len(exc_je_for_pi), 1) + self.assertEqual(len(exc_je_for_adv), 1) + self.assertEqual(exc_je_for_pi, exc_je_for_adv) + + adv.reload() + adv.cancel() + pi.reload() + self.assert_ledger_outstanding(pi.doctype, pi.name, 83.0, 1.0) + # Exc Gain/Loss journal should've been cancelled + exc_je_for_pi = self.get_journals_for(pi.doctype, pi.name) + exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) + self.assertEqual(len(exc_je_for_pi), 0) + self.assertEqual(len(exc_je_for_adv), 0) + + self.remove_advance_accounts_from_party_master() + + def test_difference_posting_date_in_pi_and_si(self): + self.setup_advance_accounts_in_party_master() + + # create payment entry for customer + adv = self.create_payment_entry(amount=1, source_exc_rate=83) + adv.save() + self.assertEqual(adv.paid_from, self.advance_received_usd) + adv.submit() + adv.reload() + + # create sales invoice with advance received + si = self.create_sales_invoice(qty=1, conversion_rate=80, rate=1, do_not_submit=True) + si.debit_to = self.debtors_usd + si.append( + "advances", + { + "reference_type": adv.doctype, + "reference_name": adv.name, + "remarks": "Amount INR 1 received from _Test MC Customer USD\nTransaction reference no Test001 dated 2024-12-19", + "advance_amount": 1.0, + "allocated_amount": 1.0, + "exchange_gain_loss": 3.0, + "ref_exchange_rate": 83.0, + "difference_posting_date": add_days(nowdate(), -2), + }, + ) + si.save().submit() + + # exc Gain/Loss journal should've been creatad + exc_je_for_si = self.get_journals_for(si.doctype, si.name) + exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) + self.assertEqual(len(exc_je_for_si), 1) + self.assertEqual(len(exc_je_for_adv), 1) + self.assertEqual(exc_je_for_si, exc_je_for_adv) + + # check jv created with difference_posting_date in sales invoice + jv = frappe.get_doc("Journal Entry", exc_je_for_si[0].parent) + sales_invoice = frappe.get_doc("Sales Invoice", si.name) + self.assertEqual(sales_invoice.advances[0].difference_posting_date, jv.posting_date) + + # create payment entry for supplier + usd_amount = 1 + inr_amount = 85 + exc_rate = 85 + adv = create_payment_entry( + company=self.company, + payment_type="Pay", + party_type="Supplier", + party=self.supplier, + paid_from=self.cash, + paid_to=self.advance_paid_usd, + paid_amount=inr_amount, + ) + adv.source_exchange_rate = 1 + adv.target_exchange_rate = exc_rate + adv.received_amount = usd_amount + adv.paid_amount = exc_rate * usd_amount + adv.posting_date = nowdate() + adv.save() + self.assertEqual(adv.paid_to, self.advance_paid_usd) + adv.submit() + + # create purchase invoice with advance paid + pi = self.create_purchase_invoice(qty=1, conversion_rate=80, rate=1, do_not_submit=True) + pi.append( + "advances", + { + "reference_type": adv.doctype, + "reference_name": adv.name, + "remarks": "Amount INR 1 paid to _Test MC Supplier USD\nTransaction reference no Test001 dated 2024-12-20", + "advance_amount": 1.0, + "allocated_amount": 1.0, + "exchange_gain_loss": 5.0, + "ref_exchange_rate": 85.0, + "difference_posting_date": add_days(nowdate(), -2), + }, + ) + pi.save().submit() + self.assertEqual(pi.credit_to, self.creditors_usd) + + # exc Gain/Loss journal should've been creatad + exc_je_for_pi = self.get_journals_for(pi.doctype, pi.name) + exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) + self.assertEqual(len(exc_je_for_pi), 1) + self.assertEqual(len(exc_je_for_adv), 1) + self.assertEqual(exc_je_for_pi, exc_je_for_adv) + + # check jv created with difference_posting_date in purchase invoice + journal_voucher = frappe.get_doc("Journal Entry", exc_je_for_pi[0].parent) + purchase_invoice = frappe.get_doc("Purchase Invoice", pi.name) + self.assertEqual(purchase_invoice.advances[0].difference_posting_date, journal_voucher.posting_date) + + def test_company_validation_in_dimension(self): + si = create_sales_invoice(do_not_submit=True) + project = make_project({"project_name": "_Test Demo Project1", "company": "_Test Company 1"}) + si.project = project.name + self.assertRaises(frappe.ValidationError, si.save) + + si_1 = create_sales_invoice(do_not_submit=True) + si_1.items[0].project = project.name + self.assertRaises(frappe.ValidationError, si_1.save) +>>>>>>> c94091d68f (test: add new unit test for company validation in accounting dimension) From 03068ab96c94dae49d592af65ff08afaaa22af3c Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Fri, 17 Jan 2025 11:46:17 +0530 Subject: [PATCH 3/6] fix: set company related values (cherry picked from commit 454067198ee8a8f649cc9db7109032587c43a098) --- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py index b7546a9ce33..a407f90b51f 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -3860,6 +3860,7 @@ class TestSalesInvoice(FrappeTestCase): si = create_sales_invoice(do_not_submit=True) project = frappe.new_doc("Project") + project.company = "_Test Company" project.project_name = "Test Total Billed Amount" project.save() From 9767dc61a620f7a3d2bf97d8d10f9efa652400fb Mon Sep 17 00:00:00 2001 From: Sugesh393 Date: Tue, 21 Jan 2025 17:38:24 +0530 Subject: [PATCH 4/6] chore: update variable names for improved readability (cherry picked from commit 36bae552992f4d9009e96397db052e6e85cc2775) --- erpnext/controllers/accounts_controller.py | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 65dfc380fd7..055dc5aae8f 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -384,7 +384,7 @@ class AccountsController(TransactionBase): def validate_company_in_accounting_dimension(self): doc_field = DocType("DocField") accounting_dimension = DocType("Accounting Dimension") - query = ( + dimension_list = ( frappe.qb.from_(accounting_dimension) .select(accounting_dimension.document_type) .join(doc_field) @@ -392,12 +392,11 @@ class AccountsController(TransactionBase): .where(doc_field.fieldname == "company") ).run(as_list=True) - dimension_list = sum(query, ["Project"]) + dimension_list = sum(dimension_list, ["Project"]) self.validate_company(dimension_list) - if childs := self.get_all_children(): - for child in childs: - self.validate_company(dimension_list, child) + for child in self.get_all_children() or []: + self.validate_company(dimension_list, child) def validate_company(self, dimension_list, child=None): for dimension in dimension_list: From b8e4d80b4e1c1ab2dcc727deb57a6023330e855c Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 27 Jan 2025 15:48:28 +0530 Subject: [PATCH 5/6] chore: resolve conflicts --- erpnext/controllers/accounts_controller.py | 26 -- .../tests/test_accounts_controller.py | 230 ------------------ 2 files changed, 256 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 055dc5aae8f..160c478f299 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -250,16 +250,8 @@ class AccountsController(TransactionBase): apply_pricing_rule_on_transaction(self) self.set_total_in_words() -<<<<<<< HEAD -======= - self.set_default_letter_head() self.validate_company_in_accounting_dimension() - def set_default_letter_head(self): - if hasattr(self, "letter_head") and not self.letter_head: - self.letter_head = frappe.db.get_value("Company", self.company, "default_letter_head") ->>>>>>> 60efd3e219 (feat: add company level validation for accounting dimension) - def init_internal_values(self): # init all the internal values as 0 on sa if self.docstatus.is_draft(): @@ -364,23 +356,6 @@ class AccountsController(TransactionBase): (sle.voucher_type == self.doctype) & (sle.voucher_no == self.name) ).run() -<<<<<<< HEAD -======= - def remove_serial_and_batch_bundle(self): - bundles = frappe.get_all( - "Serial and Batch Bundle", - filters={"voucher_type": self.doctype, "voucher_no": self.name, "docstatus": ("!=", 1)}, - ) - - for bundle in bundles: - frappe.delete_doc("Serial and Batch Bundle", bundle.name) - - batches = frappe.get_all( - "Batch", filters={"reference_doctype": self.doctype, "reference_name": self.name} - ) - for row in batches: - frappe.delete_doc("Batch", row.name) - def validate_company_in_accounting_dimension(self): doc_field = DocType("DocField") accounting_dimension = DocType("Accounting Dimension") @@ -414,7 +389,6 @@ class AccountsController(TransactionBase): ) ) ->>>>>>> 60efd3e219 (feat: add company level validation for accounting dimension) def validate_return_against_account(self): if self.doctype in ["Sales Invoice", "Purchase Invoice"] and self.is_return and self.return_against: cr_dr_account_field = "debit_to" if self.doctype == "Sales Invoice" else "credit_to" diff --git a/erpnext/controllers/tests/test_accounts_controller.py b/erpnext/controllers/tests/test_accounts_controller.py index 4be13be81fe..1e0f4cce27b 100644 --- a/erpnext/controllers/tests/test_accounts_controller.py +++ b/erpnext/controllers/tests/test_accounts_controller.py @@ -14,11 +14,6 @@ from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_ent from erpnext.accounts.doctype.payment_entry.test_payment_entry import create_payment_entry from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice from erpnext.accounts.party import get_party_account -<<<<<<< HEAD -======= -from erpnext.buying.doctype.purchase_order.test_purchase_order import prepare_data_for_internal_transfer -from erpnext.projects.doctype.project.test_project import make_project ->>>>>>> c94091d68f (test: add new unit test for company validation in accounting dimension) from erpnext.stock.doctype.item.test_item import create_item @@ -1744,228 +1739,3 @@ class TestAccountsController(FrappeTestCase): # Exchange Gain/Loss Journal should've been cancelled exc_je_for_je1 = self.get_journals_for(je1.doctype, je1.name) self.assertEqual(exc_je_for_je1, []) -<<<<<<< HEAD -======= - - def test_70_advance_payment_against_sales_invoice_in_foreign_currency(self): - """ - Customer advance booked under Liability - """ - self.setup_advance_accounts_in_party_master() - - adv = self.create_payment_entry(amount=1, source_exc_rate=83) - adv.save() # explicit 'save' is needed to trigger set_liability_account() - self.assertEqual(adv.paid_from, self.advance_received_usd) - adv.submit() - - si = self.create_sales_invoice(qty=1, conversion_rate=80, rate=1, do_not_submit=True) - si.debit_to = self.debtors_usd - si.save().submit() - self.assert_ledger_outstanding(si.doctype, si.name, 80.0, 1.0) - - pr = self.create_payment_reconciliation() - pr.receivable_payable_account = self.debtors_usd - pr.default_advance_account = self.advance_received_usd - pr.get_unreconciled_entries() - self.assertEqual(pr.invoices[0].invoice_number, si.name) - self.assertEqual(pr.payments[0].reference_name, adv.name) - - # Allocate and Reconcile - invoices = [x.as_dict() for x in pr.invoices] - payments = [x.as_dict() for x in pr.payments] - pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) - pr.reconcile() - self.assertEqual(len(pr.invoices), 0) - self.assertEqual(len(pr.payments), 0) - self.assert_ledger_outstanding(si.doctype, si.name, 0.0, 0.0) - - # Exc Gain/Loss journal should've been creatad - exc_je_for_si = self.get_journals_for(si.doctype, si.name) - exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) - self.assertEqual(len(exc_je_for_si), 1) - self.assertEqual(len(exc_je_for_adv), 1) - self.assertEqual(exc_je_for_si, exc_je_for_adv) - - adv.reload() - adv.cancel() - si.reload() - self.assert_ledger_outstanding(si.doctype, si.name, 80.0, 1.0) - # Exc Gain/Loss journal should've been cancelled - exc_je_for_si = self.get_journals_for(si.doctype, si.name) - exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) - self.assertEqual(len(exc_je_for_si), 0) - self.assertEqual(len(exc_je_for_adv), 0) - - self.remove_advance_accounts_from_party_master() - - def test_71_advance_payment_against_purchase_invoice_in_foreign_currency(self): - """ - Supplier advance booked under Asset - """ - self.setup_advance_accounts_in_party_master() - - usd_amount = 1 - inr_amount = 85 - exc_rate = 85 - adv = create_payment_entry( - company=self.company, - payment_type="Pay", - party_type="Supplier", - party=self.supplier, - paid_from=self.cash, - paid_to=self.advance_paid_usd, - paid_amount=inr_amount, - ) - adv.source_exchange_rate = 1 - adv.target_exchange_rate = exc_rate - adv.received_amount = usd_amount - adv.paid_amount = exc_rate * usd_amount - adv.posting_date = nowdate() - adv.save() - # Make sure that advance account is still set - self.assertEqual(adv.paid_to, self.advance_paid_usd) - adv.submit() - - pi = self.create_purchase_invoice(qty=1, conversion_rate=83, rate=1) - self.assertEqual(pi.credit_to, self.creditors_usd) - self.assert_ledger_outstanding(pi.doctype, pi.name, 83.0, 1.0) - - pr = self.create_payment_reconciliation() - pr.party_type = "Supplier" - pr.party = self.supplier - pr.receivable_payable_account = self.creditors_usd - pr.default_advance_account = self.advance_paid_usd - pr.get_unreconciled_entries() - self.assertEqual(pr.invoices[0].invoice_number, pi.name) - self.assertEqual(pr.payments[0].reference_name, adv.name) - - # Allocate and Reconcile - invoices = [x.as_dict() for x in pr.invoices] - payments = [x.as_dict() for x in pr.payments] - pr.allocate_entries(frappe._dict({"invoices": invoices, "payments": payments})) - pr.reconcile() - self.assertEqual(len(pr.invoices), 0) - self.assertEqual(len(pr.payments), 0) - self.assert_ledger_outstanding(pi.doctype, pi.name, 0.0, 0.0) - - # Exc Gain/Loss journal should've been creatad - exc_je_for_pi = self.get_journals_for(pi.doctype, pi.name) - exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) - self.assertEqual(len(exc_je_for_pi), 1) - self.assertEqual(len(exc_je_for_adv), 1) - self.assertEqual(exc_je_for_pi, exc_je_for_adv) - - adv.reload() - adv.cancel() - pi.reload() - self.assert_ledger_outstanding(pi.doctype, pi.name, 83.0, 1.0) - # Exc Gain/Loss journal should've been cancelled - exc_je_for_pi = self.get_journals_for(pi.doctype, pi.name) - exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) - self.assertEqual(len(exc_je_for_pi), 0) - self.assertEqual(len(exc_je_for_adv), 0) - - self.remove_advance_accounts_from_party_master() - - def test_difference_posting_date_in_pi_and_si(self): - self.setup_advance_accounts_in_party_master() - - # create payment entry for customer - adv = self.create_payment_entry(amount=1, source_exc_rate=83) - adv.save() - self.assertEqual(adv.paid_from, self.advance_received_usd) - adv.submit() - adv.reload() - - # create sales invoice with advance received - si = self.create_sales_invoice(qty=1, conversion_rate=80, rate=1, do_not_submit=True) - si.debit_to = self.debtors_usd - si.append( - "advances", - { - "reference_type": adv.doctype, - "reference_name": adv.name, - "remarks": "Amount INR 1 received from _Test MC Customer USD\nTransaction reference no Test001 dated 2024-12-19", - "advance_amount": 1.0, - "allocated_amount": 1.0, - "exchange_gain_loss": 3.0, - "ref_exchange_rate": 83.0, - "difference_posting_date": add_days(nowdate(), -2), - }, - ) - si.save().submit() - - # exc Gain/Loss journal should've been creatad - exc_je_for_si = self.get_journals_for(si.doctype, si.name) - exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) - self.assertEqual(len(exc_je_for_si), 1) - self.assertEqual(len(exc_je_for_adv), 1) - self.assertEqual(exc_je_for_si, exc_je_for_adv) - - # check jv created with difference_posting_date in sales invoice - jv = frappe.get_doc("Journal Entry", exc_je_for_si[0].parent) - sales_invoice = frappe.get_doc("Sales Invoice", si.name) - self.assertEqual(sales_invoice.advances[0].difference_posting_date, jv.posting_date) - - # create payment entry for supplier - usd_amount = 1 - inr_amount = 85 - exc_rate = 85 - adv = create_payment_entry( - company=self.company, - payment_type="Pay", - party_type="Supplier", - party=self.supplier, - paid_from=self.cash, - paid_to=self.advance_paid_usd, - paid_amount=inr_amount, - ) - adv.source_exchange_rate = 1 - adv.target_exchange_rate = exc_rate - adv.received_amount = usd_amount - adv.paid_amount = exc_rate * usd_amount - adv.posting_date = nowdate() - adv.save() - self.assertEqual(adv.paid_to, self.advance_paid_usd) - adv.submit() - - # create purchase invoice with advance paid - pi = self.create_purchase_invoice(qty=1, conversion_rate=80, rate=1, do_not_submit=True) - pi.append( - "advances", - { - "reference_type": adv.doctype, - "reference_name": adv.name, - "remarks": "Amount INR 1 paid to _Test MC Supplier USD\nTransaction reference no Test001 dated 2024-12-20", - "advance_amount": 1.0, - "allocated_amount": 1.0, - "exchange_gain_loss": 5.0, - "ref_exchange_rate": 85.0, - "difference_posting_date": add_days(nowdate(), -2), - }, - ) - pi.save().submit() - self.assertEqual(pi.credit_to, self.creditors_usd) - - # exc Gain/Loss journal should've been creatad - exc_je_for_pi = self.get_journals_for(pi.doctype, pi.name) - exc_je_for_adv = self.get_journals_for(adv.doctype, adv.name) - self.assertEqual(len(exc_je_for_pi), 1) - self.assertEqual(len(exc_je_for_adv), 1) - self.assertEqual(exc_je_for_pi, exc_je_for_adv) - - # check jv created with difference_posting_date in purchase invoice - journal_voucher = frappe.get_doc("Journal Entry", exc_je_for_pi[0].parent) - purchase_invoice = frappe.get_doc("Purchase Invoice", pi.name) - self.assertEqual(purchase_invoice.advances[0].difference_posting_date, journal_voucher.posting_date) - - def test_company_validation_in_dimension(self): - si = create_sales_invoice(do_not_submit=True) - project = make_project({"project_name": "_Test Demo Project1", "company": "_Test Company 1"}) - si.project = project.name - self.assertRaises(frappe.ValidationError, si.save) - - si_1 = create_sales_invoice(do_not_submit=True) - si_1.items[0].project = project.name - self.assertRaises(frappe.ValidationError, si_1.save) ->>>>>>> c94091d68f (test: add new unit test for company validation in accounting dimension) From befc16cc971b6ecceb20e53e21b60143a8194369 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Mon, 27 Jan 2025 16:11:53 +0530 Subject: [PATCH 6/6] refactor(test): update test data --- erpnext/projects/doctype/project/test_records.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/projects/doctype/project/test_records.json b/erpnext/projects/doctype/project/test_records.json index 567f359b50d..1482336631b 100644 --- a/erpnext/projects/doctype/project/test_records.json +++ b/erpnext/projects/doctype/project/test_records.json @@ -1,6 +1,7 @@ [ { "project_name": "_Test Project", - "status": "Open" + "status": "Open", + "company": "_Test Company" } ] \ No newline at end of file