From 8ef257abbc1fefa833697f0cc3a95d52bc34b7a4 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 14 Jun 2023 12:54:10 +0530 Subject: [PATCH 01/46] feat: Demo data creation --- erpnext/hooks.py | 2 + erpnext/setup/demo.py | 49 +++++++++++++++++++++++ erpnext/setup/demo_data/items.json | 62 ++++++++++++++++++++++++++++++ 3 files changed, 113 insertions(+) create mode 100644 erpnext/setup/demo.py create mode 100644 erpnext/setup/demo_data/items.json diff --git a/erpnext/hooks.py b/erpnext/hooks.py index c821fcf4e62..ad660405d35 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -70,6 +70,8 @@ treeviews = [ "Department", ] +demo_doctypes = ["items"] + jinja = { "methods": [ "erpnext.stock.serial_batch_bundle.get_serial_or_batch_nos", diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py new file mode 100644 index 00000000000..95e8a4d8bae --- /dev/null +++ b/erpnext/setup/demo.py @@ -0,0 +1,49 @@ +# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +import json +import os + +import frappe + + +@frappe.whitelist() +def setup_demo_data(): + create_demo_company() + process_demo_data() + make_transactions() + + +def create_demo_company(): + company = frappe.db.get_value("Company", {"docstatus": 0}) + company_doc = frappe.get_doc("Company", company) + + # Make a dummy company + new_company = frappe.new_doc("Company") + new_company.company_name = company_doc.company_name + " (Demo)" + new_company.abbr = company_doc.abbr + "D" + new_company.enable_perpetual_inventory = 1 + new_company.default_currency = company_doc.default_currency + new_company.country = company_doc.country + new_company.chart_of_accounts_based_on = "Standard Template" + new_company.chart_of_accounts = company_doc.chart_of_accounts + new_company.insert() + + +def process_demo_data(): + demo_doctypes = frappe.get_hooks("demo_doctypes") or [] + path = os.path.join(os.path.dirname(__file__), "demo_data") + for doctype in demo_doctypes: + with open(os.path.join(path, doctype + ".json"), "r") as f: + data = f.read() + if data: + for item in json.loads(data): + create_demo_record(item) + + +def create_demo_record(doctype): + frappe.get_doc(doctype).insert(ignore_permissions=True) + + +def make_transactions(): + pass diff --git a/erpnext/setup/demo_data/items.json b/erpnext/setup/demo_data/items.json new file mode 100644 index 00000000000..fed36e251ef --- /dev/null +++ b/erpnext/setup/demo_data/items.json @@ -0,0 +1,62 @@ +[ + { + "doctype": "Item", + "item_code": "SKU001", + "item_name": "T-shirt", + "image": "https://www.shutterstock.com/image-photo/close-man-blank-tshirt-140861086" + }, + { + "doctype": "Item", + "item_code": "SKU002", + "item_name": "Laptop", + "image": "https://www.shutterstock.com/image-photo/laptop-computer-blank-screen-isolated-on-1721445466" + }, + { + "doctype": "Item", + "item_code": "SKU003", + "item_name": "Book", + "image": "https://www.shutterstock.com/image-vector/blank-vertical-book-cover-template-pages-172777709" + }, + { + "doctype": "Item", + "item_code": "SKU004", + "item_name": "Smartphone", + "image": "https://www.shutterstock.com/image-vector/realistic-smartphone-mockup-front-back-1450789832" + }, + { + "doctype": "Item", + "item_code": "SKU005", + "item_name": "Sneakers", + "image": "https://www.shutterstock.com/image-photo/white-sneaker-sport-shoe-on-purple-2155395817" + }, + { + "doctype": "Item", + "item_code": "SKU006", + "item_name": "Coffee Mug", + "image": "https://www.shutterstock.com/image-vector/realistic-white-cup-isolated-on-transparent-585104080" + }, + { + "doctype": "Item", + "item_code": "SKU007", + "item_name": "Television", + "image": "https://www.shutterstock.com/image-photo/tv-flat-screen-lcd-plasma-realistic-314401364" + }, + { + "doctype": "Item", + "item_code": "SKU008", + "item_name": "Backpack", + "image": "https://www.shutterstock.com/image-photo/school-backpack-on-white-background-1440715766" + }, + { + "doctype": "Item", + "item_code": "SKU009", + "item_name": "Headphones", + "image": "https://www.shutterstock.com/image-illustration/3d-rendering-yellow-headphones-isolated-on-1833307018" + }, + { + "doctype": "Item", + "item_code": "SKU010", + "item_name": "Camera", + "image": "https://www.shutterstock.com/image-photo/camera-610909205" + } +] \ No newline at end of file From 77a29574a6e09273268cf2c6c6e102777447e20b Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 16 Jun 2023 13:43:55 +0530 Subject: [PATCH 02/46] fix: Create transactions --- erpnext/accounts/party.py | 1 + erpnext/hooks.py | 10 +- erpnext/setup/demo.py | 60 ++- erpnext/setup/demo_data/customer.json | 17 + erpnext/setup/demo_data/customer_group.json | 6 + erpnext/setup/demo_data/item.json | 71 +++ erpnext/setup/demo_data/item_group.json | 7 + erpnext/setup/demo_data/items.json | 62 --- erpnext/setup/demo_data/purchase_invoice.json | 17 + erpnext/setup/demo_data/sales_invoice.json | 17 + erpnext/setup/demo_data/supplier.json | 17 + erpnext/setup/demo_data/supplier_group.json | 6 + .../global_defaults/global_defaults.json | 434 ++++-------------- 13 files changed, 320 insertions(+), 405 deletions(-) create mode 100644 erpnext/setup/demo_data/customer.json create mode 100644 erpnext/setup/demo_data/customer_group.json create mode 100644 erpnext/setup/demo_data/item.json create mode 100644 erpnext/setup/demo_data/item_group.json delete mode 100644 erpnext/setup/demo_data/items.json create mode 100644 erpnext/setup/demo_data/purchase_invoice.json create mode 100644 erpnext/setup/demo_data/sales_invoice.json create mode 100644 erpnext/setup/demo_data/supplier.json create mode 100644 erpnext/setup/demo_data/supplier_group.json diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 07b865e66cd..933c70d5e1b 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -669,6 +669,7 @@ def get_payment_terms_template(party_name, party_type, company=None): if party_type not in ("Customer", "Supplier"): return template = None + print(party_type, party_name) if party_type == "Customer": customer = frappe.get_cached_value( "Customer", party_name, fieldname=["payment_terms", "customer_group"], as_dict=1 diff --git a/erpnext/hooks.py b/erpnext/hooks.py index ad660405d35..275c93d8acb 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -70,7 +70,15 @@ treeviews = [ "Department", ] -demo_doctypes = ["items"] +demo_master_doctypes = [ + "item_group", + "item", + "customer_group", + "supplier_group", + "customer", + "supplier", +] +demo_transaction_doctypes = ["purchase_invoice", "sales_invoice"] jinja = { "methods": [ diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index 95e8a4d8bae..1256b0e623e 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -6,12 +6,20 @@ import os import frappe +import erpnext + @frappe.whitelist() def setup_demo_data(): - create_demo_company() - process_demo_data() - make_transactions() + company = create_demo_company() + process_masters() + make_transactions(company) + + +@frappe.whitelist() +def clear_demo_data(): + company = frappe.db.get_single_value("Global Defaults", "demo_company") + create_transaction_deletion_record(company) def create_demo_company(): @@ -29,9 +37,12 @@ def create_demo_company(): new_company.chart_of_accounts = company_doc.chart_of_accounts new_company.insert() + frappe.db.set_single_value("Global Defaults", "demo_company", new_company.name) + return new_company.name -def process_demo_data(): - demo_doctypes = frappe.get_hooks("demo_doctypes") or [] + +def process_masters(): + demo_doctypes = frappe.get_hooks("demo_master_doctypes") or [] path = os.path.join(os.path.dirname(__file__), "demo_data") for doctype in demo_doctypes: with open(os.path.join(path, doctype + ".json"), "r") as f: @@ -45,5 +56,40 @@ def create_demo_record(doctype): frappe.get_doc(doctype).insert(ignore_permissions=True) -def make_transactions(): - pass +def make_transactions(company): + transaction_doctypes = frappe.get_hooks("demo_transaction_doctypes") or [] + path = os.path.join(os.path.dirname(__file__), "demo_data") + for transaction in transaction_doctypes: + with open(os.path.join(path, transaction + ".json"), "r") as f: + data = f.read() + if data: + for item in json.loads(data): + create_transaction(item, company) + + +def create_transaction(doctype, company): + doctype.update({"company": company}) + + income_account, expense_account = frappe.db.get_value( + "Company", company, ["default_income_account", "default_expense_account"] + ) + + for item in doctype.get("items"): + item.update( + { + "cost_center": erpnext.get_default_cost_center(company), + "income_account": income_account, + "expense_account": expense_account, + } + ) + + doc = frappe.get_doc(doctype) + doc.save(ignore_permissions=True) + doc.submit() + + +def create_transaction_deletion_record(company): + transaction_deletion_record = frappe.new_doc("Transaction Deletion Record") + transaction_deletion_record.company = company + transaction_deletion_record.save(ignore_permissions=True) + transaction_deletion_record.submit() diff --git a/erpnext/setup/demo_data/customer.json b/erpnext/setup/demo_data/customer.json new file mode 100644 index 00000000000..08e0e137436 --- /dev/null +++ b/erpnext/setup/demo_data/customer.json @@ -0,0 +1,17 @@ +[ + { + "doctype": "Customer", + "customer_group": "Demo Customer Group", + "customer_name": "ABC Enterprises" + }, + { + "doctype": "Customer", + "customer_group": "Demo Customer Group", + "customer_name": "XYZ Corporation" + }, + { + "doctype": "Customer", + "customer_group": "Demo Customer Group", + "customer_name": "KJPR Pvt Ltd" + } +] \ No newline at end of file diff --git a/erpnext/setup/demo_data/customer_group.json b/erpnext/setup/demo_data/customer_group.json new file mode 100644 index 00000000000..754333548a8 --- /dev/null +++ b/erpnext/setup/demo_data/customer_group.json @@ -0,0 +1,6 @@ +[ + { + "doctype": "Customer Group", + "customer_group_name": "Demo Customer Group" + } +] \ No newline at end of file diff --git a/erpnext/setup/demo_data/item.json b/erpnext/setup/demo_data/item.json new file mode 100644 index 00000000000..37822233cc0 --- /dev/null +++ b/erpnext/setup/demo_data/item.json @@ -0,0 +1,71 @@ +[ + { + "doctype": "Item", + "item_group": "Demo Item Group", + "item_code": "SKU001", + "item_name": "T-shirt", + "image": "https://media.istockphoto.com/id/1281631373/vector/mockup-template-men-black-t-shirt-short-sleeve.jpg?s=612x612&w=0&k=20&c=SfYrtFXQS2wJ1-R9ozvxhUabJz3cnmH5HXv2sXW_mZk=" + }, + { + "doctype": "Item", + "item_group": "Demo Item Group", + "item_code": "SKU002", + "item_name": "Laptop", + "image": "https://media.istockphoto.com/id/1297051332/vector/levitation-laptop-mockup.jpg?s=612x612&w=0&k=20&c=E9rp9HY7CaPjjsnZlg8NYBTFOGy7gfBSL7oK6wv5VnY=" + }, + { + "doctype": "Item", + "item_group": "Demo Item Group", + "item_code": "SKU003", + "item_name": "Book", + "image": "https://media.istockphoto.com/id/950152244/vector/vector-mock-up-of-standing-book.jpg?s=612x612&w=0&k=20&c=oDF2LeFoAcPAwJZFEVjWRvT53sMmCQwkVj-3qYy1duw=" + }, + { + "doctype": "Item", + "item_group": "Demo Item Group", + "item_code": "SKU004", + "item_name": "Smartphone", + "image": "https://media.istockphoto.com/id/1308145590/vector/realistic-mobile-phone-mockup-template-isolated-stock-vector.jpg?s=612x612&w=0&k=20&c=63UyujU3S9kAkUh3MXdJcr10xelDjgVyQzRx5Sh5018=" + }, + { + "doctype": "Item", + "item_group": "Demo Item Group", + "item_code": "SKU005", + "item_name": "Sneakers", + "image": "https://media.istockphoto.com/id/1303978937/photo/white-sneaker-on-a-blue-gradient-background-mens-fashion-sport-shoe-sneakers-lifestyle.jpg?s=612x612&w=0&k=20&c=L725fuzFTnm6qEaqE7Urc5q6IR80EgYQEjBn_qtBIQg=" + }, + { + "doctype": "Item", + "item_code": "SKU006", + "item_name": "Coffee Mug", + "image": "https://media.istockphoto.com/id/821282266/photo/white-mug-isolated.jpg?s=612x612&w=0&k=20&c=LJCMPk0D83OKmJHahkiLzAB3OsKr83nMbL7KxSgfpfM=" + }, + { + "doctype": "Item", + "item_group": "Demo Item Group", + "item_code": "SKU007", + "item_name": "Television", + "image": "https://media.istockphoto.com/id/1002728980/vector/wide-tv-monitor-mockup.jpg?s=612x612&w=0&k=20&c=1gDEH7ppC9ap8UBuIQmO1gM_Z8VeEaEUDDo-Aw_k8qs=" + }, + { + "doctype": "Item", + "item_group": "Demo Item Group", + "item_code": "SKU008", + "item_name": "Backpack", + "image": "https://media.istockphoto.com/id/1141208525/photo/yellow-open-backpack.jpg?s=612x612&w=0&k=20&c=k0NOqN9FnIGdkaUNx6-fMIBG2IfWwLT_AbDVefqJT_0=" + }, + { + "doctype": "Item", + "item_group": "Demo Item Group", + "item_code": "SKU009", + "item_name": "Headphones", + "image": "https://media.istockphoto.com/id/860853774/photo/blue-headphones-isolated-on-a-white-background.jpg?s=612x612&w=0&k=20&c=KqMSLWuM_Prrq5XHTe79bnFRU_leFDaXTuKqup5uvrE=" + }, + { + "doctype": "Item", + "item_group": "Demo Item Group", + "item_code": "SKU010", + "item_name": "Camera", + "image": "https://media.istockphoto.com/id/185278433/photo/black-digital-slr-camera-in-a-white-background.jpg?s=612x612&w=0&k=20&c=OOCbhvOF0W-eVhhrm-TxbgLfbKhFfs4Lprjd7hiQBNU=" + } +] \ No newline at end of file diff --git a/erpnext/setup/demo_data/item_group.json b/erpnext/setup/demo_data/item_group.json new file mode 100644 index 00000000000..acb261f4ed5 --- /dev/null +++ b/erpnext/setup/demo_data/item_group.json @@ -0,0 +1,7 @@ +[ + { + "doctype": "Item Group", + "item_group_name": "Demo Item Group", + "parent_item_group": "All Item Groups" + } +] \ No newline at end of file diff --git a/erpnext/setup/demo_data/items.json b/erpnext/setup/demo_data/items.json deleted file mode 100644 index fed36e251ef..00000000000 --- a/erpnext/setup/demo_data/items.json +++ /dev/null @@ -1,62 +0,0 @@ -[ - { - "doctype": "Item", - "item_code": "SKU001", - "item_name": "T-shirt", - "image": "https://www.shutterstock.com/image-photo/close-man-blank-tshirt-140861086" - }, - { - "doctype": "Item", - "item_code": "SKU002", - "item_name": "Laptop", - "image": "https://www.shutterstock.com/image-photo/laptop-computer-blank-screen-isolated-on-1721445466" - }, - { - "doctype": "Item", - "item_code": "SKU003", - "item_name": "Book", - "image": "https://www.shutterstock.com/image-vector/blank-vertical-book-cover-template-pages-172777709" - }, - { - "doctype": "Item", - "item_code": "SKU004", - "item_name": "Smartphone", - "image": "https://www.shutterstock.com/image-vector/realistic-smartphone-mockup-front-back-1450789832" - }, - { - "doctype": "Item", - "item_code": "SKU005", - "item_name": "Sneakers", - "image": "https://www.shutterstock.com/image-photo/white-sneaker-sport-shoe-on-purple-2155395817" - }, - { - "doctype": "Item", - "item_code": "SKU006", - "item_name": "Coffee Mug", - "image": "https://www.shutterstock.com/image-vector/realistic-white-cup-isolated-on-transparent-585104080" - }, - { - "doctype": "Item", - "item_code": "SKU007", - "item_name": "Television", - "image": "https://www.shutterstock.com/image-photo/tv-flat-screen-lcd-plasma-realistic-314401364" - }, - { - "doctype": "Item", - "item_code": "SKU008", - "item_name": "Backpack", - "image": "https://www.shutterstock.com/image-photo/school-backpack-on-white-background-1440715766" - }, - { - "doctype": "Item", - "item_code": "SKU009", - "item_name": "Headphones", - "image": "https://www.shutterstock.com/image-illustration/3d-rendering-yellow-headphones-isolated-on-1833307018" - }, - { - "doctype": "Item", - "item_code": "SKU010", - "item_name": "Camera", - "image": "https://www.shutterstock.com/image-photo/camera-610909205" - } -] \ No newline at end of file diff --git a/erpnext/setup/demo_data/purchase_invoice.json b/erpnext/setup/demo_data/purchase_invoice.json new file mode 100644 index 00000000000..cfcd00c0388 --- /dev/null +++ b/erpnext/setup/demo_data/purchase_invoice.json @@ -0,0 +1,17 @@ +[ + { + "conversion_rate": 1.0, + "supplier": "DQ Industries", + "doctype": "Purchase Invoice", + "items": [ + { + "doctype": "Purchase Invoice Item", + "item_code": "SKU004", + "parentfield": "items", + "qty": 20.0, + "rate": 400.0, + "conversion_factor": 1 + } + ] + } +] \ No newline at end of file diff --git a/erpnext/setup/demo_data/sales_invoice.json b/erpnext/setup/demo_data/sales_invoice.json new file mode 100644 index 00000000000..64f04f0fb23 --- /dev/null +++ b/erpnext/setup/demo_data/sales_invoice.json @@ -0,0 +1,17 @@ +[ + { + "conversion_rate": 1.0, + "customer": "ABC Enterprises", + "doctype": "Sales Invoice", + "items": [ + { + "doctype": "Sales Invoice Item", + "item_code": "SKU004", + "parentfield": "items", + "qty": 20.0, + "rate": 500.0, + "conversion_factor": 1 + } + ] + } +] \ No newline at end of file diff --git a/erpnext/setup/demo_data/supplier.json b/erpnext/setup/demo_data/supplier.json new file mode 100644 index 00000000000..96c83d1de53 --- /dev/null +++ b/erpnext/setup/demo_data/supplier.json @@ -0,0 +1,17 @@ +[ + { + "doctype": "Supplier", + "supplier_group": "Demo Supplier Group", + "supplier_name": "DQ Industries" + }, + { + "doctype": "Supplier", + "supplier_group": "Demo Supplier Group", + "supplier_name": "MA Inc." + }, + { + "doctype": "Supplier", + "supplier_group": "Demo Supplier Group", + "supplier_name": "KC Corp." + } +] \ No newline at end of file diff --git a/erpnext/setup/demo_data/supplier_group.json b/erpnext/setup/demo_data/supplier_group.json new file mode 100644 index 00000000000..17070bf9b60 --- /dev/null +++ b/erpnext/setup/demo_data/supplier_group.json @@ -0,0 +1,6 @@ +[ + { + "doctype": "Supplier Group", + "supplier_group_name": "Demo Supplier Group" + } +] \ No newline at end of file diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.json b/erpnext/setup/doctype/global_defaults/global_defaults.json index bafb97a5d80..0f574765038 100644 --- a/erpnext/setup/doctype/global_defaults/global_defaults.json +++ b/erpnext/setup/doctype/global_defaults/global_defaults.json @@ -1,352 +1,116 @@ { - "allow_copy": 1, - "allow_guest_to_view": 0, - "allow_import": 0, - "allow_rename": 0, - "beta": 0, - "creation": "2013-05-02 17:53:24", - "custom": 0, - "docstatus": 0, - "doctype": "DocType", - "editable_grid": 0, + "actions": [], + "allow_copy": 1, + "creation": "2013-05-02 17:53:24", + "doctype": "DocType", + "engine": "InnoDB", + "field_order": [ + "default_company", + "current_fiscal_year", + "country", + "default_distance_unit", + "column_break_8", + "default_currency", + "hide_currency_symbol", + "disable_rounded_total", + "disable_in_words", + "demo_company" + ], "fields": [ { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "default_company", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Company", - "length": 0, - "no_copy": 0, - "options": "Company", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "default_company", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "label": "Default Company", + "options": "Company" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "current_fiscal_year", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Current Fiscal Year", - "length": 0, - "no_copy": 0, - "options": "Fiscal Year", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "current_fiscal_year", + "fieldtype": "Link", + "label": "Current Fiscal Year", + "options": "Fiscal Year", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "country", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Country", - "length": 0, - "no_copy": 0, - "options": "Country", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "country", + "fieldtype": "Link", + "label": "Country", + "options": "Country" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "", - "fieldname": "default_distance_unit", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "label": "Default Distance Unit", - "length": 0, - "no_copy": 0, - "options": "UOM", - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "default_distance_unit", + "fieldtype": "Link", + "label": "Default Distance Unit", + "options": "UOM" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "fieldname": "column_break_8", - "fieldtype": "Column Break", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 0, - "in_standard_filter": 0, - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "fieldname": "column_break_8", + "fieldtype": "Column Break" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "default": "INR", - "fieldname": "default_currency", - "fieldtype": "Link", - "hidden": 0, - "ignore_user_permissions": 1, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Default Currency", - "length": 0, - "no_copy": 0, - "options": "Currency", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 1, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "INR", + "fieldname": "default_currency", + "fieldtype": "Link", + "ignore_user_permissions": 1, + "in_list_view": 1, + "label": "Default Currency", + "options": "Currency", + "reqd": 1 + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "Do not show any symbol like $ etc next to currencies.", - "fieldname": "hide_currency_symbol", - "fieldtype": "Select", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Hide Currency Symbol", - "length": 0, - "no_copy": 0, - "options": "\nNo\nYes", - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "description": "Do not show any symbol like $ etc next to currencies.", + "fieldname": "hide_currency_symbol", + "fieldtype": "Select", + "in_list_view": 1, + "label": "Hide Currency Symbol", + "options": "\nNo\nYes" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "If disable, 'Rounded Total' field will not be visible in any transaction", - "fieldname": "disable_rounded_total", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Disable Rounded Total", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 - }, + "default": "0", + "description": "If disable, 'Rounded Total' field will not be visible in any transaction", + "fieldname": "disable_rounded_total", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Disable Rounded Total" + }, { - "allow_bulk_edit": 0, - "allow_in_quick_entry": 0, - "allow_on_submit": 0, - "bold": 0, - "collapsible": 0, - "columns": 0, - "description": "If disable, 'In Words' field will not be visible in any transaction", - "fieldname": "disable_in_words", - "fieldtype": "Check", - "hidden": 0, - "ignore_user_permissions": 0, - "ignore_xss_filter": 0, - "in_filter": 0, - "in_global_search": 0, - "in_list_view": 1, - "in_standard_filter": 0, - "label": "Disable In Words", - "length": 0, - "no_copy": 0, - "permlevel": 0, - "precision": "", - "print_hide": 0, - "print_hide_if_no_value": 0, - "read_only": 0, - "remember_last_selected_value": 0, - "report_hide": 0, - "reqd": 0, - "search_index": 0, - "set_only_once": 0, - "translatable": 0, - "unique": 0 + "default": "0", + "description": "If disable, 'In Words' field will not be visible in any transaction", + "fieldname": "disable_in_words", + "fieldtype": "Check", + "in_list_view": 1, + "label": "Disable In Words" + }, + { + "fieldname": "demo_company", + "fieldtype": "Link", + "hidden": 1, + "label": "Demo Company", + "options": "Company", + "read_only": 1 } - ], - "has_web_view": 0, - "hide_heading": 0, - "hide_toolbar": 0, - "icon": "fa fa-cog", - "idx": 1, - "image_view": 0, - "in_create": 1, - "is_submittable": 0, - "issingle": 1, - "istable": 0, - "max_attachments": 0, - "menu_index": 0, - "modified": "2018-10-15 03:08:19.886212", - "modified_by": "Administrator", - "module": "Setup", - "name": "Global Defaults", - "owner": "Administrator", + ], + "icon": "fa fa-cog", + "idx": 1, + "in_create": 1, + "issingle": 1, + "links": [], + "modified": "2023-06-16 13:03:45.016191", + "modified_by": "Administrator", + "module": "Setup", + "name": "Global Defaults", + "owner": "Administrator", "permissions": [ { - "amend": 0, - "cancel": 0, - "create": 1, - "delete": 0, - "email": 0, - "export": 0, - "if_owner": 0, - "import": 0, - "permlevel": 0, - "print": 0, - "read": 1, - "report": 0, - "role": "System Manager", - "set_user_permissions": 0, - "share": 1, - "submit": 0, + "create": 1, + "read": 1, + "role": "System Manager", + "share": 1, "write": 1 } - ], - "quick_entry": 0, - "read_only": 1, - "read_only_onload": 0, - "show_name_in_global_search": 0, - "sort_order": "DESC", - "track_changes": 0, - "track_seen": 0, - "track_views": 0 + ], + "read_only": 1, + "sort_field": "modified", + "sort_order": "DESC", + "states": [] } \ No newline at end of file From 5b6a9fcca97a0283a7d517a904b835a26ffa388e Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 17 Jun 2023 13:08:18 +0530 Subject: [PATCH 03/46] feat: Clear demo data --- erpnext/accounts/party.py | 2 +- erpnext/setup/demo.py | 66 +++++++++++++------ erpnext/setup/demo_data/customer.json | 3 + erpnext/setup/demo_data/item.json | 1 + .../global_defaults/global_defaults.json | 8 +-- 5 files changed, 56 insertions(+), 24 deletions(-) diff --git a/erpnext/accounts/party.py b/erpnext/accounts/party.py index 933c70d5e1b..4ec5c95c76c 100644 --- a/erpnext/accounts/party.py +++ b/erpnext/accounts/party.py @@ -669,7 +669,7 @@ def get_payment_terms_template(party_name, party_type, company=None): if party_type not in ("Customer", "Supplier"): return template = None - print(party_type, party_name) + if party_type == "Customer": customer = frappe.get_cached_value( "Customer", party_name, fieldname=["payment_terms", "customer_group"], as_dict=1 diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index 1256b0e623e..41faff2c81b 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -18,12 +18,14 @@ def setup_demo_data(): @frappe.whitelist() def clear_demo_data(): - company = frappe.db.get_single_value("Global Defaults", "demo_company") + company = erpnext.get_default_company() create_transaction_deletion_record(company) + clear_masters() + delete_company(company) def create_demo_company(): - company = frappe.db.get_value("Company", {"docstatus": 0}) + company = erpnext.get_default_company() company_doc = frappe.get_doc("Company", company) # Make a dummy company @@ -37,19 +39,19 @@ def create_demo_company(): new_company.chart_of_accounts = company_doc.chart_of_accounts new_company.insert() - frappe.db.set_single_value("Global Defaults", "demo_company", new_company.name) + frappe.db.set_single_value("Global Defaults", "original_default_company", company) + + # Set Demo Company as default to + frappe.db.set_single_value("Global Defaults", "default_company", new_company.name) return new_company.name def process_masters(): - demo_doctypes = frappe.get_hooks("demo_master_doctypes") or [] - path = os.path.join(os.path.dirname(__file__), "demo_data") - for doctype in demo_doctypes: - with open(os.path.join(path, doctype + ".json"), "r") as f: - data = f.read() - if data: - for item in json.loads(data): - create_demo_record(item) + for doctype in frappe.get_hooks("demo_master_doctypes"): + data = read_data_file_using_hooks(doctype) + if data: + for item in json.loads(data): + create_demo_record(item) def create_demo_record(doctype): @@ -57,14 +59,11 @@ def create_demo_record(doctype): def make_transactions(company): - transaction_doctypes = frappe.get_hooks("demo_transaction_doctypes") or [] - path = os.path.join(os.path.dirname(__file__), "demo_data") - for transaction in transaction_doctypes: - with open(os.path.join(path, transaction + ".json"), "r") as f: - data = f.read() - if data: - for item in json.loads(data): - create_transaction(item, company) + for doctype in frappe.get_hooks("demo_transaction_doctypes"): + data = read_data_file_using_hooks(doctype) + if data: + for item in json.loads(data): + create_transaction(item, company) def create_transaction(doctype, company): @@ -93,3 +92,32 @@ def create_transaction_deletion_record(company): transaction_deletion_record.company = company transaction_deletion_record.save(ignore_permissions=True) transaction_deletion_record.submit() + + +def clear_masters(): + for doctype in frappe.get_hooks("demo_master_doctypes")[::-1]: + data = read_data_file_using_hooks(doctype) + if data: + for item in json.loads(data): + clear_demo_record(item) + + +def clear_demo_record(doctype): + doc_type = doctype.get("doctype") + del doctype["doctype"] + doc = frappe.get_doc(doc_type, doctype) + frappe.delete_doc(doc.doctype, doc.name, ignore_permissions=True) + + +def delete_company(company): + original_company = frappe.db.get_single_value("Global Defaults", "original_default_company") + frappe.db.set_single_value("Global Defaults", "default_company", original_company) + frappe.delete_doc("Company", company, ignore_permissions=True) + + +def read_data_file_using_hooks(doctype): + path = os.path.join(os.path.dirname(__file__), "demo_data") + with open(os.path.join(path, doctype + ".json"), "r") as f: + data = f.read() + + return data diff --git a/erpnext/setup/demo_data/customer.json b/erpnext/setup/demo_data/customer.json index 08e0e137436..ed952922ee3 100644 --- a/erpnext/setup/demo_data/customer.json +++ b/erpnext/setup/demo_data/customer.json @@ -2,16 +2,19 @@ { "doctype": "Customer", "customer_group": "Demo Customer Group", + "territory": "All Territories", "customer_name": "ABC Enterprises" }, { "doctype": "Customer", "customer_group": "Demo Customer Group", + "territory": "All Territories", "customer_name": "XYZ Corporation" }, { "doctype": "Customer", "customer_group": "Demo Customer Group", + "territory": "All Territories", "customer_name": "KJPR Pvt Ltd" } ] \ No newline at end of file diff --git a/erpnext/setup/demo_data/item.json b/erpnext/setup/demo_data/item.json index 37822233cc0..a24133725ff 100644 --- a/erpnext/setup/demo_data/item.json +++ b/erpnext/setup/demo_data/item.json @@ -36,6 +36,7 @@ }, { "doctype": "Item", + "item_group": "Demo Item Group", "item_code": "SKU006", "item_name": "Coffee Mug", "image": "https://media.istockphoto.com/id/821282266/photo/white-mug-isolated.jpg?s=612x612&w=0&k=20&c=LJCMPk0D83OKmJHahkiLzAB3OsKr83nMbL7KxSgfpfM=" diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.json b/erpnext/setup/doctype/global_defaults/global_defaults.json index 0f574765038..6d912ce79cb 100644 --- a/erpnext/setup/doctype/global_defaults/global_defaults.json +++ b/erpnext/setup/doctype/global_defaults/global_defaults.json @@ -14,7 +14,7 @@ "hide_currency_symbol", "disable_rounded_total", "disable_in_words", - "demo_company" + "original_default_company" ], "fields": [ { @@ -82,10 +82,10 @@ "label": "Disable In Words" }, { - "fieldname": "demo_company", + "fieldname": "original_default_company", "fieldtype": "Link", "hidden": 1, - "label": "Demo Company", + "label": "Original Default Company", "options": "Company", "read_only": 1 } @@ -95,7 +95,7 @@ "in_create": 1, "issingle": 1, "links": [], - "modified": "2023-06-16 13:03:45.016191", + "modified": "2023-06-17 13:07:40.074663", "modified_by": "Administrator", "module": "Setup", "name": "Global Defaults", From 86744b6fbba35b3bc87ec91e222102ead8514a26 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 19 Jun 2023 09:44:57 +0530 Subject: [PATCH 04/46] chore: Add more invoices --- .../profit_and_loss/profit_and_loss.json | 2 +- erpnext/setup/demo.py | 31 ++-- erpnext/setup/demo_data/customer.json | 2 +- erpnext/setup/demo_data/payment_entry.json | 0 erpnext/setup/demo_data/purchase_invoice.json | 137 +++++++++++++++++- erpnext/setup/demo_data/sales_invoice.json | 100 +++++++++++++ .../global_defaults/global_defaults.json | 8 +- .../operations/install_fixtures.py | 2 +- 8 files changed, 265 insertions(+), 17 deletions(-) create mode 100644 erpnext/setup/demo_data/payment_entry.json diff --git a/erpnext/accounts/dashboard_chart/profit_and_loss/profit_and_loss.json b/erpnext/accounts/dashboard_chart/profit_and_loss/profit_and_loss.json index 3fa995bbe15..0a0bf3a79e3 100644 --- a/erpnext/accounts/dashboard_chart/profit_and_loss/profit_and_loss.json +++ b/erpnext/accounts/dashboard_chart/profit_and_loss/profit_and_loss.json @@ -9,7 +9,7 @@ "idx": 0, "is_public": 1, "is_standard": 1, - "modified": "2020-07-22 12:33:48.888943", + "modified": "2023-06-17 12:33:48.888943", "modified_by": "Administrator", "module": "Accounts", "name": "Profit and Loss", diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index 41faff2c81b..6947f4519c3 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -3,8 +3,10 @@ import json import os +from random import randint import frappe +from frappe.utils import add_days import erpnext @@ -18,7 +20,7 @@ def setup_demo_data(): @frappe.whitelist() def clear_demo_data(): - company = erpnext.get_default_company() + company = frappe.db.get_single_value("Global Defaults", "demo_company") create_transaction_deletion_record(company) clear_masters() delete_company(company) @@ -39,10 +41,10 @@ def create_demo_company(): new_company.chart_of_accounts = company_doc.chart_of_accounts new_company.insert() - frappe.db.set_single_value("Global Defaults", "original_default_company", company) - # Set Demo Company as default to - frappe.db.set_single_value("Global Defaults", "default_company", new_company.name) + frappe.db.set_single_value("Global Defaults", "demo_company", new_company.name) + frappe.db.set_default("company", new_company.name) + return new_company.name @@ -59,15 +61,24 @@ def create_demo_record(doctype): def make_transactions(company): + fiscal_year = frappe.db.get_single_value("Global Defaults", "current_fiscal_year") + start_date = frappe.db.get_value("Fiscal Year", fiscal_year, "year_start_date") + for doctype in frappe.get_hooks("demo_transaction_doctypes"): data = read_data_file_using_hooks(doctype) if data: for item in json.loads(data): - create_transaction(item, company) + create_transaction(item, company, start_date) -def create_transaction(doctype, company): - doctype.update({"company": company}) +def create_transaction(doctype, company, start_date): + doctype.update( + { + "company": company, + "set_posting_time": 1, + "posting_date": get_random_date(start_date), + } + ) income_account, expense_account = frappe.db.get_value( "Company", company, ["default_income_account", "default_expense_account"] @@ -87,6 +98,10 @@ def create_transaction(doctype, company): doc.submit() +def get_random_date(start_date): + return add_days(start_date, randint(1, 365)) + + def create_transaction_deletion_record(company): transaction_deletion_record = frappe.new_doc("Transaction Deletion Record") transaction_deletion_record.company = company @@ -110,8 +125,6 @@ def clear_demo_record(doctype): def delete_company(company): - original_company = frappe.db.get_single_value("Global Defaults", "original_default_company") - frappe.db.set_single_value("Global Defaults", "default_company", original_company) frappe.delete_doc("Company", company, ignore_permissions=True) diff --git a/erpnext/setup/demo_data/customer.json b/erpnext/setup/demo_data/customer.json index ed952922ee3..b27c44477d1 100644 --- a/erpnext/setup/demo_data/customer.json +++ b/erpnext/setup/demo_data/customer.json @@ -15,6 +15,6 @@ "doctype": "Customer", "customer_group": "Demo Customer Group", "territory": "All Territories", - "customer_name": "KJPR Pvt Ltd" + "customer_name": "KJPR Pvt. Ltd." } ] \ No newline at end of file diff --git a/erpnext/setup/demo_data/payment_entry.json b/erpnext/setup/demo_data/payment_entry.json new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/setup/demo_data/purchase_invoice.json b/erpnext/setup/demo_data/purchase_invoice.json index cfcd00c0388..725f57147cd 100644 --- a/erpnext/setup/demo_data/purchase_invoice.json +++ b/erpnext/setup/demo_data/purchase_invoice.json @@ -1,4 +1,49 @@ [ + { + "conversion_rate": 1.0, + "supplier": "DQ Industries", + "doctype": "Purchase Invoice", + "items": [ + { + "doctype": "Purchase Invoice Item", + "item_code": "SKU001", + "parentfield": "items", + "qty": 100.0, + "rate": 400.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "supplier": "MA Inc.", + "doctype": "Purchase Invoice", + "items": [ + { + "doctype": "Purchase Invoice Item", + "item_code": "SKU002", + "parentfield": "items", + "qty": 100.0, + "rate": 400.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "supplier": "KC Corp.", + "doctype": "Purchase Invoice", + "items": [ + { + "doctype": "Purchase Invoice Item", + "item_code": "SKU003", + "parentfield": "items", + "qty": 100.0, + "rate": 400.0, + "conversion_factor": 1 + } + ] + }, { "conversion_rate": 1.0, "supplier": "DQ Industries", @@ -8,7 +53,97 @@ "doctype": "Purchase Invoice Item", "item_code": "SKU004", "parentfield": "items", - "qty": 20.0, + "qty": 100.0, + "rate": 400.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "supplier": "MA Inc.", + "doctype": "Purchase Invoice", + "items": [ + { + "doctype": "Purchase Invoice Item", + "item_code": "SKU005", + "parentfield": "items", + "qty": 100.0, + "rate": 400.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "supplier": "KC Corp.", + "doctype": "Purchase Invoice", + "items": [ + { + "doctype": "Purchase Invoice Item", + "item_code": "SKU006", + "parentfield": "items", + "qty": 100.0, + "rate": 400.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "supplier": "DQ Industries", + "doctype": "Purchase Invoice", + "items": [ + { + "doctype": "Purchase Invoice Item", + "item_code": "SKU007", + "parentfield": "items", + "qty": 100.0, + "rate": 400.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "supplier": "MA Inc.", + "doctype": "Purchase Invoice", + "items": [ + { + "doctype": "Purchase Invoice Item", + "item_code": "SKU008", + "parentfield": "items", + "qty": 100.0, + "rate": 400.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "supplier": "KC Corp.", + "doctype": "Purchase Invoice", + "items": [ + { + "doctype": "Purchase Invoice Item", + "item_code": "SKU009", + "parentfield": "items", + "qty": 100.0, + "rate": 400.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "supplier": "DQ Industries", + "doctype": "Purchase Invoice", + "items": [ + { + "doctype": "Purchase Invoice Item", + "item_code": "SKU010", + "parentfield": "items", + "qty": 100.0, "rate": 400.0, "conversion_factor": 1 } diff --git a/erpnext/setup/demo_data/sales_invoice.json b/erpnext/setup/demo_data/sales_invoice.json index 64f04f0fb23..6aaffc24713 100644 --- a/erpnext/setup/demo_data/sales_invoice.json +++ b/erpnext/setup/demo_data/sales_invoice.json @@ -13,5 +13,105 @@ "conversion_factor": 1 } ] + }, + { + "conversion_rate": 1.0, + "customer": "XYZ Corporation", + "doctype": "Sales Invoice", + "items": [ + { + "doctype": "Sales Invoice Item", + "item_code": "SKU001", + "parentfield": "items", + "qty": 25.0, + "rate": 600.0, + "conversion_factor": 1 + }, + { + "doctype": "Sales Invoice Item", + "item_code": "SKU002", + "parentfield": "items", + "qty": 15.0, + "rate": 300.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "customer": "XYZ Corporation", + "doctype": "Sales Invoice", + "items": [ + { + "doctype": "Sales Invoice Item", + "item_code": "SKU003", + "parentfield": "items", + "qty": 100, + "rate": 300.0, + "conversion_factor": 1 + }, + { + "doctype": "Sales Invoice Item", + "item_code": "SKU006", + "parentfield": "items", + "qty": 100, + "rate": 300.0, + "conversion_factor": 1 + }, + { + "doctype": "Sales Invoice Item", + "item_code": "SKU007", + "parentfield": "items", + "qty": 100, + "rate": 300.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "customer": "KJPR Pvt. Ltd.", + "doctype": "Sales Invoice", + "items": [ + { + "doctype": "Sales Invoice Item", + "item_code": "SKU005", + "parentfield": "items", + "qty": 200.0, + "rate": 100.0, + "conversion_factor": 1 + } + ] + }, + { + "conversion_rate": 1.0, + "customer": "ABC Enterprises", + "doctype": "Sales Invoice", + "items": [ + { + "doctype": "Sales Invoice Item", + "item_code": "SKU008", + "parentfield": "items", + "qty": 20.0, + "rate": 500.0, + "conversion_factor": 1 + }, + { + "doctype": "Sales Invoice Item", + "item_code": "SKU009", + "parentfield": "items", + "qty": 40.0, + "rate": 300.0, + "conversion_factor": 1 + }, + { + "doctype": "Sales Invoice Item", + "item_code": "SKU010", + "parentfield": "items", + "qty": 50.0, + "rate": 900.0, + "conversion_factor": 1 + } + ] } ] \ No newline at end of file diff --git a/erpnext/setup/doctype/global_defaults/global_defaults.json b/erpnext/setup/doctype/global_defaults/global_defaults.json index 6d912ce79cb..a2a135bdd27 100644 --- a/erpnext/setup/doctype/global_defaults/global_defaults.json +++ b/erpnext/setup/doctype/global_defaults/global_defaults.json @@ -14,7 +14,7 @@ "hide_currency_symbol", "disable_rounded_total", "disable_in_words", - "original_default_company" + "demo_company" ], "fields": [ { @@ -82,10 +82,10 @@ "label": "Disable In Words" }, { - "fieldname": "original_default_company", + "fieldname": "demo_company", "fieldtype": "Link", "hidden": 1, - "label": "Original Default Company", + "label": "Demo Company", "options": "Company", "read_only": 1 } @@ -95,7 +95,7 @@ "in_create": 1, "issingle": 1, "links": [], - "modified": "2023-06-17 13:07:40.074663", + "modified": "2023-06-17 19:49:14.094209", "modified_by": "Administrator", "module": "Setup", "name": "Global Defaults", diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 8e61fe28728..6c81cfca2c1 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -492,7 +492,7 @@ def update_stock_settings(): def create_bank_account(args): if not args.get("bank_account"): - return + args["bank_account"] = _("Bank Account") company_name = args.get("company_name") bank_account_group = frappe.db.get_value( From 85e1c85b521b9a6025b0cacab225dab4d8abdd52 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 19 Jun 2023 14:12:23 +0530 Subject: [PATCH 05/46] chore: Add payment entry --- erpnext/hooks.py | 2 +- erpnext/setup/demo.py | 27 +++++++++++++++++-- erpnext/setup/demo_data/payment_entry.json | 12 +++++++++ erpnext/setup/demo_data/purchase_invoice.json | 10 +++++++ erpnext/setup/demo_data/sales_invoice.json | 5 ++++ 5 files changed, 53 insertions(+), 3 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 275c93d8acb..beefb1d2050 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -78,7 +78,7 @@ demo_master_doctypes = [ "customer", "supplier", ] -demo_transaction_doctypes = ["purchase_invoice", "sales_invoice"] +demo_transaction_doctypes = ["purchase_invoice", "sales_invoice", "payment_entry"] jinja = { "methods": [ diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index 6947f4519c3..46500da15c7 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -9,6 +9,7 @@ import frappe from frappe.utils import add_days import erpnext +from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account @frappe.whitelist() @@ -45,6 +46,9 @@ def create_demo_company(): frappe.db.set_single_value("Global Defaults", "demo_company", new_company.name) frappe.db.set_default("company", new_company.name) + bank_account = create_bank_account({"company_name": new_company.name}) + frappe.db.set_value("Company", new_company.name, "default_bank_account", bank_account.name) + return new_company.name @@ -63,6 +67,7 @@ def create_demo_record(doctype): def make_transactions(company): fiscal_year = frappe.db.get_single_value("Global Defaults", "current_fiscal_year") start_date = frappe.db.get_value("Fiscal Year", fiscal_year, "year_start_date") + frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1) for doctype in frappe.get_hooks("demo_transaction_doctypes"): data = read_data_file_using_hooks(doctype) @@ -72,11 +77,21 @@ def make_transactions(company): def create_transaction(doctype, company, start_date): + warehouse = get_warehouse(company) + posting_date = ( + start_date if doctype.get("doctype") == "Purchase Invoice" else get_random_date(start_date) + ) + bank_account = frappe.db.get_value("Company", company, "default_bank_account") + bank_field = "paid_to" if doctype.get("party_type") == "Customer" else "paid_from" + doctype.update( { "company": company, "set_posting_time": 1, - "posting_date": get_random_date(start_date), + "posting_date": posting_date, + "set_warehouse": warehouse, + bank_field: bank_account, + "reference_date": posting_date, } ) @@ -84,7 +99,7 @@ def create_transaction(doctype, company, start_date): "Company", company, ["default_income_account", "default_expense_account"] ) - for item in doctype.get("items"): + for item in doctype.get("items") or []: item.update( { "cost_center": erpnext.get_default_cost_center(company), @@ -125,6 +140,7 @@ def clear_demo_record(doctype): def delete_company(company): + frappe.db.set_single_value("Global Defaults", "demo_company", "") frappe.delete_doc("Company", company, ignore_permissions=True) @@ -134,3 +150,10 @@ def read_data_file_using_hooks(doctype): data = f.read() return data + + +def get_warehouse(company): + abbr = frappe.db.get_value("Company", company, "abbr") + warehouse = "Stores - {0}".format(abbr) + + return warehouse diff --git a/erpnext/setup/demo_data/payment_entry.json b/erpnext/setup/demo_data/payment_entry.json index e69de29bb2d..7d8d7d5ca2c 100644 --- a/erpnext/setup/demo_data/payment_entry.json +++ b/erpnext/setup/demo_data/payment_entry.json @@ -0,0 +1,12 @@ +[ + { + "doctype": "Payment Entry", + "party_type": "Customer", + "party": "ABC Enterprises", + "paid_amount": 67000, + "received_amount": 67000, + "reference_no": "#ref0001", + "source_exchange_rate": 1, + "target_exchange_rate": 1 + } +] \ No newline at end of file diff --git a/erpnext/setup/demo_data/purchase_invoice.json b/erpnext/setup/demo_data/purchase_invoice.json index 725f57147cd..eda26b0502d 100644 --- a/erpnext/setup/demo_data/purchase_invoice.json +++ b/erpnext/setup/demo_data/purchase_invoice.json @@ -3,6 +3,7 @@ "conversion_rate": 1.0, "supplier": "DQ Industries", "doctype": "Purchase Invoice", + "update_stock": 1, "items": [ { "doctype": "Purchase Invoice Item", @@ -18,6 +19,7 @@ "conversion_rate": 1.0, "supplier": "MA Inc.", "doctype": "Purchase Invoice", + "update_stock": 1, "items": [ { "doctype": "Purchase Invoice Item", @@ -33,6 +35,7 @@ "conversion_rate": 1.0, "supplier": "KC Corp.", "doctype": "Purchase Invoice", + "update_stock": 1, "items": [ { "doctype": "Purchase Invoice Item", @@ -48,6 +51,7 @@ "conversion_rate": 1.0, "supplier": "DQ Industries", "doctype": "Purchase Invoice", + "update_stock": 1, "items": [ { "doctype": "Purchase Invoice Item", @@ -63,6 +67,7 @@ "conversion_rate": 1.0, "supplier": "MA Inc.", "doctype": "Purchase Invoice", + "update_stock": 1, "items": [ { "doctype": "Purchase Invoice Item", @@ -78,6 +83,7 @@ "conversion_rate": 1.0, "supplier": "KC Corp.", "doctype": "Purchase Invoice", + "update_stock": 1, "items": [ { "doctype": "Purchase Invoice Item", @@ -93,6 +99,7 @@ "conversion_rate": 1.0, "supplier": "DQ Industries", "doctype": "Purchase Invoice", + "update_stock": 1, "items": [ { "doctype": "Purchase Invoice Item", @@ -108,6 +115,7 @@ "conversion_rate": 1.0, "supplier": "MA Inc.", "doctype": "Purchase Invoice", + "update_stock": 1, "items": [ { "doctype": "Purchase Invoice Item", @@ -123,6 +131,7 @@ "conversion_rate": 1.0, "supplier": "KC Corp.", "doctype": "Purchase Invoice", + "update_stock": 1, "items": [ { "doctype": "Purchase Invoice Item", @@ -138,6 +147,7 @@ "conversion_rate": 1.0, "supplier": "DQ Industries", "doctype": "Purchase Invoice", + "update_stock": 1, "items": [ { "doctype": "Purchase Invoice Item", diff --git a/erpnext/setup/demo_data/sales_invoice.json b/erpnext/setup/demo_data/sales_invoice.json index 6aaffc24713..6bbfcbe4cf8 100644 --- a/erpnext/setup/demo_data/sales_invoice.json +++ b/erpnext/setup/demo_data/sales_invoice.json @@ -3,6 +3,7 @@ "conversion_rate": 1.0, "customer": "ABC Enterprises", "doctype": "Sales Invoice", + "update_stock": 1, "items": [ { "doctype": "Sales Invoice Item", @@ -18,6 +19,7 @@ "conversion_rate": 1.0, "customer": "XYZ Corporation", "doctype": "Sales Invoice", + "update_stock": 1, "items": [ { "doctype": "Sales Invoice Item", @@ -41,6 +43,7 @@ "conversion_rate": 1.0, "customer": "XYZ Corporation", "doctype": "Sales Invoice", + "update_stock": 1, "items": [ { "doctype": "Sales Invoice Item", @@ -72,6 +75,7 @@ "conversion_rate": 1.0, "customer": "KJPR Pvt. Ltd.", "doctype": "Sales Invoice", + "update_stock": 1, "items": [ { "doctype": "Sales Invoice Item", @@ -87,6 +91,7 @@ "conversion_rate": 1.0, "customer": "ABC Enterprises", "doctype": "Sales Invoice", + "update_stock": 1, "items": [ { "doctype": "Sales Invoice Item", From 490b64575bdcd668981f8c2268ad181c8c6f5f67 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 26 Jun 2023 18:33:51 +0530 Subject: [PATCH 06/46] test: Add basic test for demo data --- erpnext/setup/doctype/company/test_company.py | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py index fd2fe300fac..0ed9621ca43 100644 --- a/erpnext/setup/doctype/company/test_company.py +++ b/erpnext/setup/doctype/company/test_company.py @@ -195,6 +195,17 @@ class TestCompany(unittest.TestCase): child_company.save() self.test_basic_tree() + def test_demo_data(self): + from erpnext.setup.demo import clear_demo_data, setup_demo_data + + setup_demo_data() + company_name = frappe.db.get_value("Company", {"name": ("like", "%(Demo)")}) + self.assertTrue(company_name) + + clear_demo_data() + company_name = frappe.db.get_value("Company", {"name": ("like", "%(Demo)")}) + self.assertFalse(company_name) + def create_company_communication(doctype, docname): comm = frappe.get_doc( From d5bdd9387a56ff40f728a2f77b7a4b9bfa273205 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Mon, 26 Jun 2023 18:35:01 +0530 Subject: [PATCH 07/46] chore: Do not update shopping cart settings on install --- .../setup_wizard/operations/install_fixtures.py | 15 --------------- 1 file changed, 15 deletions(-) diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 6c81cfca2c1..4db5d8e47dd 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -454,7 +454,6 @@ def install_defaults(args=None): # nosemgrep set_global_defaults(args) update_stock_settings() - update_shopping_cart_settings(args) args.update({"set_default": 1}) create_bank_account(args) @@ -531,20 +530,6 @@ def create_bank_account(args): pass -def update_shopping_cart_settings(args): # nosemgrep - shopping_cart = frappe.get_doc("E Commerce Settings") - shopping_cart.update( - { - "enabled": 1, - "company": args.company_name, - "price_list": frappe.db.get_value("Price List", {"selling": 1}), - "default_customer_group": _("Individual"), - "quotation_series": "QTN-", - } - ) - shopping_cart.update_single(shopping_cart.get_valid_dict()) - - def get_fy_details(fy_start_date, fy_end_date): start_year = getdate(fy_start_date).year if start_year == getdate(fy_end_date).year: From bb5387fa5d0b1382783e08977058431059520fd3 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Fri, 7 Jul 2023 10:49:56 +0530 Subject: [PATCH 08/46] fix: Add demo setup check in setup wizard --- erpnext/public/build.json | 1 + erpnext/public/js/setup_wizard.js | 1 + erpnext/public/js/utils/demo.js | 11 +++++++++++ erpnext/setup/demo.py | 2 +- erpnext/setup/setup_wizard/setup_wizard.py | 11 +++++++++++ 5 files changed, 25 insertions(+), 1 deletion(-) create mode 100644 erpnext/public/js/utils/demo.js diff --git a/erpnext/public/build.json b/erpnext/public/build.json index 3d38aca4186..04ecff15afc 100644 --- a/erpnext/public/build.json +++ b/erpnext/public/build.json @@ -20,6 +20,7 @@ "public/js/queries.js", "public/js/sms_manager.js", "public/js/utils/party.js", + "public/js/utils/demo.js", "public/js/controllers/stock_controller.js", "public/js/payment/payments.js", "public/js/controllers/taxes_and_totals.js", diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js index a913844e186..a067ec0f4a4 100644 --- a/erpnext/public/js/setup_wizard.js +++ b/erpnext/public/js/setup_wizard.js @@ -38,6 +38,7 @@ erpnext.setup.slides_settings = [ { fieldname: 'fy_start_date', label: __('Financial Year Begins On'), fieldtype: 'Date', reqd: 1 }, // end date should be hidden (auto calculated) { fieldname: 'fy_end_date', label: __('End Date'), fieldtype: 'Date', reqd: 1, hidden: 1 }, + { fieldname: 'setup_demo', label: __('Generate dummy data for demo'), fieldtype: 'Check'}, ], onload: function (slide) { diff --git a/erpnext/public/js/utils/demo.js b/erpnext/public/js/utils/demo.js new file mode 100644 index 00000000000..432bad63239 --- /dev/null +++ b/erpnext/public/js/utils/demo.js @@ -0,0 +1,11 @@ +$(document).on("toolbar_setup", function() { + if (erpnext.is_demo_company_setup) { + console.log("setup"); + } +}); + +erpnext.is_demo_company_setup = function() { + frappe.db.get_value("Global Default", "Global Default", "demo_company", function(r) { + console.log(r); + }); +}; \ No newline at end of file diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index 46500da15c7..882ed37a92c 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -28,7 +28,7 @@ def clear_demo_data(): def create_demo_company(): - company = erpnext.get_default_company() + company = frappe.db.get_all("Company")[0].name company_doc = frappe.get_doc("Company", company) # Make a dummy company diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py index 65b268e385c..ad49be647b0 100644 --- a/erpnext/setup/setup_wizard/setup_wizard.py +++ b/erpnext/setup/setup_wizard/setup_wizard.py @@ -5,6 +5,7 @@ import frappe from frappe import _ +from ..demo import setup_demo_data from .operations import install_fixtures as fixtures @@ -36,6 +37,11 @@ def get_setup_stages(args=None): {"fn": setup_defaults, "args": args, "fail_msg": _("Failed to setup defaults")}, ], }, + { + "status": _("Setting up demo data"), + "fail_msg": _("Failed to setup demo data"), + "tasks": [{"fn": setup_demo, "args": args, "fail_msg": _("Failed to login")}], + }, { "status": _("Wrapping up"), "fail_msg": _("Failed to login"), @@ -63,6 +69,11 @@ def fin(args): login_as_first_user(args) +def setup_demo(args): + if args.get("setup_demo"): + setup_demo_data() + + def login_as_first_user(args): if args.get("email") and hasattr(frappe.local, "login_manager"): frappe.local.login_manager.login_as(args.get("email")) From 371413a078123b83480c04026b57a05e21a3c214 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sat, 29 Jul 2023 22:39:07 +0530 Subject: [PATCH 09/46] fix: Button to clear demo data --- erpnext/public/js/erpnext.bundle.js | 1 + erpnext/public/js/utils/demo.js | 62 +++++++++++++++++++++++++---- erpnext/setup/demo.py | 6 +-- erpnext/startup/boot.py | 2 + 4 files changed, 60 insertions(+), 11 deletions(-) diff --git a/erpnext/public/js/erpnext.bundle.js b/erpnext/public/js/erpnext.bundle.js index d7bea7b8341..966a9e1f9b3 100644 --- a/erpnext/public/js/erpnext.bundle.js +++ b/erpnext/public/js/erpnext.bundle.js @@ -28,5 +28,6 @@ import "./controllers/accounts.js" import "./utils/landed_taxes_and_charges_common.js"; import "./utils/sales_common.js"; import "./controllers/buying.js"; +import "./utils/demo.js"; // import { sum } from 'frappe/public/utils/util.js' diff --git a/erpnext/public/js/utils/demo.js b/erpnext/public/js/utils/demo.js index 432bad63239..22d78d8c67c 100644 --- a/erpnext/public/js/utils/demo.js +++ b/erpnext/public/js/utils/demo.js @@ -1,11 +1,57 @@ $(document).on("toolbar_setup", function() { - if (erpnext.is_demo_company_setup) { - console.log("setup"); - } + if (frappe.boot.sysdefaults.demo_company) { + erpnext.setup_clear_button(); + } }); -erpnext.is_demo_company_setup = function() { - frappe.db.get_value("Global Default", "Global Default", "demo_company", function(r) { - console.log(r); - }); -}; \ No newline at end of file +erpnext.setup_clear_button = function() { + let message_string = __('Demo data is setup, use this button to clear before starting actual transactions'); + let $floatingBar = $(` +
+
+

+ ${message_string} +

+ +
+
+ `); + + $('footer').append($floatingBar); + + $('#clear-demo').on('click', function () { + frappe.call({ + method: "erpnext.setup.demo.clear_demo_data", + freeze: true, + freeze_message: __('Clearing Demo Data...'), + callback: function(r) { + frappe.ui.toolbar.clear_cache(); + frappe.show_alert({ message: __('Demo data cleared'), indicator: 'green' }); + $('footer').remove($floatingBar); + } + }) + }); +} \ No newline at end of file diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index 882ed37a92c..b8cdc05dd3e 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -6,9 +6,10 @@ import os from random import randint import frappe -from frappe.utils import add_days +from frappe.utils import add_days, getdate import erpnext +from erpnext.accounts.utils import get_fiscal_year from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account @@ -65,8 +66,7 @@ def create_demo_record(doctype): def make_transactions(company): - fiscal_year = frappe.db.get_single_value("Global Defaults", "current_fiscal_year") - start_date = frappe.db.get_value("Fiscal Year", fiscal_year, "year_start_date") + start_date = get_fiscal_year(date=getdate())[1] frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1) for doctype in frappe.get_hooks("demo_transaction_doctypes"): diff --git a/erpnext/startup/boot.py b/erpnext/startup/boot.py index db1cc494e0b..bdbf8b4fac5 100644 --- a/erpnext/startup/boot.py +++ b/erpnext/startup/boot.py @@ -61,6 +61,8 @@ def boot_session(bootinfo): ) bootinfo.party_account_types = frappe._dict(party_account_types) + bootinfo.sysdefaults.demo_company = frappe.db.get_single_value("Global Defaults", "demo_company") + def update_page_info(bootinfo): bootinfo.page_info.update( From 26ee50269a7358af336fbe660137b29eb39badf9 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 30 Jul 2023 11:52:49 +0530 Subject: [PATCH 10/46] test: Update demo setup test --- erpnext/setup/doctype/company/test_company.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/erpnext/setup/doctype/company/test_company.py b/erpnext/setup/doctype/company/test_company.py index 0ed9621ca43..babd7dd4e84 100644 --- a/erpnext/setup/doctype/company/test_company.py +++ b/erpnext/setup/doctype/company/test_company.py @@ -202,9 +202,14 @@ class TestCompany(unittest.TestCase): company_name = frappe.db.get_value("Company", {"name": ("like", "%(Demo)")}) self.assertTrue(company_name) + for transaction in frappe.get_hooks("demo_transaction_doctypes"): + self.assertTrue(frappe.db.exists(frappe.unscrub(transaction), {"company": company_name})) + clear_demo_data() company_name = frappe.db.get_value("Company", {"name": ("like", "%(Demo)")}) self.assertFalse(company_name) + for transaction in frappe.get_hooks("demo_transaction_doctypes"): + self.assertFalse(frappe.db.exists(frappe.unscrub(transaction), {"company": company_name})) def create_company_communication(doctype, docname): From c850f46c0ad9ec3bedb7be9d7d811f40f1a99167 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 30 Jul 2023 11:53:09 +0530 Subject: [PATCH 11/46] chore: Update records --- erpnext/setup/demo_data/payment_entry.json | 45 +++++++++++++++++++ erpnext/setup/demo_data/purchase_invoice.json | 36 +++++++-------- .../operations/install_fixtures.py | 15 +++++++ 3 files changed, 78 insertions(+), 18 deletions(-) diff --git a/erpnext/setup/demo_data/payment_entry.json b/erpnext/setup/demo_data/payment_entry.json index 7d8d7d5ca2c..c0767c3114d 100644 --- a/erpnext/setup/demo_data/payment_entry.json +++ b/erpnext/setup/demo_data/payment_entry.json @@ -1,6 +1,7 @@ [ { "doctype": "Payment Entry", + "payment_type": "Receive", "party_type": "Customer", "party": "ABC Enterprises", "paid_amount": 67000, @@ -8,5 +9,49 @@ "reference_no": "#ref0001", "source_exchange_rate": 1, "target_exchange_rate": 1 + }, + { + "doctype": "Payment Entry", + "payment_type": "Receive", + "party_type": "Customer", + "party": "XYZ Corporation", + "paid_amount": 500000, + "received_amount": 500000, + "reference_no": "#ref0001", + "source_exchange_rate": 1, + "target_exchange_rate": 1 + }, + { + "doctype": "Payment Entry", + "payment_type": "Receive", + "party_type": "Customer", + "party": "KJPR Pvt. Ltd.", + "paid_amount": 300000, + "received_amount": 30000, + "reference_no": "#ref0001", + "source_exchange_rate": 1, + "target_exchange_rate": 1 + }, + { + "doctype": "Payment Entry", + "payment_type": "Pay", + "party_type": "Supplier", + "party": "DQ Industries", + "paid_amount": 85000, + "received_amount": 85000, + "reference_no": "#ref0005", + "source_exchange_rate": 1, + "target_exchange_rate": 1 + }, + { + "doctype": "Payment Entry", + "payment_type": "Pay", + "party_type": "Supplier", + "party": "KC Corp.", + "paid_amount": 100000, + "received_amount": 100000, + "reference_no": "#ref0006", + "source_exchange_rate": 1, + "target_exchange_rate": 1 } ] \ No newline at end of file diff --git a/erpnext/setup/demo_data/purchase_invoice.json b/erpnext/setup/demo_data/purchase_invoice.json index eda26b0502d..7d5e97d1726 100644 --- a/erpnext/setup/demo_data/purchase_invoice.json +++ b/erpnext/setup/demo_data/purchase_invoice.json @@ -25,8 +25,8 @@ "doctype": "Purchase Invoice Item", "item_code": "SKU002", "parentfield": "items", - "qty": 100.0, - "rate": 400.0, + "qty": 50.0, + "rate": 300.0, "conversion_factor": 1 } ] @@ -41,8 +41,8 @@ "doctype": "Purchase Invoice Item", "item_code": "SKU003", "parentfield": "items", - "qty": 100.0, - "rate": 400.0, + "qty": 75.0, + "rate": 523.0, "conversion_factor": 1 } ] @@ -57,8 +57,8 @@ "doctype": "Purchase Invoice Item", "item_code": "SKU004", "parentfield": "items", - "qty": 100.0, - "rate": 400.0, + "qty": 60.0, + "rate": 725.0, "conversion_factor": 1 } ] @@ -73,8 +73,8 @@ "doctype": "Purchase Invoice Item", "item_code": "SKU005", "parentfield": "items", - "qty": 100.0, - "rate": 400.0, + "qty": 82.0, + "rate": 222.0, "conversion_factor": 1 } ] @@ -89,8 +89,8 @@ "doctype": "Purchase Invoice Item", "item_code": "SKU006", "parentfield": "items", - "qty": 100.0, - "rate": 400.0, + "qty": 50.0, + "rate": 420.0, "conversion_factor": 1 } ] @@ -105,8 +105,8 @@ "doctype": "Purchase Invoice Item", "item_code": "SKU007", "parentfield": "items", - "qty": 100.0, - "rate": 400.0, + "qty": 90.0, + "rate": 375.0, "conversion_factor": 1 } ] @@ -121,8 +121,8 @@ "doctype": "Purchase Invoice Item", "item_code": "SKU008", "parentfield": "items", - "qty": 100.0, - "rate": 400.0, + "qty": 121.0, + "rate": 333.0, "conversion_factor": 1 } ] @@ -137,8 +137,8 @@ "doctype": "Purchase Invoice Item", "item_code": "SKU009", "parentfield": "items", - "qty": 100.0, - "rate": 400.0, + "qty": 76.0, + "rate": 700.0, "conversion_factor": 1 } ] @@ -153,8 +153,8 @@ "doctype": "Purchase Invoice Item", "item_code": "SKU010", "parentfield": "items", - "qty": 100.0, - "rate": 400.0, + "qty": 78.0, + "rate": 500.0, "conversion_factor": 1 } ] diff --git a/erpnext/setup/setup_wizard/operations/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py index 2205924e509..ae6881b99e0 100644 --- a/erpnext/setup/setup_wizard/operations/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -454,6 +454,7 @@ def install_defaults(args=None): # nosemgrep set_global_defaults(args) update_stock_settings() + update_shopping_cart_settings(args) args.update({"set_default": 1}) create_bank_account(args) @@ -528,6 +529,20 @@ def create_bank_account(args): pass +def update_shopping_cart_settings(args): # nosemgrep + shopping_cart = frappe.get_doc("E Commerce Settings") + shopping_cart.update( + { + "enabled": 1, + "company": args.company_name, + "price_list": frappe.db.get_value("Price List", {"selling": 1}), + "default_customer_group": _("Individual"), + "quotation_series": "QTN-", + } + ) + shopping_cart.update_single(shopping_cart.get_valid_dict()) + + def get_fy_details(fy_start_date, fy_end_date): start_year = getdate(fy_start_date).year if start_year == getdate(fy_end_date).year: From 7805abbb2dafdd16a22dc8bcb63211a7534db40b Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Sun, 30 Jul 2023 20:29:20 +0530 Subject: [PATCH 12/46] fix: reset default company --- erpnext/setup/demo.py | 2 ++ 1 file changed, 2 insertions(+) diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index b8cdc05dd3e..a6d90eda96d 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -26,6 +26,8 @@ def clear_demo_data(): create_transaction_deletion_record(company) clear_masters() delete_company(company) + default_company = frappe.db.get_single_value("Global Defaults", "default_company") + frappe.db.set_default("company", default_company) def create_demo_company(): From 333f2a565bd357809f154d40c19d9fd565b5afc8 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Tue, 1 Aug 2023 10:10:50 +0530 Subject: [PATCH 13/46] fix: Add journal entry in demo --- erpnext/hooks.py | 2 +- erpnext/setup/demo.py | 27 ++++++++++++++-------- erpnext/setup/demo_data/journal_entry.json | 25 ++++++++++++++++++++ 3 files changed, 44 insertions(+), 10 deletions(-) create mode 100644 erpnext/setup/demo_data/journal_entry.json diff --git a/erpnext/hooks.py b/erpnext/hooks.py index e5d93186031..a9eef944578 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -78,7 +78,7 @@ demo_master_doctypes = [ "customer", "supplier", ] -demo_transaction_doctypes = ["purchase_invoice", "sales_invoice", "payment_entry"] +demo_transaction_doctypes = ["purchase_invoice", "sales_invoice", "payment_entry", "journal_entry"] jinja = { "methods": [ diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index a6d90eda96d..50bc43d3258 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -83,7 +83,9 @@ def create_transaction(doctype, company, start_date): posting_date = ( start_date if doctype.get("doctype") == "Purchase Invoice" else get_random_date(start_date) ) - bank_account = frappe.db.get_value("Company", company, "default_bank_account") + bank_account, default_receivable_account = frappe.db.get_value( + "Company", company, ["default_bank_account", "default_receivable_account"] + ) bank_field = "paid_to" if doctype.get("party_type") == "Customer" else "paid_from" doctype.update( @@ -101,20 +103,27 @@ def create_transaction(doctype, company, start_date): "Company", company, ["default_income_account", "default_expense_account"] ) - for item in doctype.get("items") or []: - item.update( - { - "cost_center": erpnext.get_default_cost_center(company), - "income_account": income_account, - "expense_account": expense_account, - } - ) + if doctype in ("Purchase Invoice", "Sales Invoice"): + for item in doctype.get("items") or []: + item.update( + { + "cost_center": erpnext.get_default_cost_center(company), + "income_account": income_account, + "expense_account": expense_account, + } + ) + elif doctype == "Journal Entry": + pass + # update_accounts(doctype, bank_account, default_receivable_account) doc = frappe.get_doc(doctype) doc.save(ignore_permissions=True) doc.submit() +# def update_accounts(doctype, company, bank_account): + + def get_random_date(start_date): return add_days(start_date, randint(1, 365)) diff --git a/erpnext/setup/demo_data/journal_entry.json b/erpnext/setup/demo_data/journal_entry.json new file mode 100644 index 00000000000..b751c7cf244 --- /dev/null +++ b/erpnext/setup/demo_data/journal_entry.json @@ -0,0 +1,25 @@ +[ + { + "cheque_date": "2023-03-14", + "cheque_no": "33", + "doctype": "Journal Entry", + "accounts": [ + { + "party_type": "Customer", + "party": "ABC Enterprises", + "credit_in_account_currency": 40000.0, + "debit_in_account_currency": 0.0, + "doctype": "Journal Entry Account", + "parentfield": "accounts", + }, + { + "credit_in_account_currency": 0.0, + "debit_in_account_currency": 40000.0, + "doctype": "Journal Entry Account", + "parentfield": "accounts", + } + ], + "user_remark": "test", + "voucher_type": "Bank Entry" + } +] \ No newline at end of file From 4fb844ab70d2400afe2f1f09299b8d973f229744 Mon Sep 17 00:00:00 2001 From: barredterra <14891507+barredterra@users.noreply.github.com> Date: Tue, 8 Aug 2023 16:30:53 +0200 Subject: [PATCH 14/46] fix(RFQ): hide description in print and report --- .../request_for_quotation/request_for_quotation.json | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json index 158334f9632..fbfc1ac1693 100644 --- a/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json +++ b/erpnext/buying/doctype/request_for_quotation/request_for_quotation.json @@ -273,7 +273,9 @@ "fieldname": "html_llwp", "fieldtype": "HTML", "options": "

In your Email Template, you can use the following special variables:\n

\n
    \n
  • \n {{ update_password_link }}: A link where your supplier can set a new password to log into your portal.\n
  • \n
  • \n {{ portal_link }}: A link to this RFQ in your supplier portal.\n
  • \n
  • \n {{ supplier_name }}: The company name of your supplier.\n
  • \n
  • \n {{ contact.salutation }} {{ contact.last_name }}: The contact person of your supplier.\n
  • \n {{ user_fullname }}: Your full name.\n
  • \n
\n

\n

Apart from these, you can access all values in this RFQ, like {{ message_for_supplier }} or {{ terms }}.

", - "read_only": 1 + "print_hide": 1, + "read_only": 1, + "report_hide": 1 }, { "default": "1", @@ -287,7 +289,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-07-27 16:41:48.468873", + "modified": "2023-08-08 16:30:10.870429", "modified_by": "Administrator", "module": "Buying", "name": "Request for Quotation", From b0c79a0467272bf38553e45d3e067b52285cbfd8 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 9 Aug 2023 13:37:19 +0530 Subject: [PATCH 15/46] perf(invoice): Faster return amount query (#36556) perf: Faster return amount query --- erpnext/accounts/doctype/sales_invoice/sales_invoice.py | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py index db120740dcc..0bc5aa2ed2d 100644 --- a/erpnext/accounts/doctype/sales_invoice/sales_invoice.py +++ b/erpnext/accounts/doctype/sales_invoice/sales_invoice.py @@ -1654,15 +1654,13 @@ class SalesInvoice(SellingController): frappe.db.set_value("Customer", self.customer, "loyalty_program_tier", lp_details.tier_name) def get_returned_amount(self): - from frappe.query_builder.functions import Coalesce, Sum + from frappe.query_builder.functions import Sum doc = frappe.qb.DocType(self.doctype) returned_amount = ( frappe.qb.from_(doc) .select(Sum(doc.grand_total)) - .where( - (doc.docstatus == 1) & (doc.is_return == 1) & (Coalesce(doc.return_against, "") == self.name) - ) + .where((doc.docstatus == 1) & (doc.is_return == 1) & (doc.return_against == self.name)) ).run() return abs(returned_amount[0][0]) if returned_amount[0][0] else 0 From 9db8769e652488f545b74b86d008afbecf15f6ba Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 9 Aug 2023 13:54:26 +0530 Subject: [PATCH 16/46] fix: broken `bench update` after subscription refactor --- erpnext/patches.txt | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/patches.txt b/erpnext/patches.txt index d53bacea64d..d035ad6fe7c 100644 --- a/erpnext/patches.txt +++ b/erpnext/patches.txt @@ -262,7 +262,6 @@ erpnext.patches.v14_0.update_reference_due_date_in_journal_entry erpnext.patches.v15_0.saudi_depreciation_warning erpnext.patches.v15_0.delete_saudi_doctypes erpnext.patches.v14_0.show_loan_management_deprecation_warning -erpnext.patches.v14_0.update_subscription_details execute:frappe.rename_doc("Report", "TDS Payable Monthly", "Tax Withholding Details", force=True) [post_model_sync] @@ -322,6 +321,7 @@ erpnext.patches.v14_0.create_accounting_dimensions_for_closing_balance erpnext.patches.v14_0.update_closing_balances #14-07-2023 execute:frappe.db.set_single_value("Accounts Settings", "merge_similar_account_heads", 0) erpnext.patches.v14_0.update_reference_type_in_journal_entry_accounts +erpnext.patches.v14_0.update_subscription_details # below migration patches should always run last erpnext.patches.v14_0.migrate_gl_to_payment_ledger execute:frappe.delete_doc_if_exists("Report", "Tax Detail") From 5740942de90ae87d30928efda283ab74761761b5 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Wed, 9 Aug 2023 15:32:26 +0530 Subject: [PATCH 17/46] fix: lowercase fieldnames --- erpnext/patches/v14_0/update_subscription_details.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/patches/v14_0/update_subscription_details.py b/erpnext/patches/v14_0/update_subscription_details.py index 729ac1895a1..58ab16d39e3 100644 --- a/erpnext/patches/v14_0/update_subscription_details.py +++ b/erpnext/patches/v14_0/update_subscription_details.py @@ -10,7 +10,7 @@ def execute(): frappe.db.set_value( subscription_invoice.document_type, subscription_invoice.invoice, - "Subscription", + "subscription", subscription_invoice.parent, ) From 32863b492242dc0a761eb70b3e21663e78777aa6 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Wed, 9 Aug 2023 15:36:28 +0530 Subject: [PATCH 18/46] fix: Make default sales update frequency as monthly instead of each transaction --- .../selling/doctype/selling_settings/selling_settings.json | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/erpnext/selling/doctype/selling_settings/selling_settings.json b/erpnext/selling/doctype/selling_settings/selling_settings.json index 045227f0aa4..f3b9f6f3b06 100644 --- a/erpnext/selling/doctype/selling_settings/selling_settings.json +++ b/erpnext/selling/doctype/selling_settings/selling_settings.json @@ -85,7 +85,7 @@ "fieldname": "sales_update_frequency", "fieldtype": "Select", "label": "Sales Update Frequency in Company and Project", - "options": "Each Transaction\nDaily\nMonthly", + "options": "Monthly\nEach Transaction\nDaily", "reqd": 1 }, { @@ -200,7 +200,7 @@ "index_web_pages_for_search": 1, "issingle": 1, "links": [], - "modified": "2023-02-04 12:37:53.380857", + "modified": "2023-08-09 15:35:42.914354", "modified_by": "Administrator", "module": "Selling", "name": "Selling Settings", @@ -229,4 +229,4 @@ "sort_order": "DESC", "states": [], "track_changes": 1 -} +} \ No newline at end of file From ad33cd73e8b46fbd89321f3d2c6f519d5315020d Mon Sep 17 00:00:00 2001 From: Anand Baburajan Date: Wed, 9 Aug 2023 20:26:28 +0530 Subject: [PATCH 19/46] perf: asset depreciation entry posting [develop] (#36555) * perf: optimise post_depreciation_entries and make_depreciation_entry * chore: fixing minor mistake * chore: fix asset_value_adjustment test --- erpnext/assets/doctype/asset/asset.py | 8 +- erpnext/assets/doctype/asset/depreciation.py | 343 +++++++++++++----- .../asset_value_adjustment.py | 8 +- erpnext/hooks.py | 2 +- 4 files changed, 257 insertions(+), 104 deletions(-) diff --git a/erpnext/assets/doctype/asset/asset.py b/erpnext/assets/doctype/asset/asset.py index 04ec7be3cd8..2060c6ca835 100644 --- a/erpnext/assets/doctype/asset/asset.py +++ b/erpnext/assets/doctype/asset/asset.py @@ -478,7 +478,9 @@ class Asset(AccountsController): @frappe.whitelist() def get_manual_depreciation_entries(self): - (_, _, depreciation_expense_account) = get_depreciation_accounts(self) + (_, _, depreciation_expense_account) = get_depreciation_accounts( + self.asset_category, self.company + ) gle = frappe.qb.DocType("GL Entry") @@ -821,10 +823,10 @@ def get_asset_account(account_name, asset=None, asset_category=None, company=Non def make_journal_entry(asset_name): asset = frappe.get_doc("Asset", asset_name) ( - fixed_asset_account, + _, accumulated_depreciation_account, depreciation_expense_account, - ) = get_depreciation_accounts(asset) + ) = get_depreciation_accounts(asset.asset_category, asset.company) depreciation_cost_center, depreciation_series = frappe.get_cached_value( "Company", asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"] diff --git a/erpnext/assets/doctype/asset/depreciation.py b/erpnext/assets/doctype/asset/depreciation.py index 0588065d396..e2a4b2909a5 100644 --- a/erpnext/assets/doctype/asset/depreciation.py +++ b/erpnext/assets/doctype/asset/depreciation.py @@ -4,6 +4,8 @@ import frappe from frappe import _ +from frappe.query_builder import Order +from frappe.query_builder.functions import Max, Min from frappe.utils import ( add_months, cint, @@ -43,11 +45,48 @@ def post_depreciation_entries(date=None): failed_asset_names = [] error_log_names = [] - for asset_name in get_depreciable_assets(date): - asset_doc = frappe.get_doc("Asset", asset_name) + depreciable_asset_depr_schedules_data = get_depreciable_asset_depr_schedules_data(date) + + credit_and_debit_accounts_for_asset_category_and_company = {} + depreciation_cost_center_and_depreciation_series_for_company = ( + get_depreciation_cost_center_and_depreciation_series_for_company() + ) + + accounting_dimensions = get_checks_for_pl_and_bs_accounts() + + for asset_depr_schedule_data in depreciable_asset_depr_schedules_data: + ( + asset_depr_schedule_name, + asset_name, + asset_category, + asset_company, + sch_start_idx, + sch_end_idx, + ) = asset_depr_schedule_data + + if ( + asset_category, + asset_company, + ) not in credit_and_debit_accounts_for_asset_category_and_company: + credit_and_debit_accounts_for_asset_category_and_company.update( + { + (asset_category, asset_company): get_credit_and_debit_accounts_for_asset_category_and_company( + asset_category, asset_company + ), + } + ) try: - make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date) + make_depreciation_entry( + asset_depr_schedule_name, + date, + sch_start_idx, + sch_end_idx, + credit_and_debit_accounts_for_asset_category_and_company[(asset_category, asset_company)], + depreciation_cost_center_and_depreciation_series_for_company[asset_company], + accounting_dimensions, + ) + frappe.db.commit() except Exception as e: frappe.db.rollback() @@ -62,18 +101,36 @@ def post_depreciation_entries(date=None): frappe.db.commit() -def get_depreciable_assets(date): - return frappe.db.sql_list( - """select distinct a.name - from tabAsset a, `tabAsset Depreciation Schedule` ads, `tabDepreciation Schedule` ds - where a.name = ads.asset and ads.name = ds.parent and a.docstatus=1 and ads.docstatus=1 - and a.status in ('Submitted', 'Partially Depreciated') - and a.calculate_depreciation = 1 - and ds.schedule_date<=%s - and ifnull(ds.journal_entry, '')=''""", - date, +def get_depreciable_asset_depr_schedules_data(date): + a = frappe.qb.DocType("Asset") + ads = frappe.qb.DocType("Asset Depreciation Schedule") + ds = frappe.qb.DocType("Depreciation Schedule") + + res = ( + frappe.qb.from_(ads) + .join(a) + .on(ads.asset == a.name) + .join(ds) + .on(ads.name == ds.parent) + .select(ads.name, a.name, a.asset_category, a.company, Min(ds.idx) - 1, Max(ds.idx)) + .where(a.calculate_depreciation == 1) + .where(a.docstatus == 1) + .where(ads.docstatus == 1) + .where(a.status.isin(["Submitted", "Partially Depreciated"])) + .where(ds.journal_entry.isnull()) + .where(ds.schedule_date <= date) + .groupby(ads.name) + .orderby(a.creation, order=Order.desc) ) + acc_frozen_upto = get_acc_frozen_upto() + if acc_frozen_upto: + res = res.where(ds.schedule_date > acc_frozen_upto) + + res = res.run() + + return res + def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None): for row in asset_doc.get("finance_books"): @@ -83,8 +140,60 @@ def make_depreciation_entry_for_all_asset_depr_schedules(asset_doc, date=None): make_depreciation_entry(asset_depr_schedule_name, date) +def get_acc_frozen_upto(): + acc_frozen_upto = frappe.db.get_single_value("Accounts Settings", "acc_frozen_upto") + + if not acc_frozen_upto: + return + + frozen_accounts_modifier = frappe.db.get_single_value( + "Accounts Settings", "frozen_accounts_modifier" + ) + + if frozen_accounts_modifier not in frappe.get_roles() or frappe.session.user == "Administrator": + return getdate(acc_frozen_upto) + + return + + +def get_credit_and_debit_accounts_for_asset_category_and_company(asset_category, company): + ( + _, + accumulated_depreciation_account, + depreciation_expense_account, + ) = get_depreciation_accounts(asset_category, company) + + credit_account, debit_account = get_credit_and_debit_accounts( + accumulated_depreciation_account, depreciation_expense_account + ) + + return (credit_account, debit_account) + + +def get_depreciation_cost_center_and_depreciation_series_for_company(): + company_names = frappe.db.get_all("Company", pluck="name") + + res = {} + + for company_name in company_names: + depreciation_cost_center, depreciation_series = frappe.get_cached_value( + "Company", company_name, ["depreciation_cost_center", "series_for_depreciation_entry"] + ) + res.update({company_name: (depreciation_cost_center, depreciation_series)}) + + return res + + @frappe.whitelist() -def make_depreciation_entry(asset_depr_schedule_name, date=None): +def make_depreciation_entry( + asset_depr_schedule_name, + date=None, + sch_start_idx=None, + sch_end_idx=None, + credit_and_debit_accounts=None, + depreciation_cost_center_and_depreciation_series=None, + accounting_dimensions=None, +): frappe.has_permission("Journal Entry", throw=True) if not date: @@ -92,100 +201,144 @@ def make_depreciation_entry(asset_depr_schedule_name, date=None): asset_depr_schedule_doc = frappe.get_doc("Asset Depreciation Schedule", asset_depr_schedule_name) - asset_name = asset_depr_schedule_doc.asset + asset = frappe.get_doc("Asset", asset_depr_schedule_doc.asset) - asset = frappe.get_doc("Asset", asset_name) - ( - fixed_asset_account, - accumulated_depreciation_account, - depreciation_expense_account, - ) = get_depreciation_accounts(asset) + if credit_and_debit_accounts: + credit_account, debit_account = credit_and_debit_accounts + else: + credit_account, debit_account = get_credit_and_debit_accounts_for_asset_category_and_company( + asset.asset_category, asset.company + ) - depreciation_cost_center, depreciation_series = frappe.get_cached_value( - "Company", asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"] - ) + if depreciation_cost_center_and_depreciation_series: + depreciation_cost_center, depreciation_series = depreciation_cost_center_and_depreciation_series + else: + depreciation_cost_center, depreciation_series = frappe.get_cached_value( + "Company", asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"] + ) depreciation_cost_center = asset.cost_center or depreciation_cost_center - accounting_dimensions = get_checks_for_pl_and_bs_accounts() + if not accounting_dimensions: + accounting_dimensions = get_checks_for_pl_and_bs_accounts() - for d in asset_depr_schedule_doc.get("depreciation_schedule"): - if not d.journal_entry and getdate(d.schedule_date) <= getdate(date): - je = frappe.new_doc("Journal Entry") - je.voucher_type = "Depreciation Entry" - je.naming_series = depreciation_series - je.posting_date = d.schedule_date - je.company = asset.company - je.finance_book = asset_depr_schedule_doc.finance_book - je.remark = "Depreciation Entry against {0} worth {1}".format(asset_name, d.depreciation_amount) + depreciation_posting_error = None - credit_account, debit_account = get_credit_and_debit_accounts( - accumulated_depreciation_account, depreciation_expense_account + for d in asset_depr_schedule_doc.get("depreciation_schedule")[ + sch_start_idx or 0 : sch_end_idx or len(asset_depr_schedule_doc.get("depreciation_schedule")) + ]: + try: + _make_journal_entry_for_depreciation( + asset_depr_schedule_doc, + asset, + date, + d, + sch_start_idx, + sch_end_idx, + depreciation_cost_center, + depreciation_series, + credit_account, + debit_account, + accounting_dimensions, ) - - credit_entry = { - "account": credit_account, - "credit_in_account_currency": d.depreciation_amount, - "reference_type": "Asset", - "reference_name": asset.name, - "cost_center": depreciation_cost_center, - } - - debit_entry = { - "account": debit_account, - "debit_in_account_currency": d.depreciation_amount, - "reference_type": "Asset", - "reference_name": asset.name, - "cost_center": depreciation_cost_center, - } - - for dimension in accounting_dimensions: - if asset.get(dimension["fieldname"]) or dimension.get("mandatory_for_bs"): - credit_entry.update( - { - dimension["fieldname"]: asset.get(dimension["fieldname"]) - or dimension.get("default_dimension") - } - ) - - if asset.get(dimension["fieldname"]) or dimension.get("mandatory_for_pl"): - debit_entry.update( - { - dimension["fieldname"]: asset.get(dimension["fieldname"]) - or dimension.get("default_dimension") - } - ) - - je.append("accounts", credit_entry) - - je.append("accounts", debit_entry) - - je.flags.ignore_permissions = True - je.flags.planned_depr_entry = True - je.save() - - d.db_set("journal_entry", je.name) - - if not je.meta.get_workflow(): - je.submit() - idx = cint(asset_depr_schedule_doc.finance_book_id) - row = asset.get("finance_books")[idx - 1] - row.value_after_depreciation -= d.depreciation_amount - row.db_update() - - asset.db_set("depr_entry_posting_status", "Successful") + frappe.db.commit() + except Exception as e: + frappe.db.rollback() + depreciation_posting_error = e asset.set_status() - return asset_depr_schedule_doc + if not depreciation_posting_error: + asset.db_set("depr_entry_posting_status", "Successful") + return asset_depr_schedule_doc + + raise depreciation_posting_error -def get_depreciation_accounts(asset): +def _make_journal_entry_for_depreciation( + asset_depr_schedule_doc, + asset, + date, + depr_schedule, + sch_start_idx, + sch_end_idx, + depreciation_cost_center, + depreciation_series, + credit_account, + debit_account, + accounting_dimensions, +): + if not (sch_start_idx and sch_end_idx) and not ( + not depr_schedule.journal_entry and getdate(depr_schedule.schedule_date) <= getdate(date) + ): + return + + je = frappe.new_doc("Journal Entry") + je.voucher_type = "Depreciation Entry" + je.naming_series = depreciation_series + je.posting_date = depr_schedule.schedule_date + je.company = asset.company + je.finance_book = asset_depr_schedule_doc.finance_book + je.remark = "Depreciation Entry against {0} worth {1}".format( + asset.name, depr_schedule.depreciation_amount + ) + + credit_entry = { + "account": credit_account, + "credit_in_account_currency": depr_schedule.depreciation_amount, + "reference_type": "Asset", + "reference_name": asset.name, + "cost_center": depreciation_cost_center, + } + + debit_entry = { + "account": debit_account, + "debit_in_account_currency": depr_schedule.depreciation_amount, + "reference_type": "Asset", + "reference_name": asset.name, + "cost_center": depreciation_cost_center, + } + + for dimension in accounting_dimensions: + if asset.get(dimension["fieldname"]) or dimension.get("mandatory_for_bs"): + credit_entry.update( + { + dimension["fieldname"]: asset.get(dimension["fieldname"]) + or dimension.get("default_dimension") + } + ) + + if asset.get(dimension["fieldname"]) or dimension.get("mandatory_for_pl"): + debit_entry.update( + { + dimension["fieldname"]: asset.get(dimension["fieldname"]) + or dimension.get("default_dimension") + } + ) + + je.append("accounts", credit_entry) + je.append("accounts", debit_entry) + + je.flags.ignore_permissions = True + je.flags.planned_depr_entry = True + je.save() + + depr_schedule.db_set("journal_entry", je.name) + + if not je.meta.get_workflow(): + je.submit() + idx = cint(asset_depr_schedule_doc.finance_book_id) + row = asset.get("finance_books")[idx - 1] + row.value_after_depreciation -= depr_schedule.depreciation_amount + row.db_update() + + +def get_depreciation_accounts(asset_category, company): fixed_asset_account = accumulated_depreciation_account = depreciation_expense_account = None accounts = frappe.db.get_value( "Asset Category Account", - filters={"parent": asset.asset_category, "company_name": asset.company}, + filters={"parent": asset_category, "company_name": company}, fieldname=[ "fixed_asset_account", "accumulated_depreciation_account", @@ -201,7 +354,7 @@ def get_depreciation_accounts(asset): if not accumulated_depreciation_account or not depreciation_expense_account: accounts = frappe.get_cached_value( - "Company", asset.company, ["accumulated_depreciation_account", "depreciation_expense_account"] + "Company", company, ["accumulated_depreciation_account", "depreciation_expense_account"] ) if not accumulated_depreciation_account: @@ -216,7 +369,7 @@ def get_depreciation_accounts(asset): ): frappe.throw( _("Please set Depreciation related Accounts in Asset Category {0} or Company {1}").format( - asset.asset_category, asset.company + asset_category, company ) ) @@ -565,8 +718,8 @@ def get_gl_entries_on_asset_disposal( def get_asset_details(asset, finance_book=None): - fixed_asset_account, accumulated_depr_account, depr_expense_account = get_depreciation_accounts( - asset + fixed_asset_account, accumulated_depr_account, _ = get_depreciation_accounts( + asset.asset_category, asset.company ) disposal_account, depreciation_cost_center = get_disposal_account_and_cost_center(asset.company) depreciation_cost_center = asset.cost_center or depreciation_cost_center diff --git a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py index a1f047352c4..823b6e9e21d 100644 --- a/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py +++ b/erpnext/assets/doctype/asset_value_adjustment/asset_value_adjustment.py @@ -64,10 +64,10 @@ class AssetValueAdjustment(Document): def make_depreciation_entry(self): asset = frappe.get_doc("Asset", self.asset) ( - fixed_asset_account, + _, accumulated_depreciation_account, depreciation_expense_account, - ) = get_depreciation_accounts(asset) + ) = get_depreciation_accounts(asset.asset_category, asset.company) depreciation_cost_center, depreciation_series = frappe.get_cached_value( "Company", asset.company, ["depreciation_cost_center", "series_for_depreciation_entry"] @@ -78,9 +78,7 @@ class AssetValueAdjustment(Document): je.naming_series = depreciation_series je.posting_date = self.date je.company = self.company - je.remark = _("Depreciation Entry against {0} worth {1}").format( - self.asset, self.difference_amount - ) + je.remark = "Depreciation Entry against {0} worth {1}".format(self.asset, self.difference_amount) je.finance_book = self.finance_book credit_entry = { diff --git a/erpnext/hooks.py b/erpnext/hooks.py index d5eb4644064..44c68dcb574 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -429,7 +429,6 @@ scheduler_events = { "erpnext.controllers.accounts_controller.update_invoice_status", "erpnext.accounts.doctype.fiscal_year.fiscal_year.auto_create_fiscal_year", "erpnext.projects.doctype.task.task.set_tasks_as_overdue", - "erpnext.assets.doctype.asset.depreciation.post_depreciation_entries", "erpnext.stock.doctype.serial_no.serial_no.update_maintenance_status", "erpnext.buying.doctype.supplier_scorecard.supplier_scorecard.refresh_scorecards", "erpnext.setup.doctype.company.company.cache_companies_monthly_sales_history", @@ -454,6 +453,7 @@ scheduler_events = { "erpnext.setup.doctype.email_digest.email_digest.send", "erpnext.manufacturing.doctype.bom_update_tool.bom_update_tool.auto_update_latest_price_in_all_boms", "erpnext.crm.utils.open_leads_opportunities_based_on_todays_event", + "erpnext.assets.doctype.asset.depreciation.post_depreciation_entries", ], "monthly_long": [ "erpnext.accounts.deferred_revenue.process_deferred_accounting", From 47cb349362cd6a03cd544abea5483aff23b27e7e Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 9 Aug 2023 20:43:51 +0530 Subject: [PATCH 20/46] fix: better remarks on Cr note created by Reconciliation --- erpnext/accounts/doctype/journal_entry/journal_entry.py | 3 +++ .../payment_reconciliation/payment_reconciliation.py | 6 +++++- 2 files changed, 8 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.py b/erpnext/accounts/doctype/journal_entry/journal_entry.py index 22e092c0d04..85ef6f76d28 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.py +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.py @@ -797,6 +797,9 @@ class JournalEntry(AccountsController): def create_remarks(self): r = [] + if self.flags.skip_remarks_creation: + return + if self.user_remark: r.append(_("Note: {0}").format(self.user_remark)) diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index ea06e0ec9ae..82302cc08b8 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -6,7 +6,7 @@ import frappe from frappe import _, msgprint, qb from frappe.model.document import Document from frappe.query_builder.custom import ConstantColumn -from frappe.utils import flt, get_link_to_form, getdate, nowdate, today +from frappe.utils import flt, fmt_money, get_link_to_form, getdate, nowdate, today import erpnext from erpnext.accounts.doctype.process_payment_reconciliation.process_payment_reconciliation import ( @@ -657,6 +657,7 @@ def reconcile_dr_cr_note(dr_cr_notes, company): "reference_name": inv.against_voucher, "cost_center": erpnext.get_default_cost_center(company), "exchange_rate": inv.exchange_rate, + "user_remark": f"{fmt_money(flt(inv.allocated_amount), currency=company_currency)} against {inv.against_voucher}", }, { "account": inv.account, @@ -671,6 +672,7 @@ def reconcile_dr_cr_note(dr_cr_notes, company): "reference_name": inv.voucher_no, "cost_center": erpnext.get_default_cost_center(company), "exchange_rate": inv.exchange_rate, + "user_remark": f"{fmt_money(flt(inv.allocated_amount), currency=company_currency)} from {inv.voucher_no}", }, ], } @@ -678,6 +680,8 @@ def reconcile_dr_cr_note(dr_cr_notes, company): jv.flags.ignore_mandatory = True jv.flags.ignore_exchange_rate = True + jv.remark = None + jv.flags.skip_remarks_creation = True jv.submit() if inv.difference_amount != 0: From 3997aa77d40a5e9f6b6fd0554639be54bb977462 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Wed, 9 Aug 2023 20:50:11 +0530 Subject: [PATCH 21/46] refactor: add `is_system_generated` field to Journal Entry --- .../doctype/journal_entry/journal_entry.json | 53 +++++-------------- .../payment_reconciliation.py | 1 + 2 files changed, 13 insertions(+), 41 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json index 80e72226d3d..75c32a50189 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.json +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json @@ -9,6 +9,7 @@ "engine": "InnoDB", "field_order": [ "entry_type_and_date", + "is_system_generated", "title", "voucher_type", "naming_series", @@ -88,7 +89,7 @@ "label": "Entry Type", "oldfieldname": "voucher_type", "oldfieldtype": "Select", - "options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nExchange Gain Or Loss\nDeferred Revenue\nDeferred Expense", + "options": "Journal Entry\nInter Company Journal Entry\nBank Entry\nCash Entry\nCredit Card Entry\nDebit Note\nCredit Note\nContra Entry\nExcise Entry\nWrite Off Entry\nOpening Entry\nDepreciation Entry\nExchange Rate Revaluation\nExchange Gain Or Loss\nDeferred Revenue\nDeferred Expense\nReversal Of ITC", "reqd": 1, "search_index": 1 }, @@ -533,57 +534,27 @@ "label": "Process Deferred Accounting", "options": "Process Deferred Accounting", "read_only": 1 + }, + { + "default": "0", + "fieldname": "is_system_generated", + "fieldtype": "Check", + "hidden": 1, + "label": "Is System Generated", + "read_only": 1 } ], "icon": "fa fa-file-text", "idx": 176, "is_submittable": 1, "links": [], - "modified": "2023-03-01 14:58:59.286591", + "modified": "2023-08-09 20:47:27.719809", "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry", "naming_rule": "By \"Naming Series\" field", "owner": "Administrator", - "permissions": [ - { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts User", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "amend": 1, - "cancel": 1, - "create": 1, - "delete": 1, - "email": 1, - "export": 1, - "import": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Accounts Manager", - "share": 1, - "submit": 1, - "write": 1 - }, - { - "email": 1, - "print": 1, - "read": 1, - "report": 1, - "role": "Auditor" - } - ], + "permissions": [], "search_fields": "voucher_type,posting_date, due_date, cheque_no", "sort_field": "modified", "sort_order": "DESC", diff --git a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py index 82302cc08b8..3a9e80a9d94 100644 --- a/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py +++ b/erpnext/accounts/doctype/payment_reconciliation/payment_reconciliation.py @@ -682,6 +682,7 @@ def reconcile_dr_cr_note(dr_cr_notes, company): jv.flags.ignore_exchange_rate = True jv.remark = None jv.flags.skip_remarks_creation = True + jv.is_system_generated = True jv.submit() if inv.difference_amount != 0: From 4a7fc1506f8f9f5ee1c65c9e073e6e57c137c391 Mon Sep 17 00:00:00 2001 From: s-aga-r Date: Thu, 10 Aug 2023 09:40:58 +0530 Subject: [PATCH 22/46] fix: don't show disabled items in `Item Shortage Report` (#36550) --- .../report/item_shortage_report/item_shortage_report.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/erpnext/stock/report/item_shortage_report/item_shortage_report.py b/erpnext/stock/report/item_shortage_report/item_shortage_report.py index 9fafe91c3f9..4bd9a107e2c 100644 --- a/erpnext/stock/report/item_shortage_report/item_shortage_report.py +++ b/erpnext/stock/report/item_shortage_report/item_shortage_report.py @@ -40,7 +40,12 @@ def get_data(filters): item.item_name, item.description, ) - .where((bin.projected_qty < 0) & (wh.name == bin.warehouse) & (bin.item_code == item.name)) + .where( + (item.disabled == 0) + & (bin.projected_qty < 0) + & (wh.name == bin.warehouse) + & (bin.item_code == item.name) + ) .orderby(bin.projected_qty) ) From 51690060853d719400b5dd020fab59fbf2346872 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 10 Aug 2023 10:02:33 +0530 Subject: [PATCH 23/46] fix: move company rename to long queue --- erpnext/setup/doctype/company/company.js | 1 + 1 file changed, 1 insertion(+) diff --git a/erpnext/setup/doctype/company/company.js b/erpnext/setup/doctype/company/company.js index f4682c1b806..fa207ecdd1c 100644 --- a/erpnext/setup/doctype/company/company.js +++ b/erpnext/setup/doctype/company/company.js @@ -18,6 +18,7 @@ frappe.ui.form.on("Company", { }); }, setup: function(frm) { + frm.__rename_queue = "long"; erpnext.company.setup_queries(frm); frm.set_query("parent_company", function() { From de17eaef3857f2128303d20ec291dd7aedb61569 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 10 Aug 2023 10:05:25 +0530 Subject: [PATCH 24/46] refactor: set flag display condition --- erpnext/accounts/doctype/journal_entry/journal_entry.json | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json index 75c32a50189..2812786381c 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.json +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json @@ -537,9 +537,9 @@ }, { "default": "0", + "depends_on": "eval:doc.is_system_generated == 1;", "fieldname": "is_system_generated", "fieldtype": "Check", - "hidden": 1, "label": "Is System Generated", "read_only": 1 } @@ -548,7 +548,7 @@ "idx": 176, "is_submittable": 1, "links": [], - "modified": "2023-08-09 20:47:27.719809", + "modified": "2023-08-10 09:54:52.060639", "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry", From 4ed4b0240d04b0bbf05afa27711d0370503380af Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 10 Aug 2023 14:32:37 +0530 Subject: [PATCH 25/46] refactor: enable 'no-copy' --- erpnext/accounts/doctype/journal_entry/journal_entry.json | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/erpnext/accounts/doctype/journal_entry/journal_entry.json b/erpnext/accounts/doctype/journal_entry/journal_entry.json index 2812786381c..80df0ff0dff 100644 --- a/erpnext/accounts/doctype/journal_entry/journal_entry.json +++ b/erpnext/accounts/doctype/journal_entry/journal_entry.json @@ -541,6 +541,7 @@ "fieldname": "is_system_generated", "fieldtype": "Check", "label": "Is System Generated", + "no_copy": 1, "read_only": 1 } ], @@ -548,7 +549,7 @@ "idx": 176, "is_submittable": 1, "links": [], - "modified": "2023-08-10 09:54:52.060639", + "modified": "2023-08-10 14:32:22.366895", "modified_by": "Administrator", "module": "Accounts", "name": "Journal Entry", From 11cd163db72943c54de250b7a217d2ccd44b4c87 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Thu, 10 Aug 2023 14:40:47 +0530 Subject: [PATCH 26/46] fix: unhide `uom` and `stock_uom` fields in print view --- erpnext/controllers/print_settings.py | 3 --- 1 file changed, 3 deletions(-) diff --git a/erpnext/controllers/print_settings.py b/erpnext/controllers/print_settings.py index d86607d8dbc..59f13c6dfaf 100644 --- a/erpnext/controllers/print_settings.py +++ b/erpnext/controllers/print_settings.py @@ -14,9 +14,6 @@ def set_print_templates_for_item_table(doc, settings): } } - if doc.meta.get_field("items"): - doc.meta.get_field("items").hide_in_print_layout = ["uom", "stock_uom"] - doc.flags.compact_item_fields = ["description", "qty", "rate", "amount"] if settings.compact_item_print: From f2eb3d0f941873024e2c9e36a09696cf847b31e0 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 10 Aug 2023 15:24:07 +0530 Subject: [PATCH 27/46] chore: remove old build system file [skip ci] --- erpnext/public/build.json | 69 --------------------------------------- 1 file changed, 69 deletions(-) delete mode 100644 erpnext/public/build.json diff --git a/erpnext/public/build.json b/erpnext/public/build.json deleted file mode 100644 index 0b63e9f1915..00000000000 --- a/erpnext/public/build.json +++ /dev/null @@ -1,69 +0,0 @@ -{ - "css/erpnext.css": [ - "public/less/erpnext.less", - "public/scss/call_popup.scss", - "public/scss/point-of-sale.scss" - ], - "js/erpnext-web.min.js": [ - "public/js/website_utils.js", - "public/js/shopping_cart.js", - "public/js/wishlist.js" - ], - "css/erpnext-web.css": [ - "public/scss/website.scss", - "public/scss/shopping_cart.scss" - ], - "js/erpnext.min.js": [ - "public/js/conf.js", - "public/js/utils.js", - "public/js/queries.js", - "public/js/sms_manager.js", - "public/js/utils/party.js", - "public/js/utils/demo.js", - "public/js/controllers/stock_controller.js", - "public/js/payment/payments.js", - "public/js/controllers/taxes_and_totals.js", - "public/js/controllers/transaction.js", - "public/js/templates/item_selector.html", - "public/js/utils/item_selector.js", - "public/js/help_links.js", - "public/js/templates/item_quick_entry.html", - "public/js/utils/customer_quick_entry.js", - "public/js/utils/supplier_quick_entry.js", - "public/js/education/student_button.html", - "public/js/education/assessment_result_tool.html", - "public/js/call_popup/call_popup.js", - "public/js/utils/dimension_tree_filter.js", - "public/js/telephony.js", - "public/js/templates/call_link.html", - "public/js/bulk_transaction_processing.js" - ], - "js/item-dashboard.min.js": [ - "stock/dashboard/item_dashboard.html", - "stock/dashboard/item_dashboard_list.html", - "stock/dashboard/item_dashboard.js", - "stock/page/warehouse_capacity_summary/warehouse_capacity_summary.html", - "stock/page/warehouse_capacity_summary/warehouse_capacity_summary_header.html" - ], - "js/point-of-sale.min.js": [ - "selling/page/point_of_sale/pos_item_selector.js", - "selling/page/point_of_sale/pos_item_cart.js", - "selling/page/point_of_sale/pos_item_details.js", - "selling/page/point_of_sale/pos_number_pad.js", - "selling/page/point_of_sale/pos_payment.js", - "selling/page/point_of_sale/pos_past_order_list.js", - "selling/page/point_of_sale/pos_past_order_summary.js", - "selling/page/point_of_sale/pos_controller.js" - ], - "js/bank-reconciliation-tool.min.js": [ - "public/js/bank_reconciliation_tool/data_table_manager.js", - "public/js/bank_reconciliation_tool/number_card.js", - "public/js/bank_reconciliation_tool/dialog_manager.js" - ], - "js/e-commerce.min.js": [ - "e_commerce/product_ui/views.js", - "e_commerce/product_ui/grid.js", - "e_commerce/product_ui/list.js", - "e_commerce/product_ui/search.js" - ] -} From baf5cddd1b189b4b88712f19499f0323fba7c115 Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 10 Aug 2023 16:09:38 +0530 Subject: [PATCH 28/46] fix: Group Account total not showing in Financial Statements --- erpnext/accounts/report/financial_statements.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/erpnext/accounts/report/financial_statements.py b/erpnext/accounts/report/financial_statements.py index a76dea6a523..6b2341cef13 100644 --- a/erpnext/accounts/report/financial_statements.py +++ b/erpnext/accounts/report/financial_statements.py @@ -335,12 +335,10 @@ def add_total_row(out, root_type, balance_must_be, period_list, company_currency for period in period_list: total_row.setdefault(period.key, 0.0) total_row[period.key] += row.get(period.key, 0.0) - row[period.key] = row.get(period.key, 0.0) total_row.setdefault("total", 0.0) total_row["total"] += flt(row["total"]) total_row["opening_balance"] += row["opening_balance"] - row["total"] = "" if "total" in total_row: out.append(total_row) From 3a21c90d10fe79329d75f8cbee7b0b9af16194cc Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 10 Aug 2023 15:48:57 +0530 Subject: [PATCH 29/46] fix: misc fixes in demo data - Generate demo data field copy - absolute imports - remove whitelisting where it's not required - telemetry - banner copy - move to background - clear bootinfo after setup --- erpnext/hooks.py | 6 +++++- erpnext/public/js/setup_wizard.js | 7 ++++++- erpnext/public/js/utils/demo.js | 12 ++++++++---- erpnext/setup/demo.py | 19 +++++++++++++++---- erpnext/setup/setup_wizard/setup_wizard.py | 8 ++++---- 5 files changed, 38 insertions(+), 14 deletions(-) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index e3bea25d0dd..9e271c9293a 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -78,7 +78,11 @@ demo_master_doctypes = [ "customer", "supplier", ] -demo_transaction_doctypes = ["purchase_invoice", "sales_invoice", "payment_entry", "journal_entry"] +demo_transaction_doctypes = [ + "purchase_invoice", + "sales_invoice", + "payment_entry", +] jinja = { "methods": [ diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js index bcad6ebafd1..ba200ef1681 100644 --- a/erpnext/public/js/setup_wizard.js +++ b/erpnext/public/js/setup_wizard.js @@ -40,7 +40,12 @@ erpnext.setup.slides_settings = [ { fieldname: 'fy_start_date', label: __('Financial Year Begins On'), fieldtype: 'Date', reqd: 1 }, // end date should be hidden (auto calculated) { fieldname: 'fy_end_date', label: __('End Date'), fieldtype: 'Date', reqd: 1, hidden: 1 }, - { fieldname: 'setup_demo', label: __('Generate dummy data for demo'), fieldtype: 'Check'}, + { fieldtype: "Section Break" }, + { + fieldname: 'setup_demo', + label: __('Generate Demo Data for Exploration'), + fieldtype: 'Check', + description: 'If checked, we will create demo data for you to explore the system. This demo data can be erased later.'}, ], onload: function (slide) { diff --git a/erpnext/public/js/utils/demo.js b/erpnext/public/js/utils/demo.js index 22d78d8c67c..e810c37e487 100644 --- a/erpnext/public/js/utils/demo.js +++ b/erpnext/public/js/utils/demo.js @@ -2,15 +2,19 @@ $(document).on("toolbar_setup", function() { if (frappe.boot.sysdefaults.demo_company) { erpnext.setup_clear_button(); } + + // for first load + frappe.realtime.on("demo_data_complete", () => { + erpnext.setup_clear_button(); + }) }); erpnext.setup_clear_button = function() { - let message_string = __('Demo data is setup, use this button to clear before starting actual transactions'); + let message_string = __("Demo data is present on the system, erase data before starting real usage."); let $floatingBar = $(`
- Clear + Clear Demo Data
@@ -54,4 +58,4 @@ erpnext.setup_clear_button = function() { } }) }); -} \ No newline at end of file +} diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index 50bc43d3258..355c373d33d 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -13,15 +13,26 @@ from erpnext.accounts.utils import get_fiscal_year from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account -@frappe.whitelist() def setup_demo_data(): - company = create_demo_company() - process_masters() - make_transactions(company) + from frappe.utils.telemetry import capture + + capture("demo_data_creation_started", "erpnext") + try: + company = create_demo_company() + process_masters() + make_transactions(company) + frappe.cache.delete_keys("bootinfo") + frappe.publish_realtime("demo_data_complete") + except Exception: + frappe.log_error("Failed to create demo data") + capture("demo_data_creation_failed", "erpnext", properties={"exception": frappe.get_traceback()}) + raise + capture("demo_data_creation_completed", "erpnext") @frappe.whitelist() def clear_demo_data(): + frappe.only_for("System Manager") company = frappe.db.get_single_value("Global Defaults", "demo_company") create_transaction_deletion_record(company) clear_masters() diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py index ad49be647b0..ebd7d1e9ccf 100644 --- a/erpnext/setup/setup_wizard/setup_wizard.py +++ b/erpnext/setup/setup_wizard/setup_wizard.py @@ -5,8 +5,8 @@ import frappe from frappe import _ -from ..demo import setup_demo_data -from .operations import install_fixtures as fixtures +from erpnext.setup.demo import setup_demo_data +from erpnext.setup.setup_wizard.operations import install_fixtures as fixtures def get_setup_stages(args=None): @@ -40,7 +40,7 @@ def get_setup_stages(args=None): { "status": _("Setting up demo data"), "fail_msg": _("Failed to setup demo data"), - "tasks": [{"fn": setup_demo, "args": args, "fail_msg": _("Failed to login")}], + "tasks": [{"fn": setup_demo, "args": args, "fail_msg": _("Failed to setup demo data")}], }, { "status": _("Wrapping up"), @@ -71,7 +71,7 @@ def fin(args): def setup_demo(args): if args.get("setup_demo"): - setup_demo_data() + frappe.enqueue(setup_demo_data, enqueue_after_commit=True) def login_as_first_user(args): From 5fb92cbb49954581dc982b28ef5e41ce3032f560 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 10 Aug 2023 16:56:45 +0530 Subject: [PATCH 30/46] fix: enqueue at front to speed up demo --- erpnext/setup/setup_wizard/setup_wizard.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py index ebd7d1e9ccf..2da107e4e94 100644 --- a/erpnext/setup/setup_wizard/setup_wizard.py +++ b/erpnext/setup/setup_wizard/setup_wizard.py @@ -71,7 +71,7 @@ def fin(args): def setup_demo(args): if args.get("setup_demo"): - frappe.enqueue(setup_demo_data, enqueue_after_commit=True) + frappe.enqueue(setup_demo_data, enqueue_after_commit=True, at_front=True) def login_as_first_user(args): From 704e6577e5ec6130905ef93859bab530642ae3e1 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 10 Aug 2023 17:29:55 +0530 Subject: [PATCH 31/46] chore: use royalty free images --- erpnext/setup/demo_data/item.json | 22 +++++++++++----------- 1 file changed, 11 insertions(+), 11 deletions(-) diff --git a/erpnext/setup/demo_data/item.json b/erpnext/setup/demo_data/item.json index a24133725ff..9e47281c95f 100644 --- a/erpnext/setup/demo_data/item.json +++ b/erpnext/setup/demo_data/item.json @@ -4,69 +4,69 @@ "item_group": "Demo Item Group", "item_code": "SKU001", "item_name": "T-shirt", - "image": "https://media.istockphoto.com/id/1281631373/vector/mockup-template-men-black-t-shirt-short-sleeve.jpg?s=612x612&w=0&k=20&c=SfYrtFXQS2wJ1-R9ozvxhUabJz3cnmH5HXv2sXW_mZk=" + "image": "https://images.pexels.com/photos/1484808/pexels-photo-1484808.jpeg?auto=compress" }, { "doctype": "Item", "item_group": "Demo Item Group", "item_code": "SKU002", "item_name": "Laptop", - "image": "https://media.istockphoto.com/id/1297051332/vector/levitation-laptop-mockup.jpg?s=612x612&w=0&k=20&c=E9rp9HY7CaPjjsnZlg8NYBTFOGy7gfBSL7oK6wv5VnY=" + "image": "https://images.pexels.com/photos/3999538/pexels-photo-3999538.jpeg" }, { "doctype": "Item", "item_group": "Demo Item Group", "item_code": "SKU003", "item_name": "Book", - "image": "https://media.istockphoto.com/id/950152244/vector/vector-mock-up-of-standing-book.jpg?s=612x612&w=0&k=20&c=oDF2LeFoAcPAwJZFEVjWRvT53sMmCQwkVj-3qYy1duw=" + "image": "https://images.pexels.com/photos/2422178/pexels-photo-2422178.jpeg" }, { "doctype": "Item", "item_group": "Demo Item Group", "item_code": "SKU004", "item_name": "Smartphone", - "image": "https://media.istockphoto.com/id/1308145590/vector/realistic-mobile-phone-mockup-template-isolated-stock-vector.jpg?s=612x612&w=0&k=20&c=63UyujU3S9kAkUh3MXdJcr10xelDjgVyQzRx5Sh5018=" + "image": "https://images.pexels.com/photos/1647976/pexels-photo-1647976.jpeg" }, { "doctype": "Item", "item_group": "Demo Item Group", "item_code": "SKU005", "item_name": "Sneakers", - "image": "https://media.istockphoto.com/id/1303978937/photo/white-sneaker-on-a-blue-gradient-background-mens-fashion-sport-shoe-sneakers-lifestyle.jpg?s=612x612&w=0&k=20&c=L725fuzFTnm6qEaqE7Urc5q6IR80EgYQEjBn_qtBIQg=" + "image": "https://images.pexels.com/photos/1598505/pexels-photo-1598505.jpeg" }, { "doctype": "Item", "item_group": "Demo Item Group", "item_code": "SKU006", "item_name": "Coffee Mug", - "image": "https://media.istockphoto.com/id/821282266/photo/white-mug-isolated.jpg?s=612x612&w=0&k=20&c=LJCMPk0D83OKmJHahkiLzAB3OsKr83nMbL7KxSgfpfM=" + "image": "https://images.pexels.com/photos/585753/pexels-photo-585753.jpeg" }, { "doctype": "Item", "item_group": "Demo Item Group", "item_code": "SKU007", "item_name": "Television", - "image": "https://media.istockphoto.com/id/1002728980/vector/wide-tv-monitor-mockup.jpg?s=612x612&w=0&k=20&c=1gDEH7ppC9ap8UBuIQmO1gM_Z8VeEaEUDDo-Aw_k8qs=" + "image": "https://images.pexels.com/photos/8059376/pexels-photo-8059376.jpeg" }, { "doctype": "Item", "item_group": "Demo Item Group", "item_code": "SKU008", "item_name": "Backpack", - "image": "https://media.istockphoto.com/id/1141208525/photo/yellow-open-backpack.jpg?s=612x612&w=0&k=20&c=k0NOqN9FnIGdkaUNx6-fMIBG2IfWwLT_AbDVefqJT_0=" + "image": "https://images.pexels.com/photos/3731256/pexels-photo-3731256.jpeg" }, { "doctype": "Item", "item_group": "Demo Item Group", "item_code": "SKU009", "item_name": "Headphones", - "image": "https://media.istockphoto.com/id/860853774/photo/blue-headphones-isolated-on-a-white-background.jpg?s=612x612&w=0&k=20&c=KqMSLWuM_Prrq5XHTe79bnFRU_leFDaXTuKqup5uvrE=" + "image": "https://images.pexels.com/photos/3587478/pexels-photo-3587478.jpeg" }, { "doctype": "Item", "item_group": "Demo Item Group", "item_code": "SKU010", "item_name": "Camera", - "image": "https://media.istockphoto.com/id/185278433/photo/black-digital-slr-camera-in-a-white-background.jpg?s=612x612&w=0&k=20&c=OOCbhvOF0W-eVhhrm-TxbgLfbKhFfs4Lprjd7hiQBNU=" + "image": "https://images.pexels.com/photos/51383/photo-camera-subject-photographer-51383.jpeg" } -] \ No newline at end of file +] From 940b1d9e6772febe5b6e557520f5d6f1d7c75005 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 10 Aug 2023 17:46:35 +0530 Subject: [PATCH 32/46] feat(ux): account workspace number cards --- .../workspace/accounting/accounting.json | 23 ++++++++++++++++--- erpnext/setup/demo_data/item.json | 2 +- 2 files changed, 21 insertions(+), 4 deletions(-) diff --git a/erpnext/accounts/workspace/accounting/accounting.json b/erpnext/accounts/workspace/accounting/accounting.json index c27ede29d1b..dfdae1dec69 100644 --- a/erpnext/accounts/workspace/accounting/accounting.json +++ b/erpnext/accounts/workspace/accounting/accounting.json @@ -5,7 +5,7 @@ "label": "Profit and Loss" } ], - "content": "[{\"id\":\"MmUf9abwxg\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"id\":\"i0EtSjDAXq\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"X78jcbq1u3\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"col\":12}},{\"id\":\"pMywM0nhlj\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"id\":\"_pRdD6kqUG\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"El2anpPaFY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"id\":\"1nwcM9upJo\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"id\":\"OF9WOi1Ppc\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"iAwpe-Chra\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Accounting\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"id\":\"xOHTyD8b5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"id\":\"_Cb7C8XdJJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Bank Statement\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"id\":\"OX7lZHbiTr\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]", + "content": "[{\"id\":\"MmUf9abwxg\",\"type\":\"onboarding\",\"data\":{\"onboarding_name\":\"Accounts\",\"col\":12}},{\"id\":\"VVvJ1lUcfc\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Bills\",\"col\":3}},{\"id\":\"Vlj2FZtlHV\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Bills\",\"col\":3}},{\"id\":\"VVVjQVAhPf\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Incoming Payment\",\"col\":3}},{\"id\":\"DySNdlysIW\",\"type\":\"number_card\",\"data\":{\"number_card_name\":\"Total Outgoing Payment\",\"col\":3}},{\"id\":\"i0EtSjDAXq\",\"type\":\"chart\",\"data\":{\"chart_name\":\"Profit and Loss\",\"col\":12}},{\"id\":\"X78jcbq1u3\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"vikWSkNm6_\",\"type\":\"header\",\"data\":{\"text\":\"Your Shortcuts\",\"col\":12}},{\"id\":\"pMywM0nhlj\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Chart of Accounts\",\"col\":3}},{\"id\":\"_pRdD6kqUG\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Sales Invoice\",\"col\":3}},{\"id\":\"G984SgVRJN\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Purchase Invoice\",\"col\":3}},{\"id\":\"1ArNvt9qhz\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Journal Entry\",\"col\":3}},{\"id\":\"F9f4I1viNr\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Payment Entry\",\"col\":3}},{\"id\":\"4IBBOIxfqW\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Accounts Receivable\",\"col\":3}},{\"id\":\"El2anpPaFY\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"General Ledger\",\"col\":3}},{\"id\":\"1nwcM9upJo\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Trial Balance\",\"col\":3}},{\"id\":\"OF9WOi1Ppc\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Dashboard\",\"col\":3}},{\"id\":\"iAwpe-Chra\",\"type\":\"shortcut\",\"data\":{\"shortcut_name\":\"Learn Accounting\",\"col\":3}},{\"id\":\"B7-uxs8tkU\",\"type\":\"spacer\",\"data\":{\"col\":12}},{\"id\":\"tHb3yxthkR\",\"type\":\"header\",\"data\":{\"text\":\"Reports & Masters\",\"col\":12}},{\"id\":\"DnNtsmxpty\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounting Masters\",\"col\":4}},{\"id\":\"nKKr6fjgjb\",\"type\":\"card\",\"data\":{\"card_name\":\"General Ledger\",\"col\":4}},{\"id\":\"xOHTyD8b5l\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Receivable\",\"col\":4}},{\"id\":\"_Cb7C8XdJJ\",\"type\":\"card\",\"data\":{\"card_name\":\"Accounts Payable\",\"col\":4}},{\"id\":\"p7NY6MHe2Y\",\"type\":\"card\",\"data\":{\"card_name\":\"Financial Statements\",\"col\":4}},{\"id\":\"KlqilF5R_V\",\"type\":\"card\",\"data\":{\"card_name\":\"Taxes\",\"col\":4}},{\"id\":\"jTUy8LB0uw\",\"type\":\"card\",\"data\":{\"card_name\":\"Cost Center and Budgeting\",\"col\":4}},{\"id\":\"Wn2lhs7WLn\",\"type\":\"card\",\"data\":{\"card_name\":\"Multi Currency\",\"col\":4}},{\"id\":\"PAQMqqNkBM\",\"type\":\"card\",\"data\":{\"card_name\":\"Bank Statement\",\"col\":4}},{\"id\":\"Q_hBCnSeJY\",\"type\":\"card\",\"data\":{\"card_name\":\"Reports\",\"col\":4}},{\"id\":\"3AK1Zf0oew\",\"type\":\"card\",\"data\":{\"card_name\":\"Profitability\",\"col\":4}},{\"id\":\"kxhoaiqdLq\",\"type\":\"card\",\"data\":{\"card_name\":\"Opening and Closing\",\"col\":4}},{\"id\":\"q0MAlU2j_Z\",\"type\":\"card\",\"data\":{\"card_name\":\"Subscription Management\",\"col\":4}},{\"id\":\"ptm7T6Hwu-\",\"type\":\"card\",\"data\":{\"card_name\":\"Share Management\",\"col\":4}},{\"id\":\"OX7lZHbiTr\",\"type\":\"card\",\"data\":{\"card_name\":\"Settings\",\"col\":4}}]", "creation": "2020-03-02 15:41:59.515192", "custom_blocks": [], "docstatus": 0, @@ -1061,11 +1061,28 @@ "type": "Link" } ], - "modified": "2023-07-04 14:32:15.842044", + "modified": "2023-08-10 17:41:14.059005", "modified_by": "Administrator", "module": "Accounts", "name": "Accounting", - "number_cards": [], + "number_cards": [ + { + "label": "Total Outgoing Bills", + "number_card_name": "Total Outgoing Bills" + }, + { + "label": "Total Incoming Bills", + "number_card_name": "Total Incoming Bills" + }, + { + "label": "Total Incoming Payment", + "number_card_name": "Total Incoming Payment" + }, + { + "label": "Total Outgoing Payment", + "number_card_name": "Total Outgoing Payment" + } + ], "owner": "Administrator", "parent_page": "", "public": 1, diff --git a/erpnext/setup/demo_data/item.json b/erpnext/setup/demo_data/item.json index 9e47281c95f..ffe41528af5 100644 --- a/erpnext/setup/demo_data/item.json +++ b/erpnext/setup/demo_data/item.json @@ -4,7 +4,7 @@ "item_group": "Demo Item Group", "item_code": "SKU001", "item_name": "T-shirt", - "image": "https://images.pexels.com/photos/1484808/pexels-photo-1484808.jpeg?auto=compress" + "image": "https://images.pexels.com/photos/1484808/pexels-photo-1484808.jpeg" }, { "doctype": "Item", From e4b863af05ef224f9b31d9e545700885362fe284 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 10 Aug 2023 17:49:28 +0530 Subject: [PATCH 33/46] refactor: gracefully fail while clearing demo data --- erpnext/setup/demo.py | 29 +++++++++++++++++++---------- 1 file changed, 19 insertions(+), 10 deletions(-) diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index 355c373d33d..bb64ba1db79 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -6,6 +6,7 @@ import os from random import randint import frappe +from frappe import _ from frappe.utils import add_days, getdate import erpnext @@ -33,12 +34,20 @@ def setup_demo_data(): @frappe.whitelist() def clear_demo_data(): frappe.only_for("System Manager") - company = frappe.db.get_single_value("Global Defaults", "demo_company") - create_transaction_deletion_record(company) - clear_masters() - delete_company(company) - default_company = frappe.db.get_single_value("Global Defaults", "default_company") - frappe.db.set_default("company", default_company) + try: + company = frappe.db.get_single_value("Global Defaults", "demo_company") + create_transaction_deletion_record(company) + clear_masters() + delete_company(company) + default_company = frappe.db.get_single_value("Global Defaults", "default_company") + frappe.db.set_default("company", default_company) + except Exception: + frappe.db.rollback() + frappe.log_error("Failed to erase demo data") + frappe.throw( + _("Failed to erase demo data, please delete the demo company manually."), + title=_("Could Not Delete Demo Data"), + ) def create_demo_company(): @@ -154,10 +163,10 @@ def clear_masters(): clear_demo_record(item) -def clear_demo_record(doctype): - doc_type = doctype.get("doctype") - del doctype["doctype"] - doc = frappe.get_doc(doc_type, doctype) +def clear_demo_record(document): + doc_type = document.get("doctype") + del document["doctype"] + doc = frappe.get_doc(doc_type, document) frappe.delete_doc(doc.doctype, doc.name, ignore_permissions=True) From 8bdf280cfb1db04a8cd119261affecc71629d7f2 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 10 Aug 2023 17:55:15 +0530 Subject: [PATCH 34/46] fix: confirm before clearing demo data --- erpnext/public/js/utils/demo.js | 42 ++++++++++++++++++++------------- 1 file changed, 26 insertions(+), 16 deletions(-) diff --git a/erpnext/public/js/utils/demo.js b/erpnext/public/js/utils/demo.js index e810c37e487..05866e98647 100644 --- a/erpnext/public/js/utils/demo.js +++ b/erpnext/public/js/utils/demo.js @@ -1,4 +1,4 @@ -$(document).on("toolbar_setup", function() { +$(document).on("toolbar_setup", function () { if (frappe.boot.sysdefaults.demo_company) { erpnext.setup_clear_button(); } @@ -6,11 +6,13 @@ $(document).on("toolbar_setup", function() { // for first load frappe.realtime.on("demo_data_complete", () => { erpnext.setup_clear_button(); - }) + }); }); -erpnext.setup_clear_button = function() { - let message_string = __("Demo data is present on the system, erase data before starting real usage."); +erpnext.setup_clear_button = function () { + let message_string = __( + "Demo data is present on the system, erase data before starting real usage." + ); let $floatingBar = $(`
`); - $('footer').append($floatingBar); + $("footer").append($floatingBar); - $('#clear-demo').on('click', function () { - frappe.call({ - method: "erpnext.setup.demo.clear_demo_data", - freeze: true, - freeze_message: __('Clearing Demo Data...'), - callback: function(r) { - frappe.ui.toolbar.clear_cache(); - frappe.show_alert({ message: __('Demo data cleared'), indicator: 'green' }); - $('footer').remove($floatingBar); + $("#clear-demo").on("click", function () { + frappe.confirm( + __("Are you sure you want to clear all demo data?"), + () => { + frappe.call({ + method: "erpnext.setup.demo.clear_demo_data", + freeze: true, + freeze_message: __("Clearing Demo Data..."), + callback: function (r) { + frappe.ui.toolbar.clear_cache(); + frappe.show_alert({ + message: __("Demo data cleared"), + indicator: "green", + }); + $("footer").remove($floatingBar); + }, + }); } - }) + ); }); -} +}; From c8e6e067aebe459086aed3d70cb9d09dcd07d110 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Thu, 10 Aug 2023 18:27:34 +0530 Subject: [PATCH 35/46] chore: telemetry for demo data erasure --- erpnext/setup/demo.py | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index bb64ba1db79..09e6470f28f 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -33,7 +33,11 @@ def setup_demo_data(): @frappe.whitelist() def clear_demo_data(): + from frappe.utils.telemetry import capture + frappe.only_for("System Manager") + + capture("demo_data_erased", "erpnext") try: company = frappe.db.get_single_value("Global Defaults", "demo_company") create_transaction_deletion_record(company) From 000de4eddfb8f319e5174a9671b16a8c48220eee Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 10 Aug 2023 21:45:55 +0530 Subject: [PATCH 36/46] chore: Update customer/supplier names --- erpnext/setup/demo_data/customer.json | 6 +++--- erpnext/setup/demo_data/supplier.json | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/erpnext/setup/demo_data/customer.json b/erpnext/setup/demo_data/customer.json index b27c44477d1..1b47906eb6c 100644 --- a/erpnext/setup/demo_data/customer.json +++ b/erpnext/setup/demo_data/customer.json @@ -3,18 +3,18 @@ "doctype": "Customer", "customer_group": "Demo Customer Group", "territory": "All Territories", - "customer_name": "ABC Enterprises" + "customer_name": "Grant Plastics Ltd." }, { "doctype": "Customer", "customer_group": "Demo Customer Group", "territory": "All Territories", - "customer_name": "XYZ Corporation" + "customer_name": "West View Software Ltd." }, { "doctype": "Customer", "customer_group": "Demo Customer Group", "territory": "All Territories", - "customer_name": "KJPR Pvt. Ltd." + "customer_name": "Palmer Productions Ltd." } ] \ No newline at end of file diff --git a/erpnext/setup/demo_data/supplier.json b/erpnext/setup/demo_data/supplier.json index 96c83d1de53..01a4e8969a4 100644 --- a/erpnext/setup/demo_data/supplier.json +++ b/erpnext/setup/demo_data/supplier.json @@ -2,7 +2,7 @@ { "doctype": "Supplier", "supplier_group": "Demo Supplier Group", - "supplier_name": "DQ Industries" + "supplier_name": "Zuckerman Security Ltd." }, { "doctype": "Supplier", @@ -12,6 +12,6 @@ { "doctype": "Supplier", "supplier_group": "Demo Supplier Group", - "supplier_name": "KC Corp." + "supplier_name": "Summit Traders Ltd." } ] \ No newline at end of file From 567f4c37fcf29b97ce0ac273479de0f8b694835f Mon Sep 17 00:00:00 2001 From: Deepesh Garg Date: Thu, 10 Aug 2023 21:46:34 +0530 Subject: [PATCH 37/46] fix: Add order data --- erpnext/hooks.py | 5 +- erpnext/setup/demo.py | 84 ++++++++++--------- ...chase_invoice.json => purchase_order.json} | 62 +++++++------- .../{sales_invoice.json => sales_order.json} | 54 ++++++------ 4 files changed, 106 insertions(+), 99 deletions(-) rename erpnext/setup/demo_data/{purchase_invoice.json => purchase_order.json} (69%) rename erpnext/setup/demo_data/{sales_invoice.json => sales_order.json} (69%) diff --git a/erpnext/hooks.py b/erpnext/hooks.py index 9e271c9293a..7eaa146db65 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -79,9 +79,8 @@ demo_master_doctypes = [ "supplier", ] demo_transaction_doctypes = [ - "purchase_invoice", - "sales_invoice", - "payment_entry", + "purchase_order", + "sales_order", ] jinja = { diff --git a/erpnext/setup/demo.py b/erpnext/setup/demo.py index bb64ba1db79..78b31e4ec35 100644 --- a/erpnext/setup/demo.py +++ b/erpnext/setup/demo.py @@ -9,8 +9,10 @@ import frappe from frappe import _ from frappe.utils import add_days, getdate -import erpnext +from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry from erpnext.accounts.utils import get_fiscal_year +from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice +from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account @@ -88,8 +90,8 @@ def create_demo_record(doctype): def make_transactions(company): - start_date = get_fiscal_year(date=getdate())[1] frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1) + start_date = get_fiscal_year(date=getdate())[1] for doctype in frappe.get_hooks("demo_transaction_doctypes"): data = read_data_file_using_hooks(doctype) @@ -97,55 +99,63 @@ def make_transactions(company): for item in json.loads(data): create_transaction(item, company, start_date) + convert_order_to_invoices() + frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 0) + def create_transaction(doctype, company, start_date): + document_type = doctype.get("doctype") warehouse = get_warehouse(company) - posting_date = ( - start_date if doctype.get("doctype") == "Purchase Invoice" else get_random_date(start_date) - ) - bank_account, default_receivable_account = frappe.db.get_value( - "Company", company, ["default_bank_account", "default_receivable_account"] - ) - bank_field = "paid_to" if doctype.get("party_type") == "Customer" else "paid_from" + + if document_type == "Purchase Order": + posting_date = get_random_date(start_date, 1, 30) + else: + posting_date = get_random_date(start_date, 31, 365) doctype.update( { "company": company, "set_posting_time": 1, - "posting_date": posting_date, + "transaction_date": posting_date, + "schedule_date": posting_date, + "delivery_date": posting_date, "set_warehouse": warehouse, - bank_field: bank_account, - "reference_date": posting_date, } ) - income_account, expense_account = frappe.db.get_value( - "Company", company, ["default_income_account", "default_expense_account"] - ) - - if doctype in ("Purchase Invoice", "Sales Invoice"): - for item in doctype.get("items") or []: - item.update( - { - "cost_center": erpnext.get_default_cost_center(company), - "income_account": income_account, - "expense_account": expense_account, - } - ) - elif doctype == "Journal Entry": - pass - # update_accounts(doctype, bank_account, default_receivable_account) - doc = frappe.get_doc(doctype) doc.save(ignore_permissions=True) doc.submit() -# def update_accounts(doctype, company, bank_account): +def convert_order_to_invoices(): + for document in ["Purchase Order", "Sales Order"]: + # Keep some orders intentionally unbilled/unpaid + for i, order in enumerate( + frappe.db.get_all( + document, filters={"docstatus": 1}, fields=["name", "transaction_date"], limit=6 + ) + ): + + if document == "Purchase Order": + invoice = make_purchase_invoice(order.name) + elif document == "Sales Order": + invoice = make_sales_invoice(order.name) + + invoice.set_posting_time = 1 + invoice.posting_date = order.transaction_date + invoice.due_date = order.transaction_date + invoice.update_stock = 1 + invoice.submit() + + if i % 2 != 0: + payment = get_payment_entry(invoice.doctype, invoice.name) + payment.reference_no = invoice.name + payment.submit() -def get_random_date(start_date): - return add_days(start_date, randint(1, 365)) +def get_random_date(start_date, start_range, end_range): + return add_days(start_date, randint(start_range, end_range)) def create_transaction_deletion_record(company): @@ -164,9 +174,9 @@ def clear_masters(): def clear_demo_record(document): - doc_type = document.get("doctype") + document_type = document.get("doctype") del document["doctype"] - doc = frappe.get_doc(doc_type, document) + doc = frappe.get_doc(document_type, document) frappe.delete_doc(doc.doctype, doc.name, ignore_permissions=True) @@ -184,7 +194,5 @@ def read_data_file_using_hooks(doctype): def get_warehouse(company): - abbr = frappe.db.get_value("Company", company, "abbr") - warehouse = "Stores - {0}".format(abbr) - - return warehouse + warehouses = frappe.db.get_all("Warehouse", {"company": company, "is_group": 0}) + return warehouses[randint(0, 3)].name diff --git a/erpnext/setup/demo_data/purchase_invoice.json b/erpnext/setup/demo_data/purchase_order.json similarity index 69% rename from erpnext/setup/demo_data/purchase_invoice.json rename to erpnext/setup/demo_data/purchase_order.json index 7d5e97d1726..42ffa8862a9 100644 --- a/erpnext/setup/demo_data/purchase_invoice.json +++ b/erpnext/setup/demo_data/purchase_order.json @@ -1,12 +1,12 @@ [ { "conversion_rate": 1.0, - "supplier": "DQ Industries", - "doctype": "Purchase Invoice", + "supplier": "Zuckerman Security Ltd.", + "doctype": "Purchase Order", "update_stock": 1, "items": [ { - "doctype": "Purchase Invoice Item", + "doctype": "Purchase Order Item", "item_code": "SKU001", "parentfield": "items", "qty": 100.0, @@ -18,11 +18,11 @@ { "conversion_rate": 1.0, "supplier": "MA Inc.", - "doctype": "Purchase Invoice", + "doctype": "Purchase Order", "update_stock": 1, "items": [ { - "doctype": "Purchase Invoice Item", + "doctype": "Purchase Order Item", "item_code": "SKU002", "parentfield": "items", "qty": 50.0, @@ -33,15 +33,15 @@ }, { "conversion_rate": 1.0, - "supplier": "KC Corp.", - "doctype": "Purchase Invoice", + "supplier": "Summit Traders Ltd.", + "doctype": "Purchase Order", "update_stock": 1, "items": [ { - "doctype": "Purchase Invoice Item", + "doctype": "Purchase Order Item", "item_code": "SKU003", "parentfield": "items", - "qty": 75.0, + "qty": 200.0, "rate": 523.0, "conversion_factor": 1 } @@ -49,12 +49,12 @@ }, { "conversion_rate": 1.0, - "supplier": "DQ Industries", - "doctype": "Purchase Invoice", + "supplier": "Zuckerman Security Ltd.", + "doctype": "Purchase Order", "update_stock": 1, "items": [ { - "doctype": "Purchase Invoice Item", + "doctype": "Purchase Order Item", "item_code": "SKU004", "parentfield": "items", "qty": 60.0, @@ -66,14 +66,14 @@ { "conversion_rate": 1.0, "supplier": "MA Inc.", - "doctype": "Purchase Invoice", + "doctype": "Purchase Order", "update_stock": 1, "items": [ { - "doctype": "Purchase Invoice Item", + "doctype": "Purchase Order Item", "item_code": "SKU005", "parentfield": "items", - "qty": 82.0, + "qty": 182.0, "rate": 222.0, "conversion_factor": 1 } @@ -81,15 +81,15 @@ }, { "conversion_rate": 1.0, - "supplier": "KC Corp.", - "doctype": "Purchase Invoice", + "supplier": "Summit Traders Ltd.", + "doctype": "Purchase Order", "update_stock": 1, "items": [ { - "doctype": "Purchase Invoice Item", + "doctype": "Purchase Order Item", "item_code": "SKU006", "parentfield": "items", - "qty": 50.0, + "qty": 250.0, "rate": 420.0, "conversion_factor": 1 } @@ -97,15 +97,15 @@ }, { "conversion_rate": 1.0, - "supplier": "DQ Industries", - "doctype": "Purchase Invoice", + "supplier": "Zuckerman Security Ltd.", + "doctype": "Purchase Order", "update_stock": 1, "items": [ { - "doctype": "Purchase Invoice Item", + "doctype": "Purchase Order Item", "item_code": "SKU007", "parentfield": "items", - "qty": 90.0, + "qty": 190.0, "rate": 375.0, "conversion_factor": 1 } @@ -114,11 +114,11 @@ { "conversion_rate": 1.0, "supplier": "MA Inc.", - "doctype": "Purchase Invoice", + "doctype": "Purchase Order", "update_stock": 1, "items": [ { - "doctype": "Purchase Invoice Item", + "doctype": "Purchase Order Item", "item_code": "SKU008", "parentfield": "items", "qty": 121.0, @@ -129,12 +129,12 @@ }, { "conversion_rate": 1.0, - "supplier": "KC Corp.", - "doctype": "Purchase Invoice", + "supplier": "Summit Traders Ltd.", + "doctype": "Purchase Order", "update_stock": 1, "items": [ { - "doctype": "Purchase Invoice Item", + "doctype": "Purchase Order Item", "item_code": "SKU009", "parentfield": "items", "qty": 76.0, @@ -145,12 +145,12 @@ }, { "conversion_rate": 1.0, - "supplier": "DQ Industries", - "doctype": "Purchase Invoice", + "supplier": "Zuckerman Security Ltd.", + "doctype": "Purchase Order", "update_stock": 1, "items": [ { - "doctype": "Purchase Invoice Item", + "doctype": "Purchase Order Item", "item_code": "SKU010", "parentfield": "items", "qty": 78.0, diff --git a/erpnext/setup/demo_data/sales_invoice.json b/erpnext/setup/demo_data/sales_order.json similarity index 69% rename from erpnext/setup/demo_data/sales_invoice.json rename to erpnext/setup/demo_data/sales_order.json index 6bbfcbe4cf8..d39063723ee 100644 --- a/erpnext/setup/demo_data/sales_invoice.json +++ b/erpnext/setup/demo_data/sales_order.json @@ -1,87 +1,87 @@ [ { "conversion_rate": 1.0, - "customer": "ABC Enterprises", - "doctype": "Sales Invoice", + "customer": "Grant Plastics Ltd.", + "doctype": "Sales Order", "update_stock": 1, "items": [ { - "doctype": "Sales Invoice Item", + "doctype": "Sales Order Item", "item_code": "SKU004", "parentfield": "items", "qty": 20.0, - "rate": 500.0, + "rate": 1000.0, "conversion_factor": 1 } ] }, { "conversion_rate": 1.0, - "customer": "XYZ Corporation", - "doctype": "Sales Invoice", + "customer": "West View Software Ltd.", + "doctype": "Sales Order", "update_stock": 1, "items": [ { - "doctype": "Sales Invoice Item", + "doctype": "Sales Order Item", "item_code": "SKU001", "parentfield": "items", "qty": 25.0, - "rate": 600.0, + "rate": 800.0, "conversion_factor": 1 }, { - "doctype": "Sales Invoice Item", + "doctype": "Sales Order Item", "item_code": "SKU002", "parentfield": "items", "qty": 15.0, - "rate": 300.0, + "rate": 800.0, "conversion_factor": 1 } ] }, { "conversion_rate": 1.0, - "customer": "XYZ Corporation", - "doctype": "Sales Invoice", + "customer": "West View Software Ltd.", + "doctype": "Sales Order", "update_stock": 1, "items": [ { - "doctype": "Sales Invoice Item", + "doctype": "Sales Order Item", "item_code": "SKU003", "parentfield": "items", "qty": 100, - "rate": 300.0, + "rate": 500.0, "conversion_factor": 1 }, { - "doctype": "Sales Invoice Item", + "doctype": "Sales Order Item", "item_code": "SKU006", "parentfield": "items", "qty": 100, - "rate": 300.0, + "rate": 890.0, "conversion_factor": 1 }, { - "doctype": "Sales Invoice Item", + "doctype": "Sales Order Item", "item_code": "SKU007", "parentfield": "items", "qty": 100, - "rate": 300.0, + "rate": 900.0, "conversion_factor": 1 } ] }, { "conversion_rate": 1.0, - "customer": "KJPR Pvt. Ltd.", - "doctype": "Sales Invoice", + "customer": "Palmer Productions Ltd.", + "doctype": "Sales Order", "update_stock": 1, "items": [ { - "doctype": "Sales Invoice Item", + "doctype": "Sales Order Item", "item_code": "SKU005", "parentfield": "items", - "qty": 200.0, + "qty": 150.0, "rate": 100.0, "conversion_factor": 1 } @@ -89,12 +89,12 @@ }, { "conversion_rate": 1.0, - "customer": "ABC Enterprises", - "doctype": "Sales Invoice", + "customer": "Grant Plastics Ltd.", + "doctype": "Sales Order", "update_stock": 1, "items": [ { - "doctype": "Sales Invoice Item", + "doctype": "Sales Order Item", "item_code": "SKU008", "parentfield": "items", "qty": 20.0, @@ -102,7 +102,7 @@ "conversion_factor": 1 }, { - "doctype": "Sales Invoice Item", + "doctype": "Sales Order Item", "item_code": "SKU009", "parentfield": "items", "qty": 40.0, @@ -110,7 +110,7 @@ "conversion_factor": 1 }, { - "doctype": "Sales Invoice Item", + "doctype": "Sales Order Item", "item_code": "SKU010", "parentfield": "items", "qty": 50.0, From d138948c701892cfc920ffb3fc2d59283f952acc Mon Sep 17 00:00:00 2001 From: Anand Baburajan Date: Thu, 10 Aug 2023 23:16:01 +0530 Subject: [PATCH 38/46] feat: daily asset depreciation method [dev] (#36588) feat: daily asset depreciation method --- erpnext/assets/doctype/asset/test_asset.py | 35 +++++++++++++ .../asset_depreciation_schedule.json | 12 ++++- .../asset_depreciation_schedule.py | 51 ++++++++++++++----- .../asset_finance_book.json | 15 +++++- 4 files changed, 99 insertions(+), 14 deletions(-) diff --git a/erpnext/assets/doctype/asset/test_asset.py b/erpnext/assets/doctype/asset/test_asset.py index 2a74f20e1bf..cd66f1d136a 100644 --- a/erpnext/assets/doctype/asset/test_asset.py +++ b/erpnext/assets/doctype/asset/test_asset.py @@ -754,6 +754,40 @@ class TestDepreciationMethods(AssetSetup): self.assertEqual(schedules, expected_schedules) + def test_schedule_for_straight_line_method_with_daily_depreciation(self): + asset = create_asset( + calculate_depreciation=1, + available_for_use_date="2023-01-01", + purchase_date="2023-01-01", + gross_purchase_amount=12000, + depreciation_start_date="2023-01-31", + total_number_of_depreciations=12, + frequency_of_depreciation=1, + daily_depreciation=1, + ) + + expected_schedules = [ + ["2023-01-31", 1019.18, 1019.18], + ["2023-02-28", 920.55, 1939.73], + ["2023-03-31", 1019.18, 2958.91], + ["2023-04-30", 986.3, 3945.21], + ["2023-05-31", 1019.18, 4964.39], + ["2023-06-30", 986.3, 5950.69], + ["2023-07-31", 1019.18, 6969.87], + ["2023-08-31", 1019.18, 7989.05], + ["2023-09-30", 986.3, 8975.35], + ["2023-10-31", 1019.18, 9994.53], + ["2023-11-30", 986.3, 10980.83], + ["2023-12-31", 1019.17, 12000.0], + ] + + schedules = [ + [cstr(d.schedule_date), d.depreciation_amount, d.accumulated_depreciation_amount] + for d in get_depr_schedule(asset.name, "Draft") + ] + + self.assertEqual(schedules, expected_schedules) + def test_schedule_for_straight_line_method_for_existing_asset(self): asset = create_asset( calculate_depreciation=1, @@ -1724,6 +1758,7 @@ def create_asset(**args): "total_number_of_depreciations": args.total_number_of_depreciations or 5, "expected_value_after_useful_life": args.expected_value_after_useful_life or 0, "depreciation_start_date": args.depreciation_start_date, + "daily_depreciation": args.daily_depreciation or 0, }, ) diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json index d38508d0c42..3772ef4d683 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.json @@ -19,6 +19,7 @@ "depreciation_method", "total_number_of_depreciations", "rate_of_depreciation", + "daily_depreciation", "column_break_8", "frequency_of_depreciation", "expected_value_after_useful_life", @@ -174,12 +175,21 @@ "label": "Number of Depreciations Booked", "print_hide": 1, "read_only": 1 + }, + { + "default": "0", + "depends_on": "eval:doc.depreciation_method == \"Straight Line\" || doc.depreciation_method == \"Manual\"", + "fieldname": "daily_depreciation", + "fieldtype": "Check", + "label": "Daily Depreciation", + "print_hide": 1, + "read_only": 1 } ], "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-02-26 16:37:23.734806", + "modified": "2023-08-10 22:22:09.722968", "modified_by": "Administrator", "module": "Assets", "name": "Asset Depreciation Schedule", diff --git a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py index e616665ad1f..39ebd4ec0ec 100644 --- a/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py +++ b/erpnext/assets/doctype/asset_depreciation_schedule/asset_depreciation_schedule.py @@ -153,6 +153,7 @@ class AssetDepreciationSchedule(Document): self.frequency_of_depreciation = row.frequency_of_depreciation self.rate_of_depreciation = row.rate_of_depreciation self.expected_value_after_useful_life = row.expected_value_after_useful_life + self.daily_depreciation = row.daily_depreciation self.status = "Draft" def make_depr_schedule( @@ -499,29 +500,36 @@ def get_total_days(date, frequency): return date_diff(date, period_start_date) -@erpnext.allow_regional def get_depreciation_amount( asset, depreciable_value, - row, + fb_row, schedule_idx=0, prev_depreciation_amount=0, has_wdv_or_dd_non_yearly_pro_rata=False, ): - if row.depreciation_method in ("Straight Line", "Manual"): - return get_straight_line_or_manual_depr_amount(asset, row) + if fb_row.depreciation_method in ("Straight Line", "Manual"): + return get_straight_line_or_manual_depr_amount(asset, fb_row, schedule_idx) else: + rate_of_depreciation = get_updated_rate_of_depreciation_for_wdv_and_dd( + asset, depreciable_value, fb_row + ) return get_wdv_or_dd_depr_amount( depreciable_value, - row.rate_of_depreciation, - row.frequency_of_depreciation, + rate_of_depreciation, + fb_row.frequency_of_depreciation, schedule_idx, prev_depreciation_amount, has_wdv_or_dd_non_yearly_pro_rata, ) -def get_straight_line_or_manual_depr_amount(asset, row): +@erpnext.allow_regional +def get_updated_rate_of_depreciation_for_wdv_and_dd(asset, depreciable_value, fb_row): + return fb_row.rate_of_depreciation + + +def get_straight_line_or_manual_depr_amount(asset, row, schedule_idx): # if the Depreciation Schedule is being modified after Asset Repair due to increase in asset life and value if asset.flags.increase_in_asset_life: return (flt(row.value_after_depreciation) - flt(row.expected_value_after_useful_life)) / ( @@ -534,11 +542,30 @@ def get_straight_line_or_manual_depr_amount(asset, row): ) # if the Depreciation Schedule is being prepared for the first time else: - return ( - flt(asset.gross_purchase_amount) - - flt(asset.opening_accumulated_depreciation) - - flt(row.expected_value_after_useful_life) - ) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked) + if row.daily_depreciation: + daily_depr_amount = ( + flt(asset.gross_purchase_amount) + - flt(asset.opening_accumulated_depreciation) + - flt(row.expected_value_after_useful_life) + ) / date_diff( + add_months( + row.depreciation_start_date, + flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked) + * row.frequency_of_depreciation, + ), + row.depreciation_start_date, + ) + to_date = add_months(row.depreciation_start_date, schedule_idx * row.frequency_of_depreciation) + from_date = add_months( + row.depreciation_start_date, (schedule_idx - 1) * row.frequency_of_depreciation + ) + return daily_depr_amount * date_diff(to_date, from_date) + else: + return ( + flt(asset.gross_purchase_amount) + - flt(asset.opening_accumulated_depreciation) + - flt(row.expected_value_after_useful_life) + ) / flt(row.total_number_of_depreciations - asset.number_of_depreciations_booked) def get_wdv_or_dd_depr_amount( diff --git a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json index e5a5f194c1b..4121302c1e9 100644 --- a/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json +++ b/erpnext/assets/doctype/asset_finance_book/asset_finance_book.json @@ -8,6 +8,7 @@ "finance_book", "depreciation_method", "total_number_of_depreciations", + "daily_depreciation", "column_break_5", "frequency_of_depreciation", "depreciation_start_date", @@ -17,6 +18,7 @@ ], "fields": [ { + "columns": 2, "fieldname": "finance_book", "fieldtype": "Link", "in_list_view": 1, @@ -32,6 +34,7 @@ "reqd": 1 }, { + "columns": 2, "fieldname": "total_number_of_depreciations", "fieldtype": "Int", "in_list_view": 1, @@ -43,6 +46,7 @@ "fieldtype": "Column Break" }, { + "columns": 2, "fieldname": "frequency_of_depreciation", "fieldtype": "Int", "in_list_view": 1, @@ -57,6 +61,7 @@ "mandatory_depends_on": "eval:parent.doctype == 'Asset'" }, { + "columns": 1, "default": "0", "depends_on": "eval:parent.doctype == 'Asset'", "fieldname": "expected_value_after_useful_life", @@ -79,12 +84,19 @@ "fieldname": "rate_of_depreciation", "fieldtype": "Percent", "label": "Rate of Depreciation" + }, + { + "default": "0", + "depends_on": "eval:doc.depreciation_method == \"Straight Line\" || doc.depreciation_method == \"Manual\"", + "fieldname": "daily_depreciation", + "fieldtype": "Check", + "label": "Daily Depreciation" } ], "index_web_pages_for_search": 1, "istable": 1, "links": [], - "modified": "2021-06-17 12:59:05.743683", + "modified": "2023-08-10 22:10:36.576199", "modified_by": "Administrator", "module": "Assets", "name": "Asset Finance Book", @@ -93,5 +105,6 @@ "quick_entry": 1, "sort_field": "modified", "sort_order": "DESC", + "states": [], "track_changes": 1 } \ No newline at end of file From dbd3fdbb415e032d738c0055288c41a12e4cd9b4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 11 Aug 2023 09:50:43 +0530 Subject: [PATCH 39/46] fix: disallow mulitple SO with same PO No --- .../doctype/sales_order/sales_order.py | 28 ++++++++++++------- 1 file changed, 18 insertions(+), 10 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/sales_order.py b/erpnext/selling/doctype/sales_order/sales_order.py index ca669f630a4..cc141ffa111 100755 --- a/erpnext/selling/doctype/sales_order/sales_order.py +++ b/erpnext/selling/doctype/sales_order/sales_order.py @@ -108,18 +108,26 @@ class SalesOrder(SellingController): and customer = %s", (self.po_no, self.name, self.customer), ) - if ( - so - and so[0][0] - and not cint( + if so and so[0][0]: + if cint( frappe.db.get_single_value("Selling Settings", "allow_against_multiple_purchase_orders") - ) - ): - frappe.msgprint( - _("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format( - so[0][0], self.po_no + ): + frappe.msgprint( + _("Warning: Sales Order {0} already exists against Customer's Purchase Order {1}").format( + frappe.bold(so[0][0]), frappe.bold(self.po_no) + ) + ) + else: + frappe.throw( + _( + "Sales Order {0} already exists against Customer's Purchase Order {1}. To allow multiple Sales Orders, Enable {2} in {3}" + ).format( + frappe.bold(so[0][0]), + frappe.bold(self.po_no), + frappe.bold(_("'Allow Multiple Sales Orders Against a Customer's Purchase Order'")), + get_link_to_form("Selling Settings", "Selling Settings"), + ) ) - ) def validate_for_items(self): for d in self.get("items"): From cd28d15292a77060c2ec9b582e4b0f5635f7b112 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 11 Aug 2023 10:55:43 +0530 Subject: [PATCH 40/46] chore: update permissions for Process Payment Reconciliation --- .../process_payment_reconciliation.json | 22 ++++++++++++++----- 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json index 8bb7092dc50..1a1ab4d800e 100644 --- a/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json +++ b/erpnext/accounts/doctype/process_payment_reconciliation/process_payment_reconciliation.json @@ -146,7 +146,7 @@ "index_web_pages_for_search": 1, "is_submittable": 1, "links": [], - "modified": "2023-04-21 17:19:30.912953", + "modified": "2023-08-11 10:56:51.699137", "modified_by": "Administrator", "module": "Accounts", "name": "Process Payment Reconciliation", @@ -154,15 +154,25 @@ "owner": "Administrator", "permissions": [ { + "amend": 1, + "cancel": 1, "create": 1, "delete": 1, - "email": 1, - "export": 1, - "print": 1, "read": 1, - "report": 1, - "role": "System Manager", + "role": "Accounts Manager", "share": 1, + "submit": 1, + "write": 1 + }, + { + "amend": 1, + "cancel": 1, + "create": 1, + "delete": 1, + "read": 1, + "role": "Accounts User", + "share": 1, + "submit": 1, "write": 1 } ], From 98e82e0d99f4fed6c1a35268ab4dd7324bf1b6c5 Mon Sep 17 00:00:00 2001 From: Anand Baburajan Date: Fri, 11 Aug 2023 14:21:48 +0530 Subject: [PATCH 41/46] chore: set default filter dates if missing (#36597) --- .../fixed_asset_register/fixed_asset_register.py | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) 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 94c77ea517c..bf62a8fb39c 100644 --- a/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py +++ b/erpnext/assets/report/fixed_asset_register/fixed_asset_register.py @@ -7,13 +7,14 @@ from itertools import chain import frappe from frappe import _ from frappe.query_builder.functions import IfNull, Sum -from frappe.utils import cstr, flt, formatdate, getdate +from frappe.utils import add_months, cstr, flt, formatdate, getdate, nowdate, today from erpnext.accounts.report.financial_statements import ( get_fiscal_year_data, get_period_list, validate_fiscal_year, ) +from erpnext.accounts.utils import get_fiscal_year from erpnext.assets.doctype.asset.asset import get_asset_value_after_depreciation @@ -37,15 +38,26 @@ def get_conditions(filters): if filters.get("company"): conditions["company"] = filters.company + if filters.filter_based_on == "Date Range": + if not filters.from_date and not filters.to_date: + filters.from_date = add_months(nowdate(), -12) + filters.to_date = nowdate() + conditions[date_field] = ["between", [filters.from_date, filters.to_date]] - if filters.filter_based_on == "Fiscal Year": + elif filters.filter_based_on == "Fiscal Year": + if not filters.from_fiscal_year and not filters.to_fiscal_year: + default_fiscal_year = get_fiscal_year(today())[0] + filters.from_fiscal_year = default_fiscal_year + filters.to_fiscal_year = default_fiscal_year + fiscal_year = get_fiscal_year_data(filters.from_fiscal_year, filters.to_fiscal_year) validate_fiscal_year(fiscal_year, filters.from_fiscal_year, filters.to_fiscal_year) filters.year_start_date = getdate(fiscal_year.year_start_date) filters.year_end_date = getdate(fiscal_year.year_end_date) conditions[date_field] = ["between", [filters.year_start_date, filters.year_end_date]] + if filters.get("only_existing_assets"): conditions["is_existing_asset"] = filters.get("only_existing_assets") if filters.get("asset_category"): From 57449589e748389dcd02d016dd329ae8bab7da31 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Fri, 11 Aug 2023 16:20:50 +0530 Subject: [PATCH 42/46] chore: mergify - update stable branches [skip ci] --- .mergify.yml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.mergify.yml b/.mergify.yml index c5f3d83ce63..804b27d4357 100644 --- a/.mergify.yml +++ b/.mergify.yml @@ -15,6 +15,8 @@ pull_request_rules: - or: - base=version-13 - base=version-12 + - base=version-14 + - base=version-15 actions: close: comment: From 64614cd9152c54fe8a0b59416a0621f9992d41d4 Mon Sep 17 00:00:00 2001 From: ruthra kumar Date: Fri, 11 Aug 2023 10:45:42 +0530 Subject: [PATCH 43/46] refactor(test): don't set po_no by default --- erpnext/selling/doctype/sales_order/test_sales_order.py | 2 +- .../stock/doctype/delivery_note/test_delivery_note.py | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/erpnext/selling/doctype/sales_order/test_sales_order.py b/erpnext/selling/doctype/sales_order/test_sales_order.py index c85a4fb2f0d..954393f5730 100644 --- a/erpnext/selling/doctype/sales_order/test_sales_order.py +++ b/erpnext/selling/doctype/sales_order/test_sales_order.py @@ -2055,7 +2055,7 @@ def make_sales_order(**args): so.company = args.company or "_Test Company" so.customer = args.customer or "_Test Customer" so.currency = args.currency or "INR" - so.po_no = args.po_no or "12345" + so.po_no = args.po_no or "" if args.selling_price_list: so.selling_price_list = args.selling_price_list diff --git a/erpnext/stock/doctype/delivery_note/test_delivery_note.py b/erpnext/stock/doctype/delivery_note/test_delivery_note.py index 0ef3027bce3..48b8ab75042 100644 --- a/erpnext/stock/doctype/delivery_note/test_delivery_note.py +++ b/erpnext/stock/doctype/delivery_note/test_delivery_note.py @@ -703,7 +703,7 @@ class TestDeliveryNote(FrappeTestCase): def test_dn_billing_status_case1(self): # SO -> DN -> SI - so = make_sales_order() + so = make_sales_order(po_no="12345") dn = create_dn_against_so(so.name, delivered_qty=2) self.assertEqual(dn.status, "To Bill") @@ -730,7 +730,7 @@ class TestDeliveryNote(FrappeTestCase): make_sales_invoice, ) - so = make_sales_order() + so = make_sales_order(po_no="12345") si = make_sales_invoice(so.name) si.get("items")[0].qty = 5 @@ -774,7 +774,7 @@ class TestDeliveryNote(FrappeTestCase): frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1) - so = make_sales_order() + so = make_sales_order(po_no="12345") dn1 = make_delivery_note(so.name) dn1.get("items")[0].qty = 2 @@ -820,7 +820,7 @@ class TestDeliveryNote(FrappeTestCase): from erpnext.accounts.doctype.sales_invoice.sales_invoice import make_delivery_note from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice - so = make_sales_order() + so = make_sales_order(po_no="12345") si = make_sales_invoice(so.name) si.submit() @@ -1227,6 +1227,7 @@ class TestDeliveryNote(FrappeTestCase): self.assertEqual(get_reserved_qty(item, warehouse), 0 if dont_reserve_qty else qty_to_reserve) def tearDown(self): + frappe.db.rollback() frappe.db.set_single_value("Selling Settings", "dont_reserve_sales_order_qty_on_sales_return", 0) From 627986efa1a29ccf419f0e845cdca4f49589bac3 Mon Sep 17 00:00:00 2001 From: Anand Baburajan Date: Fri, 11 Aug 2023 18:01:27 +0530 Subject: [PATCH 44/46] fix: wrap none type rate under flt (#36602) --- erpnext/controllers/status_updater.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/erpnext/controllers/status_updater.py b/erpnext/controllers/status_updater.py index a4bc4a9c69e..f3663cc5271 100644 --- a/erpnext/controllers/status_updater.py +++ b/erpnext/controllers/status_updater.py @@ -233,7 +233,7 @@ class StatusUpdater(Document): if hasattr(d, "qty") and d.qty > 0 and self.get("is_return"): frappe.throw(_("For an item {0}, quantity must be negative number").format(d.item_code)) - if hasattr(d, "item_code") and hasattr(d, "rate") and d.rate < 0: + if hasattr(d, "item_code") and hasattr(d, "rate") and flt(d.rate) < 0: frappe.throw(_("For an item {0}, rate must be a positive number").format(d.item_code)) if d.doctype == args["source_dt"] and d.get(args["join_field"]): From 6b464edf8499b7cc0211a6c80f9ea6e1858abb1f Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 12 Aug 2023 11:21:33 +0530 Subject: [PATCH 45/46] fix: dont render demo clear button if onboarding tour present --- erpnext/public/js/utils/demo.js | 20 +++++++++++++++----- 1 file changed, 15 insertions(+), 5 deletions(-) diff --git a/erpnext/public/js/utils/demo.js b/erpnext/public/js/utils/demo.js index 05866e98647..6cacd5de889 100644 --- a/erpnext/public/js/utils/demo.js +++ b/erpnext/public/js/utils/demo.js @@ -1,15 +1,25 @@ $(document).on("toolbar_setup", function () { if (frappe.boot.sysdefaults.demo_company) { - erpnext.setup_clear_button(); + render_clear_demo_button(); } - // for first load + // for first load after setup. frappe.realtime.on("demo_data_complete", () => { - erpnext.setup_clear_button(); + render_clear_demo_button(); }); }); -erpnext.setup_clear_button = function () { +function render_clear_demo_button() { + let wait_for_onboaring_tours = setInterval(() => { + if ($("#driver-page-overlay").length) { + return; + } + setup_clear_demo_button(); + clearInterval(wait_for_onboaring_tours); + }, 2000); +} + +function setup_clear_demo_button() { let message_string = __( "Demo data is present on the system, erase data before starting real usage." ); @@ -68,4 +78,4 @@ erpnext.setup_clear_button = function () { } ); }); -}; +} From 2d3fa8040cfa7bd39cb12f8540cfbac31461adf9 Mon Sep 17 00:00:00 2001 From: Ankush Menat Date: Sat, 12 Aug 2023 11:33:35 +0530 Subject: [PATCH 46/46] fix(UX): make demo button dismissable for session --- erpnext/public/js/utils/demo.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/erpnext/public/js/utils/demo.js b/erpnext/public/js/utils/demo.js index 6cacd5de889..b59c4762e00 100644 --- a/erpnext/public/js/utils/demo.js +++ b/erpnext/public/js/utils/demo.js @@ -52,6 +52,12 @@ function setup_clear_demo_button() { > Clear Demo Data + + + + + +
`); @@ -78,4 +84,8 @@ function setup_clear_demo_button() { } ); }); + + $("#dismiss-demo-banner").on("click", function () { + $floatingBar.remove(); + }); }