From 0fe95bf77e01cf5a02be5b4351980a320f2d15df Mon Sep 17 00:00:00 2001 From: Daizy Modi Date: Wed, 21 Jun 2023 10:33:28 +0530 Subject: [PATCH 01/12] chore: remove whitelisting for methods not used from UI (#35592) --- erpnext/hr/doctype/leave_allocation/leave_allocation.py | 1 - .../doctype/leave_policy_assignment/leave_policy_assignment.py | 1 - erpnext/payroll/doctype/additional_salary/additional_salary.py | 1 - 3 files changed, 3 deletions(-) diff --git a/erpnext/hr/doctype/leave_allocation/leave_allocation.py b/erpnext/hr/doctype/leave_allocation/leave_allocation.py index 09484d337551..ffd6e42f1b08 100755 --- a/erpnext/hr/doctype/leave_allocation/leave_allocation.py +++ b/erpnext/hr/doctype/leave_allocation/leave_allocation.py @@ -333,7 +333,6 @@ def get_leave_allocation_for_period( ).run()[0][0] or 0.0 -@frappe.whitelist() def get_carry_forwarded_leaves(employee, leave_type, date, carry_forward=None): """Returns carry forwarded leaves for the given employee""" unused_leaves = 0.0 diff --git a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py index 83c0b4dceba4..79295aa1bd42 100644 --- a/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py +++ b/erpnext/hr/doctype/leave_policy_assignment/leave_policy_assignment.py @@ -74,7 +74,6 @@ def warn_about_carry_forwarding(self): ).format(frappe.bold(get_link_to_form("Leave Type", leave_type.name))) frappe.msgprint(msg, indicator="orange", alert=True) - @frappe.whitelist() def grant_leave_alloc_for_employee(self): if self.leaves_allocated: frappe.throw(_("Leave already have been assigned for this Leave Policy Assignment")) diff --git a/erpnext/payroll/doctype/additional_salary/additional_salary.py b/erpnext/payroll/doctype/additional_salary/additional_salary.py index 18bd3b7733c0..018cc8550c6f 100644 --- a/erpnext/payroll/doctype/additional_salary/additional_salary.py +++ b/erpnext/payroll/doctype/additional_salary/additional_salary.py @@ -145,7 +145,6 @@ def get_amount(self, sal_start_date, sal_end_date): return amount_per_day * no_of_days -@frappe.whitelist() def get_additional_salaries(employee, start_date, end_date, component_type): from frappe.query_builder import Criterion From 000ebe447991185e4d5a4050b066fa0781575e65 Mon Sep 17 00:00:00 2001 From: saeedkola Date: Wed, 21 Jun 2023 14:42:16 +0530 Subject: [PATCH 02/12] Fixes issue of asset value_after_depreciation field getting updated twice if workflow is enabled in Journal Entry (#35821) * Fixes issue of asset value_after_depreciation field getting updated twice if workflow is enabled in Journal Entry * chore: remove unnecessary line break * chore: formatting --------- Co-authored-by: Anand Baburajan --- erpnext/assets/doctype/asset/depreciation.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index d086f180d3a8..e54319930a58 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -136,15 +136,15 @@ def make_depreciation_entry(asset_name, date=None): je.flags.ignore_permissions = True je.flags.planned_depr_entry = True je.save() - if not je.meta.get_workflow(): - je.submit() d.db_set("journal_entry", je.name) - idx = cint(d.finance_book_id) - finance_books = asset.get("finance_books")[idx - 1] - finance_books.value_after_depreciation -= d.depreciation_amount - finance_books.db_update() + if not je.meta.get_workflow(): + je.submit() + idx = cint(d.finance_book_id) + finance_books = asset.get("finance_books")[idx - 1] + finance_books.value_after_depreciation -= d.depreciation_amount + finance_books.db_update() asset.db_set("depr_entry_posting_status", "Successful") From 6c4dff38da24b67febda67728416389ccd3b7539 Mon Sep 17 00:00:00 2001 From: Rucha Mahabal Date: Thu, 22 Jun 2023 18:10:54 +0530 Subject: [PATCH 03/12] fix: employee link fields in payroll reports (#619) (#35845) --- .../professional_tax_deductions.py | 4 +--- .../provident_fund_deductions/provident_fund_deductions.py | 4 +--- 2 files changed, 2 insertions(+), 6 deletions(-) diff --git a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py index 17a62d5e5daf..bb325da5f64e 100644 --- a/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py +++ b/erpnext/regional/report/professional_tax_deductions/professional_tax_deductions.py @@ -21,16 +21,14 @@ def get_columns(filters): columns = [ { "label": _("Employee"), - "options": "Employee", "fieldname": "employee", "fieldtype": "Link", + "options": "Employee", "width": 200, }, { "label": _("Employee Name"), - "options": "Employee", "fieldname": "employee_name", - "fieldtype": "Link", "width": 160, }, {"label": _("Amount"), "fieldname": "amount", "fieldtype": "Currency", "width": 140}, diff --git a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py index ab4b6e73b83b..0cc78a6b78a2 100644 --- a/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py +++ b/erpnext/regional/report/provident_fund_deductions/provident_fund_deductions.py @@ -18,16 +18,14 @@ def get_columns(filters): columns = [ { "label": _("Employee"), - "options": "Employee", "fieldname": "employee", "fieldtype": "Link", + "options": "Employee", "width": 200, }, { "label": _("Employee Name"), - "options": "Employee", "fieldname": "employee_name", - "fieldtype": "Link", "width": 160, }, {"label": _("PF Account"), "fieldname": "pf_account", "fieldtype": "Data", "width": 140}, From 8939e95c625676b65d18d0a93a435ec04d654547 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Thu, 22 Jun 2023 23:01:59 +0530 Subject: [PATCH 04/12] chore: asset scrap and restore fixes [v14] (backport #35851) (#35854) * chore: asset scrap and restore fixes [v14] (#35851) chore: better err msg on cancelling JE for asset scrap and allow restoring non-depr assets (cherry picked from commit 69780da0996d00a6e8fc81b2fce860e47f971b30) # Conflicts: # erpnext/assets/doctype/asset/depreciation.py * chore: fix conflict --------- Co-authored-by: Anand Baburajan --- .../doctype/journal_entry/journal_entry.py | 15 +++++++++++---- erpnext/assets/doctype/asset/depreciation.py | 3 +++ 2 files changed, 14 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index f988222c6c22..f468a35c2467 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -330,12 +330,10 @@ def unlink_advance_entry_reference(self): d.db_update() def unlink_asset_reference(self): - if self.voucher_type != "Depreciation Entry": - return - for d in self.get("accounts"): if ( - d.reference_type == "Asset" + self.voucher_type == "Depreciation Entry" + and d.reference_type == "Asset" and d.reference_name and d.account_type == "Depreciation" and d.debit @@ -362,6 +360,15 @@ def unlink_asset_reference(self): else: asset.db_set("value_after_depreciation", asset.value_after_depreciation + d.debit) asset.set_status() + elif self.voucher_type == "Journal Entry" and d.reference_type == "Asset" and d.reference_name: + journal_entry_for_scrap = frappe.db.get_value( + "Asset", d.reference_name, "journal_entry_for_scrap" + ) + + if journal_entry_for_scrap == self.name: + frappe.throw( + _("Journal Entry for Asset scrapping cannot be cancelled. Please restore the Asset.") + ) def unlink_inter_company_jv(self): if ( diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index e54319930a58..aa9cc38be22c 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -344,6 +344,9 @@ def modify_depreciation_schedule_for_asset_repairs(asset): def reverse_depreciation_entry_made_after_disposal(asset, date): from erpnext.accounts.doctype.journal_entry.journal_entry import make_reverse_journal_entry + if not asset.calculate_depreciation: + return + row = -1 finance_book = asset.get("schedules")[0].get("finance_book") for schedule in asset.get("schedules"): From 2e2c319f20eb7d034fba10a4b6b804775fa97e04 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 23 Jun 2023 08:25:11 +0530 Subject: [PATCH 05/12] fix: show non-depreciable assets in fixed asset register (backport #35858) (#35861) fix: show non-depreciable assets in fixed asset register (#35858) fix: show non-depr assets in fixed asset register (cherry picked from commit 42d09448eed316268d9a5a2c9e25791bc48fa326) Co-authored-by: Anand Baburajan --- .../report/fixed_asset_register/fixed_asset_register.py | 6 +++++- 1 file changed, 5 insertions(+), 1 deletion(-) diff --git a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py index f810819b4fc7..6911f94bbbb1 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -115,7 +115,11 @@ def get_data(filters): depreciation_amount_map = get_asset_depreciation_amount_map(filters, finance_book) for asset in assets_record: - if assets_linked_to_fb and asset.asset_id not in assets_linked_to_fb: + if ( + assets_linked_to_fb + and asset.calculate_depreciation + and asset.asset_id not in assets_linked_to_fb + ): continue asset_value = get_asset_value_after_depreciation( From de529f0adf43d39de7cbfbb531d4de6082014e72 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Fri, 23 Jun 2023 11:37:38 +0530 Subject: [PATCH 06/12] fix: use correct fieldname for purchase receipt column in item_wise_purchase_register report (backport #35828) (#35848) fix: use correct fieldname for purchase receipt column in item_wise_purcchase_register report (cherry picked from commit dcfc86e3afa53e393c4dec74fa3f7d3a01be2aa4) Co-authored-by: phot0n --- .../item_wise_purchase_register.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index d34c21348c80..924c14bdb94f 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -87,7 +87,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum "project": d.project, "company": d.company, "purchase_order": d.purchase_order, - "purchase_receipt": d.purchase_receipt, + "purchase_receipt": purchase_receipt, "expense_account": expense_account, "stock_qty": d.stock_qty, "stock_uom": d.stock_uom, @@ -241,7 +241,7 @@ def get_columns(additional_table_columns, filters): }, { "label": _("Purchase Receipt"), - "fieldname": "Purchase Receipt", + "fieldname": "purchase_receipt", "fieldtype": "Link", "options": "Purchase Receipt", "width": 100, From 3785fe6927ef620d34be649526c5cc92c57879a8 Mon Sep 17 00:00:00 2001 From: Ashish Shah Date: Sat, 24 Jun 2023 16:40:12 +0530 Subject: [PATCH 07/12] fix: frappe.exceptions.DoesNotExistError: DocType KSA VAT Setting (#35797) fix: frappe.exceptions.DoesNotExistError: DocType KSA VAT Setting not found When migrating from v12->v13 migration fails While migrating the doctype is not reloaded before adding permission. #35795 --- erpnext/regional/saudi_arabia/setup.py | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/regional/saudi_arabia/setup.py b/erpnext/regional/saudi_arabia/setup.py index 0b9f753dcc3f..45804af1ffba 100644 --- a/erpnext/regional/saudi_arabia/setup.py +++ b/erpnext/regional/saudi_arabia/setup.py @@ -35,6 +35,7 @@ def add_print_formats(): def add_permissions(): + frappe.reload_doc("regional", "doctype", "ksa_vat_setting", force=True) """Add Permissions for KSA VAT Setting.""" add_permission("KSA VAT Setting", "All", 0) for role in ("Accounts Manager", "Accounts User", "System Manager"): From 12b62571b8a3619adbcca5050ab165564e6ea8d9 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 27 Jun 2023 12:30:08 +0530 Subject: [PATCH 08/12] fix(ux): PO Get Items From Open Material Requests (backport #35894) (#35896) fix(ux): PO Get Items From Open Material Requests (cherry picked from commit 3a00bf83d68be5f083f9290f9cfcdf756e67570a) Co-authored-by: s-aga-r --- erpnext/buying/doctype/purchase_order/purchase_order.js | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/buying/doctype/purchase_order/purchase_order.js b/erpnext/buying/doctype/purchase_order/purchase_order.js index a16c1c5486fe..8f1661bc1582 100644 --- a/erpnext/buying/doctype/purchase_order/purchase_order.js +++ b/erpnext/buying/doctype/purchase_order/purchase_order.js @@ -242,7 +242,7 @@ erpnext.buying.PurchaseOrderController = erpnext.buying.BuyingController.extend( source_name: this.frm.doc.supplier, target: this.frm, setters: { - company: me.frm.doc.company + company: this.frm.doc.company }, get_query_filters: { docstatus: ["!=", 2], From 4dd088cba4cc6f7392e0fe34445b87a05728eee5 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 27 Jun 2023 13:12:06 +0530 Subject: [PATCH 09/12] fix: TDS amount calculation post LDC breach (#35886) * fix: TDS amount calculation post LDC breach (cherry picked from commit 1f9ef6c48faf330c47daafae485ac833489db08d) # Conflicts: # erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py * chore: resolve conflicts --------- Co-authored-by: Deepesh Garg --- .../tax_withholding_category/tax_withholding_category.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py index 86c6341b68df..efa15a53c5d3 100644 --- a/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py +++ b/erpnext/accounts/doctype/tax_withholding_category/tax_withholding_category.py @@ -558,7 +558,7 @@ def is_valid_certificate( ): valid = False - available_amount = flt(certificate_limit) - flt(deducted_amount) - flt(current_amount) + available_amount = flt(certificate_limit) - flt(deducted_amount) if (getdate(valid_from) <= getdate(posting_date) <= getdate(valid_upto)) and available_amount > 0: valid = True From bcfd7708f265df9160e24adeaed9e19714e23896 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 27 Jun 2023 14:27:33 +0530 Subject: [PATCH 10/12] fix: filter parent warehouses not showing (backport #35897) (#35900) * fix: filter parent warehouses not showing (#35897) (cherry picked from commit af418d2342281c5a1fe6291971ee94e2eca42b3b) * chore: add company filter for parent warehouse --------- Co-authored-by: HLD Co-authored-by: s-aga-r --- erpnext/stock/doctype/warehouse/warehouse.js | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/doctype/warehouse/warehouse.js b/erpnext/stock/doctype/warehouse/warehouse.js index 332bfa56d912..2979e1979d96 100644 --- a/erpnext/stock/doctype/warehouse/warehouse.js +++ b/erpnext/stock/doctype/warehouse/warehouse.js @@ -13,10 +13,11 @@ frappe.ui.form.on("Warehouse", { }; }); - frm.set_query("parent_warehouse", function () { + frm.set_query("parent_warehouse", function (doc) { return { filters: { is_group: 1, + company: doc.company, }, }; }); From 41344593c963e71ba0247f3e2adb3d3f647c7823 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 10:25:33 +0530 Subject: [PATCH 11/12] perf: improve item wise register reports (backport #35908) (#35912) perf: improve item wise register reports (#35908) (cherry picked from commit 33ee01174bb909ee46bb3d714d6f94fa0aefe48f) Co-authored-by: Anand Baburajan --- .../item_wise_purchase_register.py | 31 ++++++++++++------- .../item_wise_sales_register.py | 30 ++++++++++++------ 2 files changed, 39 insertions(+), 22 deletions(-) diff --git a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py index 924c14bdb94f..6fdb2f337c09 100644 --- a/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py +++ b/erpnext/accounts/report/item_wise_purchase_register/item_wise_purchase_register.py @@ -15,7 +15,6 @@ get_group_by_conditions, get_tax_accounts, ) -from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import get_item_details def execute(filters=None): @@ -40,6 +39,16 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum tax_doctype="Purchase Taxes and Charges", ) + scrubbed_tax_fields = {} + + for tax in tax_columns: + scrubbed_tax_fields.update( + { + tax + " Rate": frappe.scrub(tax + " Rate"), + tax + " Amount": frappe.scrub(tax + " Amount"), + } + ) + po_pr_map = get_purchase_receipts_against_purchase_order(item_list) data = [] @@ -50,11 +59,7 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum if filters.get("group_by"): grand_total = get_grand_total(filters, "Purchase Invoice") - item_details = get_item_details() - for d in item_list: - item_record = item_details.get(d.item_code) - purchase_receipt = None if d.purchase_receipt: purchase_receipt = d.purchase_receipt @@ -67,8 +72,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum row = { "item_code": d.item_code, - "item_name": item_record.item_name if item_record else d.item_name, - "item_group": item_record.item_group if item_record else d.item_group, + "item_name": d.pi_item_name if d.pi_item_name else d.i_item_name, + "item_group": d.pi_item_group if d.pi_item_group else d.i_item_group, "description": d.description, "invoice": d.parent, "posting_date": d.posting_date, @@ -101,8 +106,8 @@ def _execute(filters=None, additional_table_columns=None, additional_query_colum item_tax = itemised_tax.get(d.name, {}).get(tax, {}) row.update( { - frappe.scrub(tax + " Rate"): item_tax.get("tax_rate", 0), - frappe.scrub(tax + " Amount"): item_tax.get("tax_amount", 0), + scrubbed_tax_fields[tax + " Rate"]: item_tax.get("tax_rate", 0), + scrubbed_tax_fields[tax + " Amount"]: item_tax.get("tax_amount", 0), } ) total_tax += flt(item_tax.get("tax_amount")) @@ -325,15 +330,17 @@ def get_items(filters, additional_query_columns): `tabPurchase Invoice`.supplier, `tabPurchase Invoice`.remarks, `tabPurchase Invoice`.base_net_total, `tabPurchase Invoice`.unrealized_profit_loss_account, `tabPurchase Invoice Item`.`item_code`, `tabPurchase Invoice Item`.description, - `tabPurchase Invoice Item`.`item_name`, `tabPurchase Invoice Item`.`item_group`, + `tabPurchase Invoice Item`.`item_name` as pi_item_name, `tabPurchase Invoice Item`.`item_group` as pi_item_group, + `tabItem`.`item_name` as i_item_name, `tabItem`.`item_group` as i_item_group, `tabPurchase Invoice Item`.`project`, `tabPurchase Invoice Item`.`purchase_order`, `tabPurchase Invoice Item`.`purchase_receipt`, `tabPurchase Invoice Item`.`po_detail`, `tabPurchase Invoice Item`.`expense_account`, `tabPurchase Invoice Item`.`stock_qty`, `tabPurchase Invoice Item`.`stock_uom`, `tabPurchase Invoice Item`.`base_net_amount`, `tabPurchase Invoice`.`supplier_name`, `tabPurchase Invoice`.`mode_of_payment` {0} - from `tabPurchase Invoice`, `tabPurchase Invoice Item` + from `tabPurchase Invoice`, `tabPurchase Invoice Item`, `tabItem` where `tabPurchase Invoice`.name = `tabPurchase Invoice Item`.`parent` and - `tabPurchase Invoice`.docstatus = 1 %s + `tabItem`.name = `tabPurchase Invoice Item`.`item_code` and + `tabPurchase Invoice`.docstatus = 1 %s """.format( additional_query_columns ) diff --git a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py index 0ebe13f4f326..bd7d02e04302 100644 --- a/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py +++ b/erpnext/accounts/report/item_wise_sales_register/item_wise_sales_register.py @@ -11,7 +11,6 @@ from erpnext.accounts.report.sales_register.sales_register import get_mode_of_payments from erpnext.selling.report.item_wise_sales_history.item_wise_sales_history import ( get_customer_details, - get_item_details, ) @@ -35,6 +34,16 @@ def _execute( if item_list: itemised_tax, tax_columns = get_tax_accounts(item_list, columns, company_currency) + scrubbed_tax_fields = {} + + for tax in tax_columns: + scrubbed_tax_fields.update( + { + tax + " Rate": frappe.scrub(tax + " Rate"), + tax + " Amount": frappe.scrub(tax + " Amount"), + } + ) + mode_of_payments = get_mode_of_payments(set(d.parent for d in item_list)) so_dn_map = get_delivery_notes_against_sales_order(item_list) @@ -47,11 +56,9 @@ def _execute( grand_total = get_grand_total(filters, "Sales Invoice") customer_details = get_customer_details() - item_details = get_item_details() for d in item_list: customer_record = customer_details.get(d.customer) - item_record = item_details.get(d.item_code) delivery_note = None if d.delivery_note: @@ -64,8 +71,8 @@ def _execute( row = { "item_code": d.item_code, - "item_name": item_record.item_name if item_record else d.item_name, - "item_group": item_record.item_group if item_record else d.item_group, + "item_name": d.si_item_name if d.si_item_name else d.i_item_name, + "item_group": d.si_item_group if d.si_item_group else d.i_item_group, "description": d.description, "invoice": d.parent, "posting_date": d.posting_date, @@ -107,8 +114,8 @@ def _execute( item_tax = itemised_tax.get(d.name, {}).get(tax, {}) row.update( { - frappe.scrub(tax + " Rate"): item_tax.get("tax_rate", 0), - frappe.scrub(tax + " Amount"): item_tax.get("tax_amount", 0), + scrubbed_tax_fields[tax + " Rate"]: item_tax.get("tax_rate", 0), + scrubbed_tax_fields[tax + " Amount"]: item_tax.get("tax_amount", 0), } ) if item_tax.get("is_other_charges"): @@ -404,15 +411,18 @@ def get_items(filters, additional_query_columns, additional_conditions=None): `tabSales Invoice Item`.project, `tabSales Invoice Item`.item_code, `tabSales Invoice Item`.description, `tabSales Invoice Item`.`item_name`, `tabSales Invoice Item`.`item_group`, + `tabSales Invoice Item`.`item_name` as si_item_name, `tabSales Invoice Item`.`item_group` as si_item_group, + `tabItem`.`item_name` as i_item_name, `tabItem`.`item_group` as i_item_group, `tabSales Invoice Item`.sales_order, `tabSales Invoice Item`.delivery_note, `tabSales Invoice Item`.income_account, `tabSales Invoice Item`.cost_center, `tabSales Invoice Item`.stock_qty, `tabSales Invoice Item`.stock_uom, `tabSales Invoice Item`.base_net_rate, `tabSales Invoice Item`.base_net_amount, `tabSales Invoice`.customer_name, `tabSales Invoice`.customer_group, `tabSales Invoice Item`.so_detail, `tabSales Invoice`.update_stock, `tabSales Invoice Item`.uom, `tabSales Invoice Item`.qty {0} - from `tabSales Invoice`, `tabSales Invoice Item` - where `tabSales Invoice`.name = `tabSales Invoice Item`.parent - and `tabSales Invoice`.docstatus = 1 {1} + from `tabSales Invoice`, `tabSales Invoice Item`, `tabItem` + where `tabSales Invoice`.name = `tabSales Invoice Item`.parent and + `tabItem`.name = `tabSales Invoice Item`.`item_code` and + `tabSales Invoice`.docstatus = 1 {1} """.format( additional_query_columns or "", conditions ), From 0bcd0476a24b5c75b03013d1b897ba7c93b1a205 Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Wed, 28 Jun 2023 21:00:02 +0530 Subject: [PATCH 12/12] fix: asset movement (backport #35918) (#35924) * fix: asset movement (#35918) fix: asset movement fixes (cherry picked from commit e16c14863b52aaa7856c799ad64fe977d4a4fbbe) # Conflicts: # erpnext/assets/doctype/asset_movement/asset_movement.py * chore: fix conflict --------- Co-authored-by: Anand Baburajan --- .../doctype/asset_movement/asset_movement.js | 18 +++++++++------- .../asset_movement/asset_movement.json | 7 +++++-- .../doctype/asset_movement/asset_movement.py | 20 +++++++----------- .../asset_movement/test_asset_movement.py | 21 ++++++++++++++----- 4 files changed, 38 insertions(+), 28 deletions(-) diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.js b/erpnext/assets/doctype/asset_movement/asset_movement.js index 2df7db974469..f9c600731b3c 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.js +++ b/erpnext/assets/doctype/asset_movement/asset_movement.js @@ -70,19 +70,21 @@ frappe.ui.form.on('Asset Movement', { else if (frm.doc.purpose === 'Issue') { fieldnames_to_be_altered = { target_location: { read_only: 1, reqd: 0 }, - source_location: { read_only: 1, reqd: 1 }, + source_location: { read_only: 1, reqd: 0 }, from_employee: { read_only: 1, reqd: 0 }, to_employee: { read_only: 0, reqd: 1 } }; } - Object.keys(fieldnames_to_be_altered).forEach(fieldname => { - let property_to_be_altered = fieldnames_to_be_altered[fieldname]; - Object.keys(property_to_be_altered).forEach(property => { - let value = property_to_be_altered[property]; - frm.set_df_property(fieldname, property, value, cdn, 'assets'); + if (fieldnames_to_be_altered) { + Object.keys(fieldnames_to_be_altered).forEach(fieldname => { + let property_to_be_altered = fieldnames_to_be_altered[fieldname]; + Object.keys(property_to_be_altered).forEach(property => { + let value = property_to_be_altered[property]; + frm.fields_dict['assets'].grid.update_docfield_property(fieldname, property, value); + }); }); - }); - frm.refresh_field('assets'); + frm.refresh_field('assets'); + } } }); diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.json b/erpnext/assets/doctype/asset_movement/asset_movement.json index bdce639b0398..5382f9e75f26 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.json +++ b/erpnext/assets/doctype/asset_movement/asset_movement.json @@ -37,6 +37,7 @@ "reqd": 1 }, { + "default": "Now", "fieldname": "transaction_date", "fieldtype": "Datetime", "in_list_view": 1, @@ -95,10 +96,11 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2021-01-22 12:30:55.295670", + "modified": "2023-06-28 16:54:26.571083", "modified_by": "Administrator", "module": "Assets", "name": "Asset Movement", + "naming_rule": "Expression", "owner": "Administrator", "permissions": [ { @@ -148,5 +150,6 @@ } ], "sort_field": "modified", - "sort_order": "DESC" + "sort_order": "DESC", + "states": [] } \ No newline at end of file diff --git a/erpnext/assets/doctype/asset_movement/asset_movement.py b/erpnext/assets/doctype/asset_movement/asset_movement.py index e61efadb1236..d8b772a6cde3 100644 --- a/erpnext/assets/doctype/asset_movement/asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/asset_movement.py @@ -28,26 +28,20 @@ def validate_asset(self): def validate_location(self): for d in self.assets: if self.purpose in ["Transfer", "Issue"]: - if not d.source_location: - d.source_location = frappe.db.get_value("Asset", d.asset, "location") - - if not d.source_location: - frappe.throw(_("Source Location is required for the Asset {0}").format(d.asset)) - + current_location = frappe.db.get_value("Asset", d.asset, "location") if d.source_location: - current_location = frappe.db.get_value("Asset", d.asset, "location") - if current_location != d.source_location: frappe.throw( _("Asset {0} does not belongs to the location {1}").format(d.asset, d.source_location) ) + else: + d.source_location = current_location if self.purpose == "Issue": if d.target_location: frappe.throw( _( - "Issuing cannot be done to a location. \ - Please enter employee who has issued Asset {0}" + "Issuing cannot be done to a location. Please enter employee to issue the Asset {0} to" ).format(d.asset), title="Incorrect Movement Purpose", ) @@ -110,12 +104,12 @@ def validate_employee(self): ) def on_submit(self): - self.set_latest_location_in_asset() + self.set_latest_location_and_custodian_in_asset() def on_cancel(self): - self.set_latest_location_in_asset() + self.set_latest_location_and_custodian_in_asset() - def set_latest_location_in_asset(self): + def set_latest_location_and_custodian_in_asset(self): current_location, current_employee = "", "" cond = "1=1" diff --git a/erpnext/assets/doctype/asset_movement/test_asset_movement.py b/erpnext/assets/doctype/asset_movement/test_asset_movement.py index a5fe52cefa2d..d707a67f7972 100644 --- a/erpnext/assets/doctype/asset_movement/test_asset_movement.py +++ b/erpnext/assets/doctype/asset_movement/test_asset_movement.py @@ -47,7 +47,7 @@ def test_movement(self): if not frappe.db.exists("Location", "Test Location 2"): frappe.get_doc({"doctype": "Location", "location_name": "Test Location 2"}).insert() - movement1 = create_asset_movement( + create_asset_movement( purpose="Transfer", company=asset.company, assets=[ @@ -58,7 +58,7 @@ def test_movement(self): ) self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2") - create_asset_movement( + movement1 = create_asset_movement( purpose="Transfer", company=asset.company, assets=[ @@ -70,21 +70,32 @@ def test_movement(self): self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location") movement1.cancel() - self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location") + self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location 2") employee = make_employee("testassetmovemp@example.com", company="_Test Company") create_asset_movement( purpose="Issue", company=asset.company, - assets=[{"asset": asset.name, "source_location": "Test Location", "to_employee": employee}], + assets=[{"asset": asset.name, "source_location": "Test Location 2", "to_employee": employee}], reference_doctype="Purchase Receipt", reference_name=pr.name, ) - # after issuing asset should belong to an employee not at a location + # after issuing, asset should belong to an employee not at a location self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), None) self.assertEqual(frappe.db.get_value("Asset", asset.name, "custodian"), employee) + create_asset_movement( + purpose="Receipt", + company=asset.company, + assets=[{"asset": asset.name, "from_employee": employee, "target_location": "Test Location"}], + reference_doctype="Purchase Receipt", + reference_name=pr.name, + ) + + # after receiving, asset should belong to a location not at an employee + self.assertEqual(frappe.db.get_value("Asset", asset.name, "location"), "Test Location") + def test_last_movement_cancellation(self): pr = make_purchase_receipt( item_code="Macbook Pro", qty=1, rate=100000.0, location="Test Location"