From 5bd6c27b052cc42a36688d5ac791724b02b5996f Mon Sep 17 00:00:00 2001 From: Anand Baburajan Date: Sat, 2 Sep 2023 18:32:23 +0530 Subject: [PATCH 1/3] chore: patch to correct asset values if je has workflow [v13] (#36916) chore: patch to correct asset values if je has workflow --- erpnext/patches.txt | 1 + ...correct_asset_value_if_je_with_workflow.py | 119 ++++++++++++++++++ 2 files changed, 120 insertions(+) create mode 100644 erpnext/patches/v13_0/correct_asset_value_if_je_with_workflow.py diff --git a/erpnext/patches.txt b/erpnext/patches.txt index 79ec14a28fb..caeca697e06 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -377,3 +377,4 @@ execute:frappe.db.set_value("Naming Series", "Naming Series", {"select_doc_for_s erpnext.patches.v13_0.update_schedule_type_in_loans erpnext.patches.v13_0.update_asset_value_for_manual_depr_entries erpnext.patches.v13_0.update_docs_link +erpnext.patches.v13_0.correct_asset_value_if_je_with_workflow diff --git a/erpnext/patches/v13_0/correct_asset_value_if_je_with_workflow.py b/erpnext/patches/v13_0/correct_asset_value_if_je_with_workflow.py new file mode 100644 index 00000000000..aededa2287d --- /dev/null +++ b/erpnext/patches/v13_0/correct_asset_value_if_je_with_workflow.py @@ -0,0 +1,119 @@ +import frappe +from frappe.model.workflow import get_workflow_name +from frappe.query_builder.functions import IfNull, Sum + + +def execute(): + active_je_workflow = get_workflow_name("Journal Entry") + if not active_je_workflow: + return + + correct_value_for_assets_with_manual_depr_entries() + + finance_books = frappe.db.get_all("Finance Book", pluck="name") + + if finance_books: + for fb_name in finance_books: + correct_value_for_assets_with_auto_depr(fb_name) + + correct_value_for_assets_with_auto_depr() + + +def correct_value_for_assets_with_manual_depr_entries(): + asset = frappe.qb.DocType("Asset") + gle = frappe.qb.DocType("GL Entry") + aca = frappe.qb.DocType("Asset Category Account") + company = frappe.qb.DocType("Company") + + asset_details_and_depr_amount_map = ( + frappe.qb.from_(gle) + .join(asset) + .on(gle.against_voucher == asset.name) + .join(aca) + .on((aca.parent == asset.asset_category) & (aca.company_name == asset.company)) + .join(company) + .on(company.name == asset.company) + .select( + asset.name.as_("asset_name"), + asset.gross_purchase_amount.as_("gross_purchase_amount"), + asset.opening_accumulated_depreciation.as_("opening_accumulated_depreciation"), + Sum(gle.debit).as_("depr_amount"), + ) + .where( + gle.account == IfNull(aca.depreciation_expense_account, company.depreciation_expense_account) + ) + .where(gle.debit != 0) + .where(gle.is_cancelled == 0) + .where(asset.docstatus == 1) + .where(asset.calculate_depreciation == 0) + .groupby(asset.name) + ) + + frappe.qb.update(asset).join(asset_details_and_depr_amount_map).on( + asset_details_and_depr_amount_map.asset_name == asset.name + ).set( + asset.value_after_depreciation, + asset_details_and_depr_amount_map.gross_purchase_amount + - asset_details_and_depr_amount_map.opening_accumulated_depreciation + - asset_details_and_depr_amount_map.depr_amount, + ).run() + + +def correct_value_for_assets_with_auto_depr(fb_name=None): + asset = frappe.qb.DocType("Asset") + gle = frappe.qb.DocType("GL Entry") + aca = frappe.qb.DocType("Asset Category Account") + company = frappe.qb.DocType("Company") + afb = frappe.qb.DocType("Asset Finance Book") + + asset_details_and_depr_amount_map = ( + frappe.qb.from_(gle) + .join(asset) + .on(gle.against_voucher == asset.name) + .join(aca) + .on((aca.parent == asset.asset_category) & (aca.company_name == asset.company)) + .join(company) + .on(company.name == asset.company) + .select( + asset.name.as_("asset_name"), + asset.gross_purchase_amount.as_("gross_purchase_amount"), + asset.opening_accumulated_depreciation.as_("opening_accumulated_depreciation"), + Sum(gle.debit).as_("depr_amount"), + ) + .where( + gle.account == IfNull(aca.depreciation_expense_account, company.depreciation_expense_account) + ) + .where(gle.debit != 0) + .where(gle.is_cancelled == 0) + .where(asset.docstatus == 1) + .where(asset.calculate_depreciation == 1) + .groupby(asset.name) + ) + + if fb_name: + asset_details_and_depr_amount_map = asset_details_and_depr_amount_map.where( + gle.finance_book == fb_name + ) + else: + asset_details_and_depr_amount_map = asset_details_and_depr_amount_map.where( + (gle.finance_book.isin([""])) | (gle.finance_book.isnull()) + ) + + query = ( + frappe.qb.update(afb) + .join(asset_details_and_depr_amount_map) + .on(asset_details_and_depr_amount_map.asset_name == afb.parent) + .set( + afb.value_after_depreciation, + asset_details_and_depr_amount_map.gross_purchase_amount + - asset_details_and_depr_amount_map.opening_accumulated_depreciation + - asset_details_and_depr_amount_map.depr_amount, + ) + ) + + if fb_name: + query = query.where(afb.finance_book == fb_name) + else: + query = query.where((afb.finance_book.isin([""])) | (afb.finance_book.isnull())) + + query.run() From 6f40d0cdf6ac1049043368794b0c0e17203d27ea Mon Sep 17 00:00:00 2001 From: Anand Baburajan Date: Tue, 5 Sep 2023 12:43:09 +0530 Subject: [PATCH 2/3] fix: update repay_from_salary, payment_account and payroll_payable_account fields (#36949) * fix: update repay_from_salary, payment_account and payroll_payable_account fields * chore: formatting --- .../doctype/loan_repayment/loan_repayment.json | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json index 71f93e26bdb..99997170140 100644 --- a/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json +++ b/erpnext/loan_management/doctype/loan_repayment/loan_repayment.json @@ -15,7 +15,6 @@ "posting_date", "clearance_date", "rate_of_interest", - "payroll_payable_account", "is_term_loan", "repay_from_salary", "payment_details_section", @@ -41,6 +40,7 @@ "amended_from", "accounting_details_section", "payment_account", + "payroll_payable_account", "penalty_income_account", "column_break_36", "loan_account" @@ -263,6 +263,7 @@ { "default": "0", "fetch_from": "against_loan.repay_from_salary", + "fetch_if_empty": 1, "fieldname": "repay_from_salary", "fieldtype": "Check", "label": "Repay From Salary" @@ -280,6 +281,7 @@ "label": "Accounting Details" }, { + "depends_on": "eval:!doc.repay_from_salary", "fetch_from": "against_loan.payment_account", "fetch_if_empty": 1, "fieldname": "payment_account", From 3a71fa9d96b4e5e9912d7a2e846928b155ca631d Mon Sep 17 00:00:00 2001 From: "mergify[bot]" <37929162+mergify[bot]@users.noreply.github.com> Date: Tue, 5 Sep 2023 18:14:49 +0530 Subject: [PATCH 3/3] fix: ask for asset related accounts only when needed (backport #36960) (#36972) fix: ask for asset related accounts only when needed (#36960) * fix: only ask for asset_received_but_not_billed account when needed * chore: remove unnecessary if condition * fix: only ask for expenses_included_in_asset_valuation account when needed (cherry picked from commit 174f95d699fde51185868864cdc74e792d2ff686) Co-authored-by: Anand Baburajan --- .../purchase_invoice/purchase_invoice.py | 94 ++++++++++--------- 1 file changed, 51 insertions(+), 43 deletions(-) diff --git a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py index bd63c69831f..94792e6eb13 100644 --- a/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py +++ b/erpnext/accounts/doctype/purchase_invoice/purchase_invoice.py @@ -261,9 +261,7 @@ class PurchaseInvoice(BuyingController): stock_not_billed_account = self.get_company_default("stock_received_but_not_billed") stock_items = self.get_stock_items() - asset_items = [d.is_fixed_asset for d in self.items if d.is_fixed_asset] - if len(asset_items) > 0: - asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed") + asset_received_but_not_billed = None if self.update_stock: self.validate_item_code() @@ -357,6 +355,8 @@ class PurchaseInvoice(BuyingController): ) item.expense_account = asset_category_account elif item.is_fixed_asset and item.pr_detail: + if not asset_received_but_not_billed: + asset_received_but_not_billed = self.get_company_default("asset_received_but_not_billed") item.expense_account = asset_received_but_not_billed elif not item.expense_account and for_validate: throw(_("Expense account is mandatory for item {0}").format(item.item_code or item.item_name)) @@ -924,8 +924,9 @@ class PurchaseInvoice(BuyingController): ) def get_asset_gl_entry(self, gl_entries): - arbnb_account = self.get_company_default("asset_received_but_not_billed") - eiiav_account = self.get_company_default("expenses_included_in_asset_valuation") + arbnb_account = None + eiiav_account = None + asset_eiiav_currency = None for item in self.get("items"): if item.is_fixed_asset: @@ -937,6 +938,8 @@ class PurchaseInvoice(BuyingController): "Asset Received But Not Billed", "Fixed Asset", ]: + if not arbnb_account: + arbnb_account = self.get_company_default("asset_received_but_not_billed") item.expense_account = arbnb_account if not self.update_stock: @@ -959,7 +962,10 @@ class PurchaseInvoice(BuyingController): ) if item.item_tax_amount: - asset_eiiav_currency = get_account_currency(eiiav_account) + if not eiiav_account or not asset_eiiav_currency: + eiiav_account = self.get_company_default("expenses_included_in_asset_valuation") + asset_eiiav_currency = get_account_currency(eiiav_account) + gl_entries.append( self.get_gl_dict( { @@ -1002,7 +1008,10 @@ class PurchaseInvoice(BuyingController): ) if item.item_tax_amount and not cint(erpnext.is_perpetual_inventory_enabled(self.company)): - asset_eiiav_currency = get_account_currency(eiiav_account) + if not eiiav_account or not asset_eiiav_currency: + eiiav_account = self.get_company_default("expenses_included_in_asset_valuation") + asset_eiiav_currency = get_account_currency(eiiav_account) + gl_entries.append( self.get_gl_dict( { @@ -1022,47 +1031,46 @@ class PurchaseInvoice(BuyingController): ) ) - # When update stock is checked # Assets are bought through this document then it will be linked to this document - if self.update_stock: - if flt(item.landed_cost_voucher_amount): - gl_entries.append( - self.get_gl_dict( - { - "account": eiiav_account, - "against": cwip_account, - "cost_center": item.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "credit": flt(item.landed_cost_voucher_amount), - "project": item.project or self.project, - }, - item=item, - ) - ) + if flt(item.landed_cost_voucher_amount): + if not eiiav_account: + eiiav_account = self.get_company_default("expenses_included_in_asset_valuation") - gl_entries.append( - self.get_gl_dict( - { - "account": cwip_account, - "against": eiiav_account, - "cost_center": item.cost_center, - "remarks": self.get("remarks") or _("Accounting Entry for Stock"), - "debit": flt(item.landed_cost_voucher_amount), - "project": item.project or self.project, - }, - item=item, - ) + gl_entries.append( + self.get_gl_dict( + { + "account": eiiav_account, + "against": cwip_account, + "cost_center": item.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "credit": flt(item.landed_cost_voucher_amount), + "project": item.project or self.project, + }, + item=item, ) - - # update gross amount of assets bought through this document - assets = frappe.db.get_all( - "Asset", filters={"purchase_invoice": self.name, "item_code": item.item_code} ) - for asset in assets: - frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate)) - frappe.db.set_value( - "Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate) + + gl_entries.append( + self.get_gl_dict( + { + "account": cwip_account, + "against": eiiav_account, + "cost_center": item.cost_center, + "remarks": self.get("remarks") or _("Accounting Entry for Stock"), + "debit": flt(item.landed_cost_voucher_amount), + "project": item.project or self.project, + }, + item=item, ) + ) + + # update gross amount of assets bought through this document + assets = frappe.db.get_all( + "Asset", filters={"purchase_invoice": self.name, "item_code": item.item_code} + ) + for asset in assets: + frappe.db.set_value("Asset", asset.name, "gross_purchase_amount", flt(item.valuation_rate)) + frappe.db.set_value("Asset", asset.name, "purchase_receipt_amount", flt(item.valuation_rate)) return gl_entries