Merge branch 'develop' into asset_bill_date_new
diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
index c3a9855..39a6235 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.js
@@ -569,6 +569,10 @@
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 3d74b8f..882a374 100644
--- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
+++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py
@@ -71,6 +71,9 @@
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 @@
"Stock Ledger Entry",
"Repost Item Valuation",
"Payment Ledger Entry",
- "Purchase Invoice",
+ "Tax Withheld Vouchers",
)
self.update_advance_tax_references(cancel=1)
diff --git a/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py
index 1ba7824..cb0d1a7 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 @@
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(
diff --git a/erpnext/buying/doctype/purchase_order/test_purchase_order.py b/erpnext/buying/doctype/purchase_order/test_purchase_order.py
index 6c1bcc7..5a96131 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 @@
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,9 +732,31 @@
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
- )
+ @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)
diff --git a/erpnext/controllers/accounts_controller.py b/erpnext/controllers/accounts_controller.py
index 22291a3..7f5dc02 100644
--- a/erpnext/controllers/accounts_controller.py
+++ b/erpnext/controllers/accounts_controller.py
@@ -7,7 +7,7 @@
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 @@
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]
diff --git a/erpnext/controllers/taxes_and_totals.py b/erpnext/controllers/taxes_and_totals.py
index cbcccce..b5836c9 100644
--- a/erpnext/controllers/taxes_and_totals.py
+++ b/erpnext/controllers/taxes_and_totals.py
@@ -889,24 +889,33 @@
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:
diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py
index adfb39c..dfa341b 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 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 @@
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
diff --git a/erpnext/stock/doctype/batch/batch.py b/erpnext/stock/doctype/batch/batch.py
index 52854a0..f14288b 100644
--- a/erpnext/stock/doctype/batch/batch.py
+++ b/erpnext/stock/doctype/batch/batch.py
@@ -291,7 +291,7 @@
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
diff --git a/erpnext/stock/doctype/material_request/test_material_request.py b/erpnext/stock/doctype/material_request/test_material_request.py
index 78af153..f02462c 100644
--- a/erpnext/stock/doctype/material_request/test_material_request.py
+++ b/erpnext/stock/doctype/material_request/test_material_request.py
@@ -590,6 +590,7 @@
mr = frappe.copy_doc(test_records[0])
mr.material_request_type = "Material Issue"
mr.submit()
+ frappe.db.value_cache = {}
# testing bin value after material request is submitted
self.assertEqual(_get_requested_qty(), existing_requested_qty - 54.0)