diff --git a/asset/asset/doctype/depreciation_schedule/depreciation_schedule.json b/asset/asset/doctype/depreciation_schedule/depreciation_schedule.json index 182b54f..5398f37 100644 --- a/asset/asset/doctype/depreciation_schedule/depreciation_schedule.json +++ b/asset/asset/doctype/depreciation_schedule/depreciation_schedule.json @@ -9,6 +9,7 @@ "field_order": [ "schedule_date", "depreciation_amount", + "finance_book_id", "column_break_3", "accumulated_depreciation_amount", "journal_entry", @@ -64,11 +65,19 @@ "fieldtype": "Link", "label": "Shift", "options": "Asset Shift Factor" + }, + { + "fieldname": "finance_book_id", + "fieldtype": "Int", + "hidden": 1, + "label": "Finance Book Id", + "print_hide": 1, + "read_only": 1 } ], "istable": 1, "links": [], - "modified": "2024-03-27 13:06:51.227001", + "modified": "2024-08-01 17:27:38.205287", "modified_by": "Administrator", "module": "Asset", "name": "Depreciation Schedule", diff --git a/asset/asset/form_tour/item/item.json b/asset/asset/form_tour/item/item.json new file mode 100644 index 0000000..f7e8783 --- /dev/null +++ b/asset/asset/form_tour/item/item.json @@ -0,0 +1,105 @@ +{ + "creation": "2021-08-24 17:56:40.754909", + "docstatus": 0, + "doctype": "Form Tour", + "first_document": 0, + "idx": 0, + "include_name_field": 0, + "is_standard": 1, + "modified": "2021-11-24 17:59:44.559001", + "modified_by": "Administrator", + "module": "Asset", + "name": "Item", + "owner": "Administrator", + "reference_doctype": "Item", + "save_on_complete": 1, + "steps": [ + { + "description": "Enter code for Asset Item", + "field": "", + "fieldname": "item_code", + "fieldtype": "Data", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Item Code", + "parent_field": "", + "position": "Bottom", + "title": "Asset Item Code" + }, + { + "description": "Enter name for Asset Item", + "field": "", + "fieldname": "item_name", + "fieldtype": "Data", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Item Name", + "parent_field": "", + "position": "Bottom", + "title": "Asset Item Name" + }, + { + "description": "Select an Item Group", + "field": "", + "fieldname": "item_group", + "fieldtype": "Link", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Item Group", + "parent_field": "", + "position": "Right", + "title": "Item Group" + }, + { + "description": "Check this field to make this an Asset Item", + "field": "", + "fieldname": "is_fixed_asset", + "fieldtype": "Check", + "has_next_condition": 1, + "is_table_field": 0, + "label": "Is Fixed Asset", + "next_step_condition": "eval:doc.is_fixed_asset", + "parent_field": "", + "position": "Bottom", + "title": "Is this a Fixed Asset?" + }, + { + "description": "On checking it, the system will create an Asset automatically on purchase", + "field": "", + "fieldname": "auto_create_assets", + "fieldtype": "Check", + "has_next_condition": 1, + "is_table_field": 0, + "label": "Auto Create Assets on Purchase", + "next_step_condition": "eval:doc.auto_create_assets", + "parent_field": "", + "position": "Bottom", + "title": "Auto Create Asset on Purchase" + }, + { + "description": "Select an Asset Category for this Asset Item", + "field": "", + "fieldname": "asset_category", + "fieldtype": "Link", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Asset Category", + "parent_field": "", + "position": "Left", + "title": "Asset Category" + }, + { + "description": "Select a naming series which will be used to create an Asset automatically", + "field": "", + "fieldname": "asset_naming_series", + "fieldtype": "Select", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Asset Naming Series", + "parent_field": "", + "position": "Left", + "title": "Asset Naming Series" + } + ], + "title": "Item" +} \ No newline at end of file diff --git a/asset/asset/form_tour/purchase_receipt/purchase_receipt.json b/asset/asset/form_tour/purchase_receipt/purchase_receipt.json new file mode 100644 index 0000000..40179a3 --- /dev/null +++ b/asset/asset/form_tour/purchase_receipt/purchase_receipt.json @@ -0,0 +1,41 @@ +{ + "creation": "2021-08-24 13:03:21.333088", + "docstatus": 0, + "doctype": "Form Tour", + "idx": 0, + "is_standard": 1, + "modified": "2021-08-24 13:03:21.333088", + "modified_by": "Administrator", + "module": "Asset", + "name": "Purchase Receipt", + "owner": "Administrator", + "reference_doctype": "Purchase Receipt", + "save_on_complete": 0, + "steps": [ + { + "description": "Select Asset Supplier", + "field": "", + "fieldname": "supplier", + "fieldtype": "Link", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Supplier", + "parent_field": "", + "position": "Bottom", + "title": "Supplier" + }, + { + "description": "Select an Asset Item, Enter rate and quantity", + "field": "", + "fieldname": "items", + "fieldtype": "Table", + "has_next_condition": 0, + "is_table_field": 0, + "label": "Items", + "parent_field": "", + "position": "Bottom", + "title": "Items" + } + ], + "title": "Purchase Receipt" +} \ No newline at end of file diff --git a/asset/asset/patches/post_install/add_index_on_nestedset_doctypes.py b/asset/asset/patches/post_install/add_index_on_nestedset_doctypes.py deleted file mode 100644 index 09649e6..0000000 --- a/asset/asset/patches/post_install/add_index_on_nestedset_doctypes.py +++ /dev/null @@ -1,10 +0,0 @@ -import frappe - - -def execute(): - frappe.reload_doc("asset", "doctype", "Location") - for dt in ( - "Location" - ): - frappe.reload_doctype(dt) - frappe.get_doc("DocType", dt).run_module_method("on_doctype_update") \ No newline at end of file diff --git a/asset/install.py b/asset/install.py index f78384d..860274e 100644 --- a/asset/install.py +++ b/asset/install.py @@ -8,7 +8,7 @@ def after_install(): print("Setting up Frappe Asset...") setup() - click.secho("Thank you for installing Frappe Asset!", fg="green") + click.secho("Thank you for installing Frappe Fixed Asset!", fg="green") except Exception as e: click.secho( diff --git a/asset/patches.txt b/asset/patches.txt index f15c3a9..7c348d6 100644 --- a/asset/patches.txt +++ b/asset/patches.txt @@ -1,6 +1,16 @@ [pre_model_sync] -# Patches added in this section will be executed before doctypes are migrated -# Read docs to understand patches: https://frappeframework.com/docs/v14/user/en/database-migrations [post_model_sync] -# Patches added in this section will be executed after doctypes are migrated \ No newline at end of file +asset.patches.v15_0.correct_asset_value_if_je_with_workflow +asset.patches.v15_0.create_asset_depreciation_schedules_from_assets +asset.patches.v15_0.delete_orphaned_asset_movement_item_records +asset.patches.v15_0.remove_cancelled_asset_capitalization_from_asset +asset.patches.v15_0.rename_daily_depreciation_to_depreciation_amount_based_on_num_days_in_month +asset.patches.v15_0.rename_depreciation_amount_based_on_num_days_in_month_to_daily_prorata_based +asset.patches.v15_0.rename_number_of_depreciations_booked_to_opening_booked_depreciations +asset.patches.v15_0.rename_purchase_receipt_amount_to_purchase_amount +asset.patches.v15_0.update_asset_repair_field_in_stock_entry +asset.patches.v15_0.update_asset_value_for_manual_depr_entries +asset.patches.v15_0.update_gpa_and_ndb_for_assdeprsch +asset.patches.v15_0.update_total_number_of_booked_depreciations +asset.patches.v15_0.update_warehouse_field_in_asset_repair_consumed_item_doctype \ No newline at end of file diff --git a/asset/patches/post_install/create_accounting_dimensions_for_asset_capitalization.py b/asset/patches/post_install/create_accounting_dimensions_for_asset_capitalization.py new file mode 100644 index 0000000..09e20a9 --- /dev/null +++ b/asset/patches/post_install/create_accounting_dimensions_for_asset_capitalization.py @@ -0,0 +1,31 @@ +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_field + + +def execute(): + accounting_dimensions = frappe.db.get_all( + "Accounting Dimension", fields=["fieldname", "label", "document_type", "disabled"] + ) + + if not accounting_dimensions: + return + + doctype = "Asset Capitalization" + + for d in accounting_dimensions: + field = frappe.db.get_value("Custom Field", {"dt": doctype, "fieldname": d.fieldname}) + + if field: + continue + + df = { + "fieldname": d.fieldname, + "label": d.label, + "fieldtype": "Link", + "options": d.document_type, + "insert_after": "accounting_dimensions_section", + } + + create_custom_field(doctype, df, ignore_validate=True) + + frappe.clear_cache(doctype=doctype) diff --git a/asset/asset/patches/post_install/create_accounting_dimensions_for_asset_repair.py b/asset/patches/post_install/create_accounting_dimensions_for_asset_repair.py similarity index 100% rename from asset/asset/patches/post_install/create_accounting_dimensions_for_asset_repair.py rename to asset/patches/post_install/create_accounting_dimensions_for_asset_repair.py diff --git a/asset/asset/patches/post_install/make_asset_finance_book_against_old_entries.py b/asset/patches/post_install/make_asset_finance_book_against_old_entries.py similarity index 100% rename from asset/asset/patches/post_install/make_asset_finance_book_against_old_entries.py rename to asset/patches/post_install/make_asset_finance_book_against_old_entries.py diff --git a/asset/asset/patches/post_install/make_location_from_warehouse.py b/asset/patches/post_install/make_location_from_warehouse.py similarity index 100% rename from asset/asset/patches/post_install/make_location_from_warehouse.py rename to asset/patches/post_install/make_location_from_warehouse.py diff --git a/asset/asset/patches/post_install/merge_land_unit_with_location.py b/asset/patches/post_install/merge_land_unit_with_location.py similarity index 87% rename from asset/asset/patches/post_install/merge_land_unit_with_location.py rename to asset/patches/post_install/merge_land_unit_with_location.py index 2587e09..b2151ff 100644 --- a/asset/asset/patches/post_install/merge_land_unit_with_location.py +++ b/asset/patches/post_install/merge_land_unit_with_location.py @@ -18,13 +18,6 @@ def execute(): frappe.reload_doc("asset", "doctype", "linked_location") - if not frappe.db.table_exists("Crop Cycle"): - frappe.reload_doc("agriculture", "doctype", "crop_cycle") - - # Rename the fields in related doctypes - if "linked_land_unit" in frappe.db.get_table_columns("Crop Cycle"): - rename_field("Crop Cycle", "linked_land_unit", "linked_location") - if "land_unit" in frappe.db.get_table_columns("Linked Location"): rename_field("Linked Location", "land_unit", "location") diff --git a/asset/asset/patches/post_install/rename_asset_adjustment_doctype.py b/asset/patches/post_install/rename_asset_adjustment_doctype.py similarity index 100% rename from asset/asset/patches/post_install/rename_asset_adjustment_doctype.py rename to asset/patches/post_install/rename_asset_adjustment_doctype.py diff --git a/asset/patches/post_install/set_cwip_and_delete_asset_settings.py b/asset/patches/post_install/set_cwip_and_delete_asset_settings.py new file mode 100644 index 0000000..952f64b --- /dev/null +++ b/asset/patches/post_install/set_cwip_and_delete_asset_settings.py @@ -0,0 +1,16 @@ +import frappe +from frappe.utils import cint + + +def execute(): + """Get 'Disable CWIP Accounting value' from Asset Settings, set it in 'Enable Capital Work in Progress Accounting' field + in Company, delete Asset Settings""" + + if frappe.db.exists("DocType", "Asset Settings"): + frappe.reload_doctype("Asset Category") + cwip_value = frappe.db.get_single_value("Asset Settings", "disable_cwip_accounting") + + frappe.db.sql("""UPDATE `tabAsset Category` SET enable_cwip_accounting = %s""", cint(cwip_value)) + + frappe.db.sql("""DELETE FROM `tabSingles` where doctype = 'Asset Settings'""") + frappe.delete_doc_if_exists("DocType", "Asset Settings") diff --git a/asset/patches/post_install/update_asset_quantity_field.py b/asset/patches/post_install/update_asset_quantity_field.py new file mode 100644 index 0000000..265a3bb --- /dev/null +++ b/asset/patches/post_install/update_asset_quantity_field.py @@ -0,0 +1,8 @@ +import frappe + + +def execute(): + if frappe.db.count("Asset"): + frappe.reload_doc("assets", "doctype", "Asset") + asset = frappe.qb.DocType("Asset") + frappe.qb.update(asset).set(asset.asset_quantity, 1).run() diff --git a/asset/patches/post_install/update_total_asset_cost_field.py b/asset/patches/post_install/update_total_asset_cost_field.py new file mode 100644 index 0000000..57cf71b --- /dev/null +++ b/asset/patches/post_install/update_total_asset_cost_field.py @@ -0,0 +1,17 @@ +import frappe + + +def execute(): + asset = frappe.qb.DocType("Asset") + frappe.qb.update(asset).set(asset.total_asset_cost, asset.gross_purchase_amount).run() + + asset_repair_list = frappe.db.get_all( + "Asset Repair", + filters={"docstatus": 1, "repair_status": "Completed", "capitalize_repair_cost": 1}, + fields=["asset", "repair_cost"], + ) + + for asset_repair in asset_repair_list: + frappe.qb.update(asset).set( + asset.total_asset_cost, asset.total_asset_cost + asset_repair.repair_cost + ).where(asset.name == asset_repair.asset).run() diff --git a/asset/patches/post_install/update_zero_asset_quantity_field.py b/asset/patches/post_install/update_zero_asset_quantity_field.py new file mode 100644 index 0000000..0480f9b --- /dev/null +++ b/asset/patches/post_install/update_zero_asset_quantity_field.py @@ -0,0 +1,6 @@ +import frappe + + +def execute(): + asset = frappe.qb.DocType("Asset") + frappe.qb.update(asset).set(asset.asset_quantity, 1).where(asset.asset_quantity == 0).run() diff --git a/asset/patches/v15_0/correct_asset_value_if_je_with_workflow.py b/asset/patches/v15_0/correct_asset_value_if_je_with_workflow.py new file mode 100644 index 0000000..dba27b4 --- /dev/null +++ b/asset/patches/v15_0/correct_asset_value_if_je_with_workflow.py @@ -0,0 +1,115 @@ +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() diff --git a/asset/asset/patches/post_install/create_asset_depreciation_schedules_from_assets.py b/asset/patches/v15_0/create_asset_depreciation_schedules_from_assets.py similarity index 100% rename from asset/asset/patches/post_install/create_asset_depreciation_schedules_from_assets.py rename to asset/patches/v15_0/create_asset_depreciation_schedules_from_assets.py diff --git a/asset/patches/v15_0/delete_orphaned_asset_movement_item_records.py b/asset/patches/v15_0/delete_orphaned_asset_movement_item_records.py new file mode 100644 index 0000000..a1d7dc9 --- /dev/null +++ b/asset/patches/v15_0/delete_orphaned_asset_movement_item_records.py @@ -0,0 +1,11 @@ +import frappe + + +def execute(): + # nosemgrep + frappe.db.sql( + """ + DELETE FROM `tabAsset Movement Item` + WHERE parent NOT IN (SELECT name FROM `tabAsset Movement`) + """ + ) diff --git a/asset/patches/v15_0/remove_cancelled_asset_capitalization_from_asset.py b/asset/patches/v15_0/remove_cancelled_asset_capitalization_from_asset.py new file mode 100644 index 0000000..cb39a92 --- /dev/null +++ b/asset/patches/v15_0/remove_cancelled_asset_capitalization_from_asset.py @@ -0,0 +1,11 @@ +import frappe + + +def execute(): + cancelled_asset_capitalizations = frappe.get_all( + "Asset Capitalization", + filters={"docstatus": 2}, + fields=["name", "target_asset"], + ) + for asset_capitalization in cancelled_asset_capitalizations: + frappe.db.set_value("Asset", asset_capitalization.target_asset, "capitalized_in", None) diff --git a/asset/patches/v15_0/rename_daily_depreciation_to_depreciation_amount_based_on_num_days_in_month.py b/asset/patches/v15_0/rename_daily_depreciation_to_depreciation_amount_based_on_num_days_in_month.py new file mode 100644 index 0000000..63dc0e0 --- /dev/null +++ b/asset/patches/v15_0/rename_daily_depreciation_to_depreciation_amount_based_on_num_days_in_month.py @@ -0,0 +1,21 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + + +from frappe.model.utils.rename_field import rename_field + + +def execute(): + try: + rename_field( + "Asset Finance Book", "daily_depreciation", "depreciation_amount_based_on_num_days_in_month" + ) + rename_field( + "Asset Depreciation Schedule", + "daily_depreciation", + "depreciation_amount_based_on_num_days_in_month", + ) + + except Exception as e: + if e.args[0] != 1054: + raise diff --git a/asset/patches/v15_0/rename_depreciation_amount_based_on_num_days_in_month_to_daily_prorata_based.py b/asset/patches/v15_0/rename_depreciation_amount_based_on_num_days_in_month_to_daily_prorata_based.py new file mode 100644 index 0000000..2c03c23 --- /dev/null +++ b/asset/patches/v15_0/rename_depreciation_amount_based_on_num_days_in_month_to_daily_prorata_based.py @@ -0,0 +1,21 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + + +from frappe.model.utils.rename_field import rename_field + + +def execute(): + try: + rename_field( + "Asset Finance Book", "depreciation_amount_based_on_num_days_in_month", "daily_prorata_based" + ) + rename_field( + "Asset Depreciation Schedule", + "depreciation_amount_based_on_num_days_in_month", + "daily_prorata_based", + ) + + except Exception as e: + if e.args[0] != 1054: + raise diff --git a/asset/patches/v15_0/rename_number_of_depreciations_booked_to_opening_booked_depreciations.py b/asset/patches/v15_0/rename_number_of_depreciations_booked_to_opening_booked_depreciations.py new file mode 100644 index 0000000..1818337 --- /dev/null +++ b/asset/patches/v15_0/rename_number_of_depreciations_booked_to_opening_booked_depreciations.py @@ -0,0 +1,7 @@ +import frappe +from frappe.model.utils.rename_field import rename_field + + +def execute(): + if frappe.db.has_column("Asset", "number_of_depreciations_booked"): + rename_field("Asset", "number_of_depreciations_booked", "opening_number_of_booked_depreciations") diff --git a/asset/patches/v15_0/rename_purchase_receipt_amount_to_purchase_amount.py b/asset/patches/v15_0/rename_purchase_receipt_amount_to_purchase_amount.py new file mode 100644 index 0000000..ab287d0 --- /dev/null +++ b/asset/patches/v15_0/rename_purchase_receipt_amount_to_purchase_amount.py @@ -0,0 +1,8 @@ +import frappe +from frappe.model.utils.rename_field import rename_field + + +def execute(): + frappe.reload_doc("asset", "doctype", "asset") + if frappe.db.has_column("Asset", "purchase_receipt_amount"): + rename_field("Asset", "purchase_receipt_amount", "purchase_amount") diff --git a/asset/patches/v15_0/update_asset_repair_field_in_stock_entry.py b/asset/patches/v15_0/update_asset_repair_field_in_stock_entry.py new file mode 100644 index 0000000..cc0668d --- /dev/null +++ b/asset/patches/v15_0/update_asset_repair_field_in_stock_entry.py @@ -0,0 +1,15 @@ +import frappe +from frappe.query_builder import DocType + + +def execute(): + if frappe.db.has_column("Asset Repair", "stock_entry"): + AssetRepair = DocType("Asset Repair") + StockEntry = DocType("Stock Entry") + + ( + frappe.qb.update(StockEntry) + .join(AssetRepair) + .on(StockEntry.name == AssetRepair.stock_entry) + .set(StockEntry.asset_repair, AssetRepair.name) + ).run() diff --git a/asset/patches/v15_0/update_asset_value_for_manual_depr_entries.py b/asset/patches/v15_0/update_asset_value_for_manual_depr_entries.py new file mode 100644 index 0000000..9bdcda0 --- /dev/null +++ b/asset/patches/v15_0/update_asset_value_for_manual_depr_entries.py @@ -0,0 +1,32 @@ +import frappe +from frappe.query_builder.functions import IfNull, Sum + + +def execute(): + asset = frappe.qb.DocType("Asset") + gle = frappe.qb.DocType("GL Entry") + aca = frappe.qb.DocType("Asset Category Account") + company = frappe.qb.DocType("Company") + + asset_total_depr_value_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(Sum(gle.debit).as_("value"), asset.name.as_("asset_name")) + .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_total_depr_value_map).on( + asset_total_depr_value_map.asset_name == asset.name + ).set( + asset.value_after_depreciation, asset.value_after_depreciation - asset_total_depr_value_map.value + ).where(asset.docstatus == 1).where(asset.calculate_depreciation == 0).run() diff --git a/asset/patches/v15_0/update_gpa_and_ndb_for_assdeprsch.py b/asset/patches/v15_0/update_gpa_and_ndb_for_assdeprsch.py new file mode 100644 index 0000000..4399a95 --- /dev/null +++ b/asset/patches/v15_0/update_gpa_and_ndb_for_assdeprsch.py @@ -0,0 +1,20 @@ +import frappe + + +def execute(): + # not using frappe.qb because https://github.com/frappe/frappe/issues/20292 + frappe.db.sql( + """UPDATE `tabAsset Depreciation Schedule` + JOIN `tabAsset` + ON `tabAsset Depreciation Schedule`.`asset`=`tabAsset`.`name` + SET + `tabAsset Depreciation Schedule`.`gross_purchase_amount`=`tabAsset`.`gross_purchase_amount`, + `tabAsset Depreciation Schedule`.`opening_number_of_booked_depreciations`=`tabAsset`.`opening_number_of_booked_depreciations` + WHERE + ( + `tabAsset Depreciation Schedule`.`gross_purchase_amount`<>`tabAsset`.`gross_purchase_amount` + OR + `tabAsset Depreciation Schedule`.`opening_number_of_booked_depreciations`<>`tabAsset`.`opening_number_of_booked_depreciations` + ) + AND `tabAsset Depreciation Schedule`.`docstatus`<2""" + ) diff --git a/asset/patches/v15_0/update_total_number_of_booked_depreciations.py b/asset/patches/v15_0/update_total_number_of_booked_depreciations.py new file mode 100644 index 0000000..b8f70b3 --- /dev/null +++ b/asset/patches/v15_0/update_total_number_of_booked_depreciations.py @@ -0,0 +1,30 @@ +import frappe + +from asset.asset.doctype.asset_depreciation_schedule.asset_depreciation_schedule import ( + get_depr_schedule, +) + + +def execute(): + if frappe.db.has_column("Asset Finance Book", "total_number_of_booked_depreciations"): + assets = frappe.get_all( + "Asset", filters={"docstatus": 1}, fields=["name", "opening_number_of_booked_depreciations"] + ) + + for asset in assets: + asset_doc = frappe.get_doc("Asset", asset.name) + + for fb_row in asset_doc.get("finance_books"): + depr_schedule = get_depr_schedule(asset.name, "Active", fb_row.finance_book) + total_number_of_booked_depreciations = asset.opening_number_of_booked_depreciations or 0 + + if depr_schedule: + for je in depr_schedule: + if je.journal_entry: + total_number_of_booked_depreciations += 1 + frappe.db.set_value( + "Asset Finance Book", + fb_row.name, + "total_number_of_booked_depreciations", + total_number_of_booked_depreciations, + ) diff --git a/asset/patches/v15_0/update_warehouse_field_in_asset_repair_consumed_item_doctype.py b/asset/patches/v15_0/update_warehouse_field_in_asset_repair_consumed_item_doctype.py new file mode 100644 index 0000000..e029182 --- /dev/null +++ b/asset/patches/v15_0/update_warehouse_field_in_asset_repair_consumed_item_doctype.py @@ -0,0 +1,14 @@ +import frappe + + +# not able to use frappe.qb because of this bug https://github.com/frappe/frappe/issues/20292 +def execute(): + if frappe.db.has_column("Asset Repair", "warehouse"): + # nosemgrep + frappe.db.sql( + """UPDATE `tabAsset Repair Consumed Item` ar_item + JOIN `tabAsset Repair` ar + ON ar.name = ar_item.parent + SET ar_item.warehouse = ar.warehouse + WHERE ifnull(ar.warehouse, '') != ''""" + ) diff --git a/asset/setup.py b/asset/setup.py index 795b64e..15295dd 100644 --- a/asset/setup.py +++ b/asset/setup.py @@ -14,6 +14,7 @@ def after_migrate(): def after_install(): create_custom_fields() create_property_setter() + run_post_install_patches() def before_uninstall(): @@ -51,3 +52,35 @@ def delete_custom_fields(): cfs = frappe.db.get_values("Custom Field", filters={"module": ["in", module_list]}) for cf in cfs: frappe.delete_doc("Custom Field", cf[0]) + + +def get_post_install_patches(): + return ( + "erpnext.patches.v11_0.make_asset_finance_book_against_old_entries", + "erpnext.patches.v11_0.make_location_from_warehouse", + "erpnext.patches.v11_0.rename_asset_adjustment_doctype", + "erpnext.patches.v11_0.merge_land_unit_with_location", + "erpnext.patches.v12_0.set_cwip_and_delete_asset_settings", + "erpnext.patches.v13_0.create_accounting_dimensions_for_asset_repair", + "erpnext.patches.v13_0.update_asset_quantity_field", + "erpnext.patches.v14_0.create_accounting_dimensions_for_asset_capitalization", + "erpnext.patches.v14_0.update_total_asset_cost_field", + "erpnext.patches.v14_0.update_zero_asset_quantity_field", + ) + + +def run_post_install_patches(): + print("\nPatching Existing Data...") + + POST_INSTALL_PATCHES = get_post_install_patches() + frappe.flags.in_patch = True + + try: + for patch in POST_INSTALL_PATCHES: + patch_name = patch.split(".")[-1] + if not patch_name: + continue + + frappe.get_attr(f"asset.patches.post_install.{patch_name}.execute")() + finally: + frappe.flags.in_patch = False diff --git a/asset/uninstall.py b/asset/uninstall.py index 4d2c50d..b49ff69 100644 --- a/asset/uninstall.py +++ b/asset/uninstall.py @@ -5,7 +5,7 @@ def before_uninstall(): try: - print("Removing customizations created by the Frappe Asset app...") + print("Removing customizations created by the Frappe Fixed Asset app...") remove_custom_fields() except Exception as e: