Skip to content

Commit b0c742b

Browse files
authored
Merge pull request #46941 from frappe/version-14-hotfix
chore: release v14
2 parents ceaea16 + 18282b2 commit b0c742b

21 files changed

Lines changed: 3160 additions & 2097 deletions

File tree

erpnext/accounts/doctype/bank_clearance/bank_clearance.py

Lines changed: 2 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -46,9 +46,6 @@ def get_payment_entries(self):
4646
as_dict=1,
4747
)
4848

49-
if self.bank_account:
50-
condition += "and bank_account = %(bank_account)s"
51-
5249
payment_entries = frappe.db.sql(
5350
f"""
5451
select
@@ -70,7 +67,6 @@ def get_payment_entries(self):
7067
"account": self.account,
7168
"from": self.from_date,
7269
"to": self.to_date,
73-
"bank_account": self.bank_account,
7470
},
7571
as_dict=1,
7672
)
@@ -93,7 +89,7 @@ def get_payment_entries(self):
9389
.where(loan_disbursement.docstatus == 1)
9490
.where(loan_disbursement.disbursement_date >= self.from_date)
9591
.where(loan_disbursement.disbursement_date <= self.to_date)
96-
.where(loan_disbursement.disbursement_account.isin([self.bank_account, self.account]))
92+
.where(loan_disbursement.disbursement_account == self.account)
9793
.orderby(loan_disbursement.disbursement_date)
9894
.orderby(loan_disbursement.name, order=frappe.qb.desc)
9995
)
@@ -121,7 +117,7 @@ def get_payment_entries(self):
121117
.where(loan_repayment.docstatus == 1)
122118
.where(loan_repayment.posting_date >= self.from_date)
123119
.where(loan_repayment.posting_date <= self.to_date)
124-
.where(loan_repayment.payment_account.isin([self.bank_account, self.account]))
120+
.where(loan_repayment.payment_account == self.account)
125121
)
126122

127123
if not self.include_reconciled_entries:

erpnext/accounts/doctype/purchase_invoice/test_purchase_invoice.py

Lines changed: 73 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1852,7 +1852,7 @@ def test_payment_allocation_for_payment_terms(self):
18521852
1,
18531853
)
18541854
pi = make_pi_from_pr(pr.name)
1855-
self.assertEqual(pi.payment_schedule[0].payment_amount, 2500)
1855+
self.assertEqual(pi.payment_schedule[0].payment_amount, 1000)
18561856

18571857
automatically_fetch_payment_terms(enable=0)
18581858
frappe.db.set_value(
@@ -1984,6 +1984,78 @@ def test_debit_note_with_account_mismatch(self):
19841984

19851985
self.assertRaises(frappe.ValidationError, dr_note.save)
19861986

1987+
def test_apply_discount_on_grand_total(self):
1988+
"""
1989+
To test if after applying discount on grand total,
1990+
the grand total is calculated correctly without any rounding errors
1991+
"""
1992+
invoice = make_purchase_invoice(qty=2, rate=100, do_not_save=True, do_not_submit=True)
1993+
invoice.append(
1994+
"items",
1995+
{
1996+
"item_code": "_Test Item",
1997+
"qty": 1,
1998+
"rate": 21.39,
1999+
},
2000+
)
2001+
invoice.append(
2002+
"taxes",
2003+
{
2004+
"charge_type": "On Net Total",
2005+
"account_head": "_Test Account VAT - _TC",
2006+
"description": "VAT",
2007+
"rate": 15.5,
2008+
},
2009+
)
2010+
2011+
# the grand total here will be 255.71
2012+
invoice.disable_rounded_total = 1
2013+
# apply discount on grand total to adjust the grand total to 255
2014+
invoice.discount_amount = 0.71
2015+
invoice.save()
2016+
2017+
# check if grand total is 496 and not something like 254.99 due to rounding errors
2018+
self.assertEqual(invoice.grand_total, 255)
2019+
2020+
def test_apply_discount_on_grand_total_with_previous_row_total_tax(self):
2021+
"""
2022+
To test if after applying discount on grand total,
2023+
where the tax is calculated on previous row total, the grand total is calculated correctly
2024+
"""
2025+
2026+
invoice = make_purchase_invoice(qty=2, rate=100, do_not_save=True, do_not_submit=True)
2027+
invoice.extend(
2028+
"taxes",
2029+
[
2030+
{
2031+
"charge_type": "Actual",
2032+
"account_head": "_Test Account VAT - _TC",
2033+
"description": "VAT",
2034+
"tax_amount": 100,
2035+
},
2036+
{
2037+
"charge_type": "On Previous Row Amount",
2038+
"account_head": "_Test Account VAT - _TC",
2039+
"description": "VAT",
2040+
"row_id": 1,
2041+
"rate": 10,
2042+
},
2043+
{
2044+
"charge_type": "On Previous Row Total",
2045+
"account_head": "_Test Account VAT - _TC",
2046+
"description": "VAT",
2047+
"row_id": 1,
2048+
"rate": 10,
2049+
},
2050+
],
2051+
)
2052+
2053+
# the total here will be 340, so applying 40 discount
2054+
invoice.discount_amount = 40
2055+
invoice.save()
2056+
2057+
self.assertEqual(invoice.grand_total, 300)
2058+
19872059

19882060
def check_gl_entries(
19892061
doc,

erpnext/accounts/doctype/sales_invoice/sales_invoice.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,8 +91,8 @@ def set_indicator(self):
9191
self.indicator_title = _("Paid")
9292

9393
def validate(self):
94-
super().validate()
9594
self.validate_auto_set_posting_time()
95+
super().validate()
9696

9797
if not (self.is_pos or self.is_debit_note):
9898
self.so_dn_required()

erpnext/accounts/doctype/sales_invoice/test_sales_invoice.py

Lines changed: 32 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -416,9 +416,9 @@ def test_sales_invoice_discount_amount(self):
416416
for i, k in enumerate(expected_values["keys"]):
417417
self.assertEqual(d.get(k), expected_values[d.account_head][i])
418418

419-
self.assertEqual(si.base_grand_total, 1500.01)
420-
self.assertEqual(si.grand_total, 1500.01)
421-
self.assertEqual(si.rounding_adjustment, -0.01)
419+
self.assertEqual(si.base_grand_total, 1500)
420+
self.assertEqual(si.grand_total, 1500)
421+
self.assertEqual(si.rounding_adjustment, 0)
422422

423423
def test_discount_amount_gl_entry(self):
424424
frappe.db.set_value("Company", "_Test Company", "round_off_account", "Round Off - _TC")
@@ -3860,6 +3860,35 @@ def test_total_billed_amount(self):
38603860
doc = frappe.get_doc("Project", project.name)
38613861
self.assertEqual(doc.total_billed_amount, si.grand_total)
38623862

3863+
def test_create_return_invoice_for_self_update(self):
3864+
from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
3865+
from erpnext.accounts.doctype.sales_invoice.test_sales_invoice import create_sales_invoice
3866+
from erpnext.controllers.sales_and_purchase_return import make_return_doc
3867+
3868+
invoice = create_sales_invoice()
3869+
3870+
payment_entry = get_payment_entry(dt=invoice.doctype, dn=invoice.name)
3871+
payment_entry.reference_no = "test001"
3872+
payment_entry.reference_date = getdate()
3873+
3874+
payment_entry.save()
3875+
payment_entry.submit()
3876+
3877+
r_invoice = make_return_doc(invoice.doctype, invoice.name)
3878+
3879+
r_invoice.update_outstanding_for_self = 0
3880+
r_invoice.save()
3881+
3882+
self.assertEqual(r_invoice.update_outstanding_for_self, 1)
3883+
3884+
r_invoice.submit()
3885+
3886+
self.assertNotEqual(r_invoice.outstanding_amount, 0)
3887+
3888+
invoice.reload()
3889+
3890+
self.assertEqual(invoice.outstanding_amount, 0)
3891+
38633892

38643893
def check_gl_entries(doc, voucher_no, expected_gle, posting_date):
38653894
gl_entries = frappe.db.sql(

erpnext/accounts/report/accounts_receivable/test_accounts_receivable.py

Lines changed: 108 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -21,7 +21,7 @@ def setUp(self):
2121
def tearDown(self):
2222
frappe.db.rollback()
2323

24-
def create_sales_invoice(self, no_payment_schedule=False, do_not_submit=False):
24+
def create_sales_invoice(self, no_payment_schedule=False, do_not_submit=False, **args):
2525
frappe.set_user("Administrator")
2626
si = create_sales_invoice(
2727
item=self.item,
@@ -34,6 +34,7 @@ def create_sales_invoice(self, no_payment_schedule=False, do_not_submit=False):
3434
rate=100,
3535
price_list_rate=100,
3636
do_not_save=1,
37+
**args,
3738
)
3839
if not no_payment_schedule:
3940
si.append(
@@ -111,7 +112,7 @@ def test_pos_receivable(self):
111112
self.assertEqual(expected_data[0], [row.invoiced, row.paid, row.credit_note])
112113
pos_inv.cancel()
113114

114-
def test_accounts_receivable(self):
115+
def test_accounts_receivable_with_payment(self):
115116
filters = {
116117
"company": self.company,
117118
"based_on_payment_terms": 1,
@@ -151,11 +152,15 @@ def test_accounts_receivable(self):
151152
cr_note = self.create_credit_note(si.name, do_not_submit=True)
152153
cr_note.update_outstanding_for_self = False
153154
cr_note.save().submit()
155+
156+
# as the invoice partially paid and returning the full amount so the outstanding amount should be True
157+
self.assertEqual(cr_note.update_outstanding_for_self, True)
158+
154159
report = execute(filters)
155160

156-
expected_data_after_credit_note = [100, 0, 0, 40, -40, self.debit_to]
161+
expected_data_after_credit_note = [0, 0, 100, 0, -100, self.debit_to]
157162

158-
row = report[1][0]
163+
row = report[1][-1]
159164
self.assertEqual(
160165
expected_data_after_credit_note,
161166
[
@@ -168,6 +173,105 @@ def test_accounts_receivable(self):
168173
],
169174
)
170175

176+
def test_accounts_receivable_without_payment(self):
177+
filters = {
178+
"company": self.company,
179+
"based_on_payment_terms": 1,
180+
"report_date": today(),
181+
"range1": 30,
182+
"range2": 60,
183+
"range3": 90,
184+
"range4": 120,
185+
"show_remarks": True,
186+
}
187+
188+
# check invoice grand total and invoiced column's value for 3 payment terms
189+
si = self.create_sales_invoice()
190+
191+
report = execute(filters)
192+
193+
expected_data = [[100, 30, "No Remarks"], [100, 50, "No Remarks"], [100, 20, "No Remarks"]]
194+
195+
for i in range(3):
196+
row = report[1][i - 1]
197+
self.assertEqual(expected_data[i - 1], [row.invoice_grand_total, row.invoiced, row.remarks])
198+
199+
# check invoice grand total, invoiced, paid and outstanding column's value after credit note
200+
cr_note = self.create_credit_note(si.name, do_not_submit=True)
201+
cr_note.update_outstanding_for_self = False
202+
cr_note.save().submit()
203+
204+
self.assertEqual(cr_note.update_outstanding_for_self, False)
205+
206+
report = execute(filters)
207+
208+
row = report[1]
209+
self.assertTrue(len(row) == 0)
210+
211+
def test_accounts_receivable_with_partial_payment(self):
212+
filters = {
213+
"company": self.company,
214+
"based_on_payment_terms": 1,
215+
"report_date": today(),
216+
"range1": 30,
217+
"range2": 60,
218+
"range3": 90,
219+
"range4": 120,
220+
"show_remarks": True,
221+
}
222+
223+
# check invoice grand total and invoiced column's value for 3 payment terms
224+
si = self.create_sales_invoice(qty=2)
225+
226+
report = execute(filters)
227+
228+
expected_data = [[200, 60, "No Remarks"], [200, 100, "No Remarks"], [200, 40, "No Remarks"]]
229+
230+
for i in range(3):
231+
row = report[1][i - 1]
232+
self.assertEqual(expected_data[i - 1], [row.invoice_grand_total, row.invoiced, row.remarks])
233+
234+
# check invoice grand total, invoiced, paid and outstanding column's value after payment
235+
self.create_payment_entry(si.name)
236+
report = execute(filters)
237+
238+
expected_data_after_payment = [[200, 60, 40, 20], [200, 100, 0, 100], [200, 40, 0, 40]]
239+
240+
for i in range(3):
241+
row = report[1][i - 1]
242+
self.assertEqual(
243+
expected_data_after_payment[i - 1],
244+
[row.invoice_grand_total, row.invoiced, row.paid, row.outstanding],
245+
)
246+
247+
# check invoice grand total, invoiced, paid and outstanding column's value after credit note
248+
cr_note = self.create_credit_note(si.name, do_not_submit=True)
249+
cr_note.update_outstanding_for_self = False
250+
cr_note.save().submit()
251+
252+
self.assertFalse(cr_note.update_outstanding_for_self)
253+
254+
report = execute(filters)
255+
256+
expected_data_after_credit_note = [
257+
[200, 100, 0, 80, 20, self.debit_to],
258+
[200, 40, 0, 0, 40, self.debit_to],
259+
]
260+
261+
for i in range(2):
262+
row = report[1][i - 1]
263+
self.assertEqual(
264+
expected_data_after_credit_note[i - 1],
265+
[
266+
row.invoice_grand_total,
267+
row.invoiced,
268+
row.paid,
269+
row.credit_note,
270+
row.outstanding,
271+
row.party_account,
272+
],
273+
)
274+
171275
def test_cr_note_flag_to_update_self(self):
172276
filters = {
173277
"company": self.company,

erpnext/accounts/report/asset_depreciations_and_balances/asset_depreciations_and_balances.js

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -25,11 +25,26 @@ frappe.query_reports["Asset Depreciations and Balances"] = {
2525
default: erpnext.utils.get_fiscal_year(frappe.datetime.get_today(), true)[2],
2626
reqd: 1,
2727
},
28+
{
29+
fieldname: "group_by",
30+
label: __("Group By"),
31+
fieldtype: "Select",
32+
options: ["Asset Category", "Asset"],
33+
default: "Asset Category",
34+
},
2835
{
2936
fieldname: "asset_category",
3037
label: __("Asset Category"),
3138
fieldtype: "Link",
3239
options: "Asset Category",
40+
depends_on: "eval: doc.group_by == 'Asset Category'",
41+
},
42+
{
43+
fieldname: "asset",
44+
label: __("Asset"),
45+
fieldtype: "Link",
46+
options: "Asset",
47+
depends_on: "eval: doc.group_by == 'Asset'",
3348
},
3449
],
3550
};

0 commit comments

Comments
 (0)