From 0534cf6c9c25b510593789e0736e9b1fd6c0463b Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 25 Mar 2022 19:03:33 +0530 Subject: [PATCH 1/6] fix: show subassembly table always (#30422) [skip ci] --- .../manufacturing/doctype/production_plan/production_plan.json | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/erpnext/manufacturing/doctype/production_plan/production_plan.json b/erpnext/manufacturing/doctype/production_plan/production_plan.json index 339c6af64a..85f98430cd 100644 --- a/erpnext/manufacturing/doctype/production_plan/production_plan.json +++ b/erpnext/manufacturing/doctype/production_plan/production_plan.json @@ -351,7 +351,6 @@ "hide_border": 1 }, { - "depends_on": "get_items_from", "fieldname": "sub_assembly_items", "fieldtype": "Table", "label": "Sub Assembly Items", @@ -385,7 +384,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2022-03-14 03:56:23.209247", + "modified": "2022-03-25 09:15:25.017664", "modified_by": "Administrator", "module": "Manufacturing", "name": "Production Plan", From 046122362758c9060ee06104bd362f9298fe7129 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 24 Mar 2022 22:36:20 +0530 Subject: [PATCH 2/6] fix: Expense Claim conditions for Paid status - status doesn't change to Paid if the entire required amount is already covered via linked advances - status doesn't change to Paid if the claim is partially paid via advances - patch to update such uncancelled claims to Paid --- .../hr/doctype/expense_claim/expense_claim.py | 12 ++++++++--- erpnext/patches.txt | 1 + ..._expense_claim_status_for_paid_advances.py | 21 +++++++++++++++++++ 3 files changed, 31 insertions(+), 3 deletions(-) create mode 100644 erpnext/patches/v13_0/update_expense_claim_status_for_paid_advances.py diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index fe04efbbab..9bb31b3ad8 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -42,10 +42,16 @@ class ExpenseClaim(AccountsController): "2": "Cancelled" }[cstr(self.docstatus or 0)] - paid_amount = flt(self.total_amount_reimbursed) + flt(self.total_advance_amount) precision = self.precision("grand_total") - if (self.is_paid or (flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 - and flt(self.grand_total, precision) == flt(paid_amount, precision))) and self.approval_status == 'Approved': + + if ( + # set as paid + self.is_paid + # grand total is reimbursed + or (flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and flt(self.grand_total, precision) == flt(self.total_amount_reimbursed, precision)) + # grand total (to be paid) is 0 since linked advances already cover the claimed amount + or (flt(self.grand_total, precision) == 0) + ) and self.approval_status == "Approved": status = "Paid" elif flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and self.approval_status == 'Approved': status = "Unpaid" diff --git a/erpnext/patches.txt b/erpnext/patches.txt index dc1d6929aa..028834a0ec 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -362,3 +362,4 @@ erpnext.patches.v14_0.update_employee_advance_status erpnext.patches.v13_0.add_cost_center_in_loans erpnext.patches.v13_0.set_return_against_in_pos_invoice_references erpnext.patches.v13_0.remove_unknown_links_to_prod_plan_items # 24-03-2022 +erpnext.patches.v13_0.update_expense_claim_status_for_paid_advances diff --git a/erpnext/patches/v13_0/update_expense_claim_status_for_paid_advances.py b/erpnext/patches/v13_0/update_expense_claim_status_for_paid_advances.py new file mode 100644 index 0000000000..206d032f53 --- /dev/null +++ b/erpnext/patches/v13_0/update_expense_claim_status_for_paid_advances.py @@ -0,0 +1,21 @@ +import frappe + + +def execute(): + """ + Update Expense Claim status to Paid if: + - the entire required amount is already covered via linked advances + - the claim is partially paid via advances and the rest is reimbursed + """ + + ExpenseClaim = frappe.qb.DocType('Expense Claim') + + (frappe.qb + .update(ExpenseClaim) + .set(ExpenseClaim.status, 'Paid') + .where( + ((ExpenseClaim.grand_total == 0) | (ExpenseClaim.grand_total == ExpenseClaim.total_amount_reimbursed)) + & (ExpenseClaim.approval_status == 'Approved') + & (ExpenseClaim.docstatus != 2) + ) + ).run() From edf0c0030e9fe73b459b6584f2b3e2d42ec5e3e2 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 24 Mar 2022 22:36:28 +0530 Subject: [PATCH 3/6] test: expense claim against fully and partially paid advances --- .../expense_claim/test_expense_claim.py | 51 +++++++++++++++++++ 1 file changed, 51 insertions(+) diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py index 2a079201b7..e1f26e92be 100644 --- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py @@ -72,6 +72,57 @@ class TestExpenseClaim(unittest.TestCase): expense_claim = frappe.get_doc("Expense Claim", expense_claim.name) self.assertEqual(expense_claim.status, "Unpaid") + def test_expense_claim_against_fully_paid_advances(self): + from erpnext.hr.doctype.employee_advance.test_employee_advance import get_advances_for_claim, make_employee_advance, make_payment_entry + + frappe.db.delete("Employee Advance") + + payable_account = get_payable_account("_Test Company") + claim = make_expense_claim(payable_account, 1000, 1000, "_Test Company", "Travel Expenses - _TC", do_not_submit=True) + + advance = make_employee_advance(claim.employee) + pe = make_payment_entry(advance) + pe.submit() + + # claim for already paid out advances + claim = get_advances_for_claim(claim, advance.name) + claim.save() + claim.submit() + + self.assertEqual(claim.grand_total, 0) + self.assertEqual(claim.status, "Paid") + + def test_expense_claim_partially_paid_via_advance(self): + from erpnext.hr.doctype.employee_advance.test_employee_advance import ( + get_advances_for_claim, + make_employee_advance, + make_payment_entry as make_advance_payment + ) + + frappe.db.delete("Employee Advance") + + payable_account = get_payable_account("_Test Company") + claim = make_expense_claim(payable_account, 1000, 1000, "_Test Company", "Travel Expenses - _TC", do_not_submit=True) + + # link advance for partial amount + advance = make_employee_advance(claim.employee, {'advance_amount': 500}) + pe = make_advance_payment(advance) + pe.submit() + + claim = get_advances_for_claim(claim, advance.name) + claim.save() + claim.submit() + + self.assertEqual(claim.grand_total, 500) + self.assertEqual(claim.status, "Unpaid") + + # reimburse remaning amount + make_payment_entry(claim, payable_account, 500) + claim.reload() + + self.assertEqual(claim.total_amount_reimbursed, 500) + self.assertEqual(claim.status, "Paid") + def test_expense_claim_gl_entry(self): payable_account = get_payable_account(company_name) taxes = generate_taxes() From 2d915782cb29f66d0d59c719450ad926934976d8 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 24 Mar 2022 23:23:44 +0530 Subject: [PATCH 4/6] chore: sort imports --- erpnext/hr/doctype/expense_claim/test_expense_claim.py | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py index e1f26e92be..285717a68d 100644 --- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py @@ -73,7 +73,11 @@ class TestExpenseClaim(unittest.TestCase): self.assertEqual(expense_claim.status, "Unpaid") def test_expense_claim_against_fully_paid_advances(self): - from erpnext.hr.doctype.employee_advance.test_employee_advance import get_advances_for_claim, make_employee_advance, make_payment_entry + from erpnext.hr.doctype.employee_advance.test_employee_advance import ( + get_advances_for_claim, + make_employee_advance, + make_payment_entry, + ) frappe.db.delete("Employee Advance") @@ -96,7 +100,9 @@ class TestExpenseClaim(unittest.TestCase): from erpnext.hr.doctype.employee_advance.test_employee_advance import ( get_advances_for_claim, make_employee_advance, - make_payment_entry as make_advance_payment + ) + from erpnext.hr.doctype.employee_advance.test_employee_advance import ( + make_payment_entry as make_advance_payment, ) frappe.db.delete("Employee Advance") From ffec9516fac7855107a86fed2a6acca6c44bd39f Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Fri, 25 Mar 2022 20:11:38 +0530 Subject: [PATCH 5/6] fix: do not update status to Paid if sanctioned amount is 0 --- erpnext/hr/doctype/expense_claim/expense_claim.py | 10 ++++++---- erpnext/hr/doctype/expense_claim/test_expense_claim.py | 9 +++++++++ .../update_expense_claim_status_for_paid_advances.py | 3 ++- 3 files changed, 17 insertions(+), 5 deletions(-) diff --git a/erpnext/hr/doctype/expense_claim/expense_claim.py b/erpnext/hr/doctype/expense_claim/expense_claim.py index 9bb31b3ad8..12a3112396 100644 --- a/erpnext/hr/doctype/expense_claim/expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/expense_claim.py @@ -47,10 +47,12 @@ class ExpenseClaim(AccountsController): if ( # set as paid self.is_paid - # grand total is reimbursed - or (flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and flt(self.grand_total, precision) == flt(self.total_amount_reimbursed, precision)) - # grand total (to be paid) is 0 since linked advances already cover the claimed amount - or (flt(self.grand_total, precision) == 0) + or (flt(self.total_sanctioned_amount > 0) and ( + # grand total is reimbursed + (self.docstatus == 1 and flt(self.grand_total, precision) == flt(self.total_amount_reimbursed, precision)) + # grand total (to be paid) is 0 since linked advances already cover the claimed amount + or (flt(self.grand_total, precision) == 0) + )) ) and self.approval_status == "Approved": status = "Paid" elif flt(self.total_sanctioned_amount) > 0 and self.docstatus == 1 and self.approval_status == 'Approved': diff --git a/erpnext/hr/doctype/expense_claim/test_expense_claim.py b/erpnext/hr/doctype/expense_claim/test_expense_claim.py index 285717a68d..1244cc4364 100644 --- a/erpnext/hr/doctype/expense_claim/test_expense_claim.py +++ b/erpnext/hr/doctype/expense_claim/test_expense_claim.py @@ -72,6 +72,15 @@ class TestExpenseClaim(unittest.TestCase): expense_claim = frappe.get_doc("Expense Claim", expense_claim.name) self.assertEqual(expense_claim.status, "Unpaid") + # expense claim without any sanctioned amount should not have status as Paid + claim = make_expense_claim(payable_account, 1000, 0, "_Test Company", "Travel Expenses - _TC") + self.assertEqual(claim.total_sanctioned_amount, 0) + self.assertEqual(claim.status, "Submitted") + + # no gl entries created + gl_entry = frappe.get_all('GL Entry', {'voucher_type': 'Expense Claim', 'voucher_no': claim.name}) + self.assertEqual(len(gl_entry), 0) + def test_expense_claim_against_fully_paid_advances(self): from erpnext.hr.doctype.employee_advance.test_employee_advance import ( get_advances_for_claim, diff --git a/erpnext/patches/v13_0/update_expense_claim_status_for_paid_advances.py b/erpnext/patches/v13_0/update_expense_claim_status_for_paid_advances.py index 206d032f53..063de1637d 100644 --- a/erpnext/patches/v13_0/update_expense_claim_status_for_paid_advances.py +++ b/erpnext/patches/v13_0/update_expense_claim_status_for_paid_advances.py @@ -16,6 +16,7 @@ def execute(): .where( ((ExpenseClaim.grand_total == 0) | (ExpenseClaim.grand_total == ExpenseClaim.total_amount_reimbursed)) & (ExpenseClaim.approval_status == 'Approved') - & (ExpenseClaim.docstatus != 2) + & (ExpenseClaim.docstatus == 1) + & (ExpenseClaim.total_sanctioned_amount > 0) ) ).run() From 2e9648538ea248f6d13f004d0fee9a06b54fe548 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 25 Mar 2022 21:49:19 +0530 Subject: [PATCH 6/6] fix: Check for onload property (cherry picked from commit 71402b43a776d4af98912223c8299c4fd8bfbbfe) --- erpnext/public/js/controllers/transaction.js | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/erpnext/public/js/controllers/transaction.js b/erpnext/public/js/controllers/transaction.js index 19e12e3c69..a8cec0ad12 100644 --- a/erpnext/public/js/controllers/transaction.js +++ b/erpnext/public/js/controllers/transaction.js @@ -1044,7 +1044,7 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe var company_currency = this.get_company_currency(); // Added `ignore_price_list` to determine if document is loading after mapping from another doc if(this.frm.doc.currency && this.frm.doc.currency !== company_currency - && !this.frm.doc.__onload.ignore_price_list) { + && !(this.frm.doc.__onload && this.frm.doc.__onload.ignore_price_list)) { this.get_exchange_rate(transaction_date, this.frm.doc.currency, company_currency, function(exchange_rate) { @@ -1145,7 +1145,8 @@ erpnext.TransactionController = class TransactionController extends erpnext.taxe var company_currency = this.get_company_currency(); // Added `ignore_price_list` to determine if document is loading after mapping from another doc - if(this.frm.doc.price_list_currency !== company_currency && !this.frm.doc.__onload.ignore_price_list) { + if(this.frm.doc.price_list_currency !== company_currency && + !(this.frm.doc.__onload && this.frm.doc.__onload.ignore_price_list)) { this.get_exchange_rate(this.frm.doc.posting_date, this.frm.doc.price_list_currency, company_currency, function(exchange_rate) { me.frm.set_value("plc_conversion_rate", exchange_rate);