diff --git a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json index 4db531eac90..4d0579ebc7e 100644 --- a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json +++ b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.json @@ -14,7 +14,8 @@ "advance_amount", "allocated_amount", "exchange_gain_loss", - "ref_exchange_rate" + "ref_exchange_rate", + "difference_posting_date" ], "fields": [ { @@ -30,7 +31,7 @@ "width": "180px" }, { - "columns": 3, + "columns": 2, "fieldname": "reference_name", "fieldtype": "Dynamic Link", "in_list_view": 1, @@ -40,7 +41,7 @@ "read_only": 1 }, { - "columns": 3, + "columns": 2, "fieldname": "remarks", "fieldtype": "Text", "in_list_view": 1, @@ -111,13 +112,20 @@ "label": "Reference Exchange Rate", "non_negative": 1, "read_only": 1 + }, + { + "columns": 2, + "fieldname": "difference_posting_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Difference Posting Date" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2023-06-23 21:13:18.013816", + "modified": "2024-12-20 12:04:46.729972", "modified_by": "Administrator", "module": "Accounts", "name": "Purchase Invoice Advance", diff --git a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py index bbd3009224a..a3fabbdc322 100644 --- a/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py +++ b/erpnext/accounts/doctype/purchase_invoice_advance/purchase_invoice_advance.py @@ -16,6 +16,7 @@ class PurchaseInvoiceAdvance(Document): advance_amount: DF.Currency allocated_amount: DF.Currency + difference_posting_date: DF.Date | None exchange_gain_loss: DF.Currency parent: DF.Data parentfield: DF.Data diff --git a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json index 0ae85d90004..1246d04d3d6 100644 --- a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json +++ b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.json @@ -14,7 +14,8 @@ "advance_amount", "allocated_amount", "exchange_gain_loss", - "ref_exchange_rate" + "ref_exchange_rate", + "difference_posting_date" ], "fields": [ { @@ -30,7 +31,7 @@ "width": "250px" }, { - "columns": 3, + "columns": 2, "fieldname": "reference_name", "fieldtype": "Dynamic Link", "in_list_view": 1, @@ -41,7 +42,7 @@ "read_only": 1 }, { - "columns": 3, + "columns": 2, "fieldname": "remarks", "fieldtype": "Text", "in_list_view": 1, @@ -112,13 +113,20 @@ "label": "Reference Exchange Rate", "non_negative": 1, "read_only": 1 + }, + { + "columns": 2, + "fieldname": "difference_posting_date", + "fieldtype": "Date", + "in_list_view": 1, + "label": "Difference Posting Date" } ], "idx": 1, "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2023-06-23 21:12:57.557731", + "modified": "2024-12-20 11:58:28.962370", "modified_by": "Administrator", "module": "Accounts", "name": "Sales Invoice Advance", diff --git a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py index 5eeedb25f29..1d115c5c507 100644 --- a/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py +++ b/erpnext/accounts/doctype/sales_invoice_advance/sales_invoice_advance.py @@ -16,6 +16,7 @@ class SalesInvoiceAdvance(Document): advance_amount: DF.Currency allocated_amount: DF.Currency + difference_posting_date: DF.Date | None exchange_gain_loss: DF.Currency parent: DF.Data parentfield: DF.Data diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 6932a4b47d9..20b5885bfdc 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -379,13 +379,14 @@ class AccountsController(TransactionBase): == 1 ) ).run() - frappe.db.sql( - "delete from `tabGL Entry` where voucher_type=%s and voucher_no=%s", (self.doctype, self.name) - ) - frappe.db.sql( - "delete from `tabStock Ledger Entry` where voucher_type=%s and voucher_no=%s", - (self.doctype, self.name), - ) + gle = frappe.qb.DocType("GL Entry") + frappe.qb.from_(gle).delete().where( + (gle.voucher_type == self.doctype) & (gle.voucher_no == self.name) + ).run() + sle = frappe.qb.DocType("Stock Ledger Entry") + frappe.qb.from_(sle).delete().where( + (sle.voucher_type == self.doctype) & (sle.voucher_no == self.name) + ).run() def remove_serial_and_batch_bundle(self): bundles = frappe.get_all( @@ -1150,11 +1151,12 @@ class AccountsController(TransactionBase): def clear_unallocated_advances(self, childtype, parentfield): self.set(parentfield, self.get(parentfield, {"allocated_amount": ["not in", [0, None, ""]]})) - frappe.db.sql( - """delete from `tab{}` where parentfield={} and parent = {} - and allocated_amount = 0""".format(childtype, "%s", "%s"), - (parentfield, self.name), - ) + doctype = frappe.qb.DocType(childtype) + frappe.qb.from_(doctype).delete().where( + (doctype.parentfield == parentfield) + & (doctype.parent == self.name) + & (doctype.allocated_amount == 0) + ).run() @frappe.whitelist() def apply_shipping_rule(self): @@ -1204,6 +1206,7 @@ class AccountsController(TransactionBase): "advance_amount": flt(d.amount), "allocated_amount": allocated_amount, "ref_exchange_rate": flt(d.exchange_rate), # exchange_rate of advance entry + "difference_posting_date": self.posting_date, } if d.get("paid_from"): advance_row["account"] = d.paid_from @@ -1509,7 +1512,6 @@ class AccountsController(TransactionBase): gain_loss_account = frappe.get_cached_value( "Company", self.company, "exchange_gain_loss_account" ) - je = create_gain_loss_journal( self.company, args.get("difference_posting_date") if args else self.posting_date, @@ -1595,6 +1597,7 @@ class AccountsController(TransactionBase): "Company", self.company, "exchange_gain_loss_account" ), "exchange_gain_loss": flt(d.get("exchange_gain_loss")), + "difference_posting_date": d.get("difference_posting_date"), } ) lst.append(args) @@ -2128,11 +2131,9 @@ class AccountsController(TransactionBase): for adv in self.advances: consider_for_total_advance = True if adv.reference_name == linked_doc_name: - frappe.db.sql( - f"""delete from `tab{self.doctype} Advance` - where name = %s""", - adv.name, - ) + doctype = frappe.qb.DocType(self.doctype + " Advance") + frappe.qb.from_(doctype).delete().where(doctype.name == adv.name).run() + consider_for_total_advance = False if consider_for_total_advance: diff --git a/erpnext/controllers/tests/test_accounts_controller.py b/erpnext/controllers/tests/test_accounts_controller.py index 289a955f980..e557a6b2d79 100644 --- a/erpnext/controllers/tests/test_accounts_controller.py +++ b/erpnext/controllers/tests/test_accounts_controller.py @@ -2,6 +2,8 @@ # For license information, please see license.txt +from datetime import datetime + import frappe from frappe import qb from frappe.query_builder.functions import Sum @@ -1979,3 +1981,95 @@ class TestAccountsController(FrappeTestCase): 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)