From 06e8e28531e2584fd5499df1c233082657de12b0 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 31 Oct 2022 19:58:46 +0530 Subject: [PATCH 01/10] fix: Mode of payment for returns in POS Sales Invoice --- erpnext/controllers/taxes_and_totals.py | 41 +++++++++++++++---------- 1 file changed, 25 insertions(+), 16 deletions(-) diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py index cbcccce5f7..b5836c9070 100644 --- a/erpnext/controllers/taxes_and_totals.py +++ b/erpnext/controllers/taxes_and_totals.py @@ -889,24 +889,33 @@ class calculate_taxes_and_totals(object): self.doc.other_charges_calculation = get_itemised_tax_breakup_html(self.doc) def set_total_amount_to_default_mop(self, total_amount_to_pay): - default_mode_of_payment = frappe.db.get_value( - "POS Payment Method", - {"parent": self.doc.pos_profile, "default": 1}, - ["mode_of_payment"], - as_dict=1, - ) - - if default_mode_of_payment: - self.doc.payments = [] - self.doc.append( - "payments", - { - "mode_of_payment": default_mode_of_payment.mode_of_payment, - "amount": total_amount_to_pay, - "default": 1, - }, + total_paid_amount = 0 + for payment in self.doc.get("payments"): + total_paid_amount += ( + payment.amount if self.doc.party_account_currency == self.doc.currency else payment.base_amount ) + pending_amount = total_amount_to_pay - total_paid_amount + + if pending_amount > 0: + default_mode_of_payment = frappe.db.get_value( + "POS Payment Method", + {"parent": self.doc.pos_profile, "default": 1}, + ["mode_of_payment"], + as_dict=1, + ) + + if default_mode_of_payment: + self.doc.payments = [] + self.doc.append( + "payments", + { + "mode_of_payment": default_mode_of_payment.mode_of_payment, + "amount": pending_amount, + "default": 1, + }, + ) + def get_itemised_tax_breakup_html(doc): if not doc.taxes: From 4487065b6716ad3d48982df2d4642aa3b8447a80 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Tue, 1 Nov 2022 10:11:38 +0530 Subject: [PATCH 02/10] fix: update advance paid in SO/PO from Payment Ledger --- erpnext/controllers/accounts_controller.py | 40 ++++++++-------------- 1 file changed, 15 insertions(+), 25 deletions(-) diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py index 22291a3544..7f5dc0262d 100644 --- a/erpnext/controllers/accounts_controller.py +++ b/erpnext/controllers/accounts_controller.py @@ -7,7 +7,7 @@ import json import frappe from frappe import _, throw from frappe.model.workflow import get_workflow_name, is_transition_condition_satisfied -from frappe.query_builder.functions import Sum +from frappe.query_builder.functions import Abs, Sum from frappe.utils import ( add_days, add_months, @@ -1334,30 +1334,20 @@ class AccountsController(TransactionBase): return stock_items def set_total_advance_paid(self): - if self.doctype == "Sales Order": - dr_or_cr = "credit_in_account_currency" - rev_dr_or_cr = "debit_in_account_currency" - party = self.customer - else: - dr_or_cr = "debit_in_account_currency" - rev_dr_or_cr = "credit_in_account_currency" - party = self.supplier - - advance = frappe.db.sql( - """ - select - account_currency, sum({dr_or_cr}) - sum({rev_dr_cr}) as amount - from - `tabGL Entry` - where - against_voucher_type = %s and against_voucher = %s and party=%s - and docstatus = 1 - """.format( - dr_or_cr=dr_or_cr, rev_dr_cr=rev_dr_or_cr - ), - (self.doctype, self.name, party), - as_dict=1, - ) # nosec + ple = frappe.qb.DocType("Payment Ledger Entry") + party = self.customer if self.doctype == "Sales Order" else self.supplier + advance = ( + frappe.qb.from_(ple) + .select(ple.account_currency, Abs(Sum(ple.amount)).as_("amount")) + .where( + (ple.against_voucher_type == self.doctype) + & (ple.against_voucher_no == self.name) + & (ple.party == party) + & (ple.delinked == 0) + & (ple.company == self.company) + ) + .run(as_dict=True) + ) if advance: advance = advance[0] From 9fb3fb4c836aef1d05e9a8160baf7089cd3bb224 Mon Sep 17 00:00:00 2001 From: Sagar Sharma Date: Tue, 1 Nov 2022 10:38:33 +0530 Subject: [PATCH 03/10] fix: use `flt` instead of `cint` in `get_batch_no` --- erpnext/stock/doctype/batch/batch.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py index 52854a0f01..f14288beb2 100644 --- a/erpnext/stock/doctype/batch/batch.py +++ b/erpnext/stock/doctype/batch/batch.py @@ -291,7 +291,7 @@ def get_batch_no(item_code, warehouse, qty=1, throw=False, serial_no=None): batches = get_batches(item_code, warehouse, qty, throw, serial_no) for batch in batches: - if cint(qty) <= cint(batch.qty): + if flt(qty) <= flt(batch.qty): batch_no = batch.batch_id break From ddd1b4be3ff1daea9e9abc922c62c4abea5be951 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 1 Nov 2022 19:30:37 +0530 Subject: [PATCH 04/10] fix: test cases --- erpnext/stock/doctype/material_request/test_material_request.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 78af1532ea..005480e399 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -591,6 +591,7 @@ class TestMaterialRequest(FrappeTestCase): mr.material_request_type = "Material Issue" mr.submit() + self.assertTrue(frappe.db.exists("Material Request", mr.name)) # testing bin value after material request is submitted self.assertEqual(_get_requested_qty(), existing_requested_qty - 54.0) From f7c9258770a79aff0b951dc18c0b7c39f794b03f Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 1 Nov 2022 19:54:41 +0530 Subject: [PATCH 05/10] fix: Issues while cancel/amending Purchase Invoice with TDS enabled --- .../accounts/doctype/purchase_invoice/purchase_invoice.js | 4 ++++ .../accounts/doctype/purchase_invoice/purchase_invoice.py | 5 ++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js index c3a9855ff4..39a623519a 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js @@ -569,6 +569,10 @@ frappe.ui.form.on("Purchase Invoice", { erpnext.queries.setup_queries(frm, "Warehouse", function() { return erpnext.queries.warehouse(frm.doc); }); + + if (frm.is_new()) { + frm.clear_table("tax_withheld_vouchers"); + } }, is_subcontracted: function(frm) { diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index 3d74b8f139..882a374046 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -71,6 +71,9 @@ class PurchaseInvoice(BuyingController): supplier_tds = frappe.db.get_value("Supplier", self.supplier, "tax_withholding_category") self.set_onload("supplier_tds", supplier_tds) + if self.is_new(): + self.set("tax_withheld_vouchers", []) + def before_save(self): if not self.on_hold: self.release_date = "" @@ -1415,7 +1418,7 @@ class PurchaseInvoice(BuyingController): "Stock Ledger Entry", "Repost Item Valuation", "Payment Ledger Entry", - "Purchase Invoice", + "Tax Withheld Vouchers", ) self.update_advance_tax_references(cancel=1) From 5b74161195b3b006d47f29de5a97428effca527e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 1 Nov 2022 20:17:34 +0530 Subject: [PATCH 06/10] chore: Update tests --- erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py | 3 ++- 1 file changed, 2 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 1ba782451b..cb0d1a75a0 100644 --- a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py @@ -965,7 +965,8 @@ class TestSalesInvoice(unittest.TestCase): pos_return.insert() pos_return.submit() - self.assertEqual(pos_return.get("payments")[0].amount, -1000) + self.assertEqual(pos_return.get("payments")[0].amount, -500) + self.assertEqual(pos_return.get("payments")[1].amount, -500) def test_pos_change_amount(self): make_pos_profile( From 3f2728e3f7645080b20a6835da6bb39bbd084b11 Mon Sep 17 00:00:00 2001 From: Rohit Waghchaure Date: Tue, 1 Nov 2022 19:56:55 +0530 Subject: [PATCH 07/10] test: run tmate --- erpnext/stock/doctype/material_request/test_material_request.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py index 005480e399..f02462c596 100644 --- a/erpnext/stock/doctype/material_request/test_material_request.py +++ b/erpnext/stock/doctype/material_request/test_material_request.py @@ -590,8 +590,8 @@ class TestMaterialRequest(FrappeTestCase): mr = frappe.copy_doc(test_records[0]) mr.material_request_type = "Material Issue" mr.submit() + frappe.db.value_cache = {} - self.assertTrue(frappe.db.exists("Material Request", mr.name)) # testing bin value after material request is submitted self.assertEqual(_get_requested_qty(), existing_requested_qty - 54.0) From 81d791eea0eaec86d532a0a248752976eeaf08c2 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 2 Nov 2022 15:40:56 +0530 Subject: [PATCH 08/10] test: refactor use @change_settings decorator when possible --- .../doctype/purchase_order/test_purchase_order.py | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index 6c1bcc7dd4..e0981c697b 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -5,7 +5,7 @@ import json import frappe -from frappe.tests.utils import FrappeTestCase +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, flt, getdate, nowdate from frappe.utils.data import today @@ -709,13 +709,10 @@ class TestPurchaseOrder(FrappeTestCase): pi.insert() self.assertTrue(pi.get("payment_schedule")) + @change_settings("Accounts Settings", {"unlink_advance_payment_on_cancelation_of_order": 1}) def test_advance_payment_entry_unlink_against_purchase_order(self): from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry - frappe.db.set_value( - "Accounts Settings", "Accounts Settings", "unlink_advance_payment_on_cancelation_of_order", 1 - ) - po_doc = create_purchase_order() pe = get_payment_entry("Purchase Order", po_doc.name, bank_account="_Test Bank - _TC") @@ -735,10 +732,6 @@ class TestPurchaseOrder(FrappeTestCase): pe_doc = frappe.get_doc("Payment Entry", pe.name) pe_doc.cancel() - frappe.db.set_value( - "Accounts Settings", "Accounts Settings", "unlink_advance_payment_on_cancelation_of_order", 0 - ) - def test_schedule_date(self): po = create_purchase_order(do_not_submit=True) po.schedule_date = None From 1a0a8ac7e238ab3ca912b0912e76b1de69ace363 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 2 Nov 2022 15:43:45 +0530 Subject: [PATCH 09/10] test: PO advance paid on payment submission and cancellation --- .../purchase_order/test_purchase_order.py | 26 +++++++++++++++++++ 1 file changed, 26 insertions(+) diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py index e0981c697b..5a96131157 100644 --- a/erpnext/buying/doctype/purchase_order/test_purchase_order.py +++ b/erpnext/buying/doctype/purchase_order/test_purchase_order.py @@ -732,6 +732,32 @@ class TestPurchaseOrder(FrappeTestCase): pe_doc = frappe.get_doc("Payment Entry", pe.name) pe_doc.cancel() + @change_settings("Accounts Settings", {"unlink_advance_payment_on_cancelation_of_order": 1}) + def test_advance_paid_upon_payment_entry_cancellation(self): + from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry + + po_doc = create_purchase_order() + + pe = get_payment_entry("Purchase Order", po_doc.name, bank_account="_Test Bank - _TC") + pe.reference_no = "1" + pe.reference_date = nowdate() + pe.paid_from_account_currency = po_doc.currency + pe.paid_to_account_currency = po_doc.currency + pe.source_exchange_rate = 1 + pe.target_exchange_rate = 1 + pe.paid_amount = po_doc.grand_total + pe.save(ignore_permissions=True) + pe.submit() + + po_doc.reload() + self.assertEqual(po_doc.advance_paid, po_doc.base_grand_total) + + pe_doc = frappe.get_doc("Payment Entry", pe.name) + pe_doc.cancel() + + po_doc.reload() + self.assertEqual(po_doc.advance_paid, 0) + def test_schedule_date(self): po = create_purchase_order(do_not_submit=True) po.schedule_date = None From 721ac6b847ed56943621697123359d7d37360a3e Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 2 Nov 2022 15:54:23 +0530 Subject: [PATCH 10/10] test: SO advance paid on Payment submission and cancellation --- .../doctype/sales_order/test_sales_order.py | 29 ++++++++++++++++++- 1 file changed, 28 insertions(+), 1 deletion(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index adfb39c1ae..dfa341b1fc 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -6,7 +6,7 @@ import json import frappe import frappe.permissions from frappe.core.doctype.user_permission.test_user_permission import create_user -from frappe.tests.utils import FrappeTestCase +from frappe.tests.utils import FrappeTestCase, change_settings from frappe.utils import add_days, flt, getdate, nowdate, today from erpnext.controllers.accounts_controller import update_child_qty_rate @@ -1346,6 +1346,33 @@ class TestSalesOrder(FrappeTestCase): self.assertRaises(frappe.LinkExistsError, so_doc.cancel) + @change_settings("Accounts Settings", {"unlink_advance_payment_on_cancelation_of_order": 1}) + def test_advance_paid_upon_payment_cancellation(self): + from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry + + so = make_sales_order() + + pe = get_payment_entry("Sales Order", so.name, bank_account="_Test Bank - _TC") + pe.reference_no = "1" + pe.reference_date = nowdate() + pe.paid_from_account_currency = so.currency + pe.paid_to_account_currency = so.currency + pe.source_exchange_rate = 1 + pe.target_exchange_rate = 1 + pe.paid_amount = so.grand_total + pe.save(ignore_permissions=True) + pe.submit() + so.reload() + + self.assertEqual(so.advance_paid, so.base_grand_total) + + # cancel advance payment + pe.reload() + pe.cancel() + + so.reload() + self.assertEqual(so.advance_paid, 0) + def test_cancel_sales_order_after_cancel_payment_entry(self): from erpnext.accounts.doctype.payment_entry.test_payment_entry import get_payment_entry