blob: f48402e175b4426513308cef417d6cbbe92cf399 [file] [log] [blame]
Deepesh Garg8ef257a2023-06-14 12:54:10 +05301# Copyright (c) 2023, Frappe Technologies Pvt. Ltd. and Contributors
2# License: GNU General Public License v3. See license.txt
3
4import json
5import os
Deepesh Garg86744b62023-06-19 09:44:57 +05306from random import randint
Deepesh Garg8ef257a2023-06-14 12:54:10 +05307
8import frappe
Ankush Menate4b863a2023-08-10 17:49:28 +05309from frappe import _
Deepesh Garg371413a2023-07-29 22:39:07 +053010from frappe.utils import add_days, getdate
Deepesh Garg8ef257a2023-06-14 12:54:10 +053011
Deepesh Garg567f4c32023-08-10 21:46:34 +053012from erpnext.accounts.doctype.payment_entry.payment_entry import get_payment_entry
Deepesh Garg371413a2023-07-29 22:39:07 +053013from erpnext.accounts.utils import get_fiscal_year
Deepesh Garg567f4c32023-08-10 21:46:34 +053014from erpnext.buying.doctype.purchase_order.purchase_order import make_purchase_invoice
15from erpnext.selling.doctype.sales_order.sales_order import make_sales_invoice
Deepesh Garg85e1c852023-06-19 14:12:23 +053016from erpnext.setup.setup_wizard.operations.install_fixtures import create_bank_account
Deepesh Garg77a29572023-06-16 13:43:55 +053017
Deepesh Garg8ef257a2023-06-14 12:54:10 +053018
Deepesh Garg8ef257a2023-06-14 12:54:10 +053019def setup_demo_data():
Ankush Menat3a21c902023-08-10 15:48:57 +053020 from frappe.utils.telemetry import capture
21
22 capture("demo_data_creation_started", "erpnext")
23 try:
24 company = create_demo_company()
25 process_masters()
26 make_transactions(company)
27 frappe.cache.delete_keys("bootinfo")
28 frappe.publish_realtime("demo_data_complete")
29 except Exception:
30 frappe.log_error("Failed to create demo data")
31 capture("demo_data_creation_failed", "erpnext", properties={"exception": frappe.get_traceback()})
32 raise
33 capture("demo_data_creation_completed", "erpnext")
Deepesh Garg77a29572023-06-16 13:43:55 +053034
35
36@frappe.whitelist()
37def clear_demo_data():
Ankush Menatc8e6e062023-08-10 18:27:34 +053038 from frappe.utils.telemetry import capture
39
Ankush Menat3a21c902023-08-10 15:48:57 +053040 frappe.only_for("System Manager")
Ankush Menatc8e6e062023-08-10 18:27:34 +053041
42 capture("demo_data_erased", "erpnext")
Ankush Menate4b863a2023-08-10 17:49:28 +053043 try:
44 company = frappe.db.get_single_value("Global Defaults", "demo_company")
45 create_transaction_deletion_record(company)
46 clear_masters()
47 delete_company(company)
48 default_company = frappe.db.get_single_value("Global Defaults", "default_company")
49 frappe.db.set_default("company", default_company)
50 except Exception:
51 frappe.db.rollback()
52 frappe.log_error("Failed to erase demo data")
53 frappe.throw(
54 _("Failed to erase demo data, please delete the demo company manually."),
55 title=_("Could Not Delete Demo Data"),
56 )
Deepesh Garg8ef257a2023-06-14 12:54:10 +053057
58
59def create_demo_company():
Deepesh Gargbb5387f2023-07-07 10:49:56 +053060 company = frappe.db.get_all("Company")[0].name
Deepesh Garg8ef257a2023-06-14 12:54:10 +053061 company_doc = frappe.get_doc("Company", company)
62
63 # Make a dummy company
64 new_company = frappe.new_doc("Company")
65 new_company.company_name = company_doc.company_name + " (Demo)"
66 new_company.abbr = company_doc.abbr + "D"
67 new_company.enable_perpetual_inventory = 1
68 new_company.default_currency = company_doc.default_currency
69 new_company.country = company_doc.country
70 new_company.chart_of_accounts_based_on = "Standard Template"
71 new_company.chart_of_accounts = company_doc.chart_of_accounts
72 new_company.insert()
73
Deepesh Garg5b6a9fc2023-06-17 13:08:18 +053074 # Set Demo Company as default to
Deepesh Garg86744b62023-06-19 09:44:57 +053075 frappe.db.set_single_value("Global Defaults", "demo_company", new_company.name)
76 frappe.db.set_default("company", new_company.name)
77
Deepesh Garg85e1c852023-06-19 14:12:23 +053078 bank_account = create_bank_account({"company_name": new_company.name})
79 frappe.db.set_value("Company", new_company.name, "default_bank_account", bank_account.name)
80
Deepesh Garg77a29572023-06-16 13:43:55 +053081 return new_company.name
Deepesh Garg8ef257a2023-06-14 12:54:10 +053082
Deepesh Garg77a29572023-06-16 13:43:55 +053083
84def process_masters():
Deepesh Garg5b6a9fc2023-06-17 13:08:18 +053085 for doctype in frappe.get_hooks("demo_master_doctypes"):
86 data = read_data_file_using_hooks(doctype)
87 if data:
88 for item in json.loads(data):
89 create_demo_record(item)
Deepesh Garg8ef257a2023-06-14 12:54:10 +053090
91
92def create_demo_record(doctype):
93 frappe.get_doc(doctype).insert(ignore_permissions=True)
94
95
Deepesh Garg77a29572023-06-16 13:43:55 +053096def make_transactions(company):
Deepesh Garg85e1c852023-06-19 14:12:23 +053097 frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 1)
ruthra kumar3c3c57c2024-02-25 15:08:13 +053098 from erpnext.accounts.utils import FiscalYearError
99
100 try:
101 start_date = get_fiscal_year(date=getdate())[1]
102 except FiscalYearError:
103 # User might have setup fiscal year for previous or upcoming years
104 active_fiscal_years = frappe.db.get_all("Fiscal Year", filters={"disabled": 0}, as_list=1)
105 if active_fiscal_years:
106 start_date = frappe.db.get_value("Fiscal Year", active_fiscal_years[0][0], "year_start_date")
107 else:
108 frappe.throw(_("There are no active Fiscal Years for which Demo Data can be generated."))
Deepesh Garg86744b62023-06-19 09:44:57 +0530109
Deepesh Garg5b6a9fc2023-06-17 13:08:18 +0530110 for doctype in frappe.get_hooks("demo_transaction_doctypes"):
111 data = read_data_file_using_hooks(doctype)
112 if data:
113 for item in json.loads(data):
Deepesh Garg86744b62023-06-19 09:44:57 +0530114 create_transaction(item, company, start_date)
Deepesh Garg77a29572023-06-16 13:43:55 +0530115
Deepesh Garg567f4c32023-08-10 21:46:34 +0530116 convert_order_to_invoices()
117 frappe.db.set_single_value("Stock Settings", "allow_negative_stock", 0)
118
Deepesh Garg77a29572023-06-16 13:43:55 +0530119
Deepesh Garg86744b62023-06-19 09:44:57 +0530120def create_transaction(doctype, company, start_date):
Deepesh Garg567f4c32023-08-10 21:46:34 +0530121 document_type = doctype.get("doctype")
Deepesh Garg85e1c852023-06-19 14:12:23 +0530122 warehouse = get_warehouse(company)
Deepesh Garg567f4c32023-08-10 21:46:34 +0530123
124 if document_type == "Purchase Order":
Deepesh Gargc9fd1822023-12-17 13:36:58 +0530125 posting_date = get_random_date(start_date, 1, 25)
Deepesh Garg567f4c32023-08-10 21:46:34 +0530126 else:
Deepesh Gargc9fd1822023-12-17 13:36:58 +0530127 posting_date = get_random_date(start_date, 31, 350)
Deepesh Garg85e1c852023-06-19 14:12:23 +0530128
Deepesh Garg86744b62023-06-19 09:44:57 +0530129 doctype.update(
130 {
131 "company": company,
132 "set_posting_time": 1,
Deepesh Garg567f4c32023-08-10 21:46:34 +0530133 "transaction_date": posting_date,
134 "schedule_date": posting_date,
135 "delivery_date": posting_date,
Deepesh Garg85e1c852023-06-19 14:12:23 +0530136 "set_warehouse": warehouse,
Deepesh Garg86744b62023-06-19 09:44:57 +0530137 }
138 )
Deepesh Garg77a29572023-06-16 13:43:55 +0530139
Deepesh Garg77a29572023-06-16 13:43:55 +0530140 doc = frappe.get_doc(doctype)
141 doc.save(ignore_permissions=True)
142 doc.submit()
143
144
Deepesh Garg567f4c32023-08-10 21:46:34 +0530145def convert_order_to_invoices():
146 for document in ["Purchase Order", "Sales Order"]:
147 # Keep some orders intentionally unbilled/unpaid
148 for i, order in enumerate(
149 frappe.db.get_all(
150 document, filters={"docstatus": 1}, fields=["name", "transaction_date"], limit=6
151 )
152 ):
153
154 if document == "Purchase Order":
155 invoice = make_purchase_invoice(order.name)
156 elif document == "Sales Order":
157 invoice = make_sales_invoice(order.name)
158
159 invoice.set_posting_time = 1
160 invoice.posting_date = order.transaction_date
161 invoice.due_date = order.transaction_date
Deepesh Garg5b157182024-01-04 10:48:01 +0530162 invoice.bill_date = order.transaction_date
163
164 if invoice.get("payment_schedule"):
165 invoice.payment_schedule[0].due_date = order.transaction_date
166
Deepesh Garg567f4c32023-08-10 21:46:34 +0530167 invoice.update_stock = 1
168 invoice.submit()
169
170 if i % 2 != 0:
171 payment = get_payment_entry(invoice.doctype, invoice.name)
ruthra kumar3c3c57c2024-02-25 15:08:13 +0530172 payment.posting_date = order.transaction_date
Deepesh Garg567f4c32023-08-10 21:46:34 +0530173 payment.reference_no = invoice.name
174 payment.submit()
Deepesh Garg333f2a52023-08-01 10:10:50 +0530175
176
Deepesh Garg567f4c32023-08-10 21:46:34 +0530177def get_random_date(start_date, start_range, end_range):
178 return add_days(start_date, randint(start_range, end_range))
Deepesh Garg86744b62023-06-19 09:44:57 +0530179
180
Deepesh Garg77a29572023-06-16 13:43:55 +0530181def create_transaction_deletion_record(company):
182 transaction_deletion_record = frappe.new_doc("Transaction Deletion Record")
183 transaction_deletion_record.company = company
ruthra kumar81309572024-03-20 15:16:33 +0530184 transaction_deletion_record.process_in_single_transaction = True
Deepesh Garg77a29572023-06-16 13:43:55 +0530185 transaction_deletion_record.save(ignore_permissions=True)
186 transaction_deletion_record.submit()
ruthra kumar81309572024-03-20 15:16:33 +0530187 transaction_deletion_record.start_deletion_tasks()
Deepesh Garg5b6a9fc2023-06-17 13:08:18 +0530188
189
190def clear_masters():
191 for doctype in frappe.get_hooks("demo_master_doctypes")[::-1]:
192 data = read_data_file_using_hooks(doctype)
193 if data:
194 for item in json.loads(data):
195 clear_demo_record(item)
196
197
Ankush Menate4b863a2023-08-10 17:49:28 +0530198def clear_demo_record(document):
Deepesh Garg567f4c32023-08-10 21:46:34 +0530199 document_type = document.get("doctype")
Ankush Menate4b863a2023-08-10 17:49:28 +0530200 del document["doctype"]
Ankush Menat8b579792023-08-14 14:16:48 +0530201
202 valid_columns = frappe.get_meta(document_type).get_valid_columns()
203
204 filters = document
205 for key in list(filters):
206 if key not in valid_columns:
207 filters.pop(key, None)
208
209 doc = frappe.get_doc(document_type, filters)
210 doc.delete(ignore_permissions=True)
Deepesh Garg5b6a9fc2023-06-17 13:08:18 +0530211
212
213def delete_company(company):
Deepesh Garg85e1c852023-06-19 14:12:23 +0530214 frappe.db.set_single_value("Global Defaults", "demo_company", "")
Deepesh Garg5b6a9fc2023-06-17 13:08:18 +0530215 frappe.delete_doc("Company", company, ignore_permissions=True)
216
217
218def read_data_file_using_hooks(doctype):
219 path = os.path.join(os.path.dirname(__file__), "demo_data")
220 with open(os.path.join(path, doctype + ".json"), "r") as f:
221 data = f.read()
222
223 return data
Deepesh Garg85e1c852023-06-19 14:12:23 +0530224
225
226def get_warehouse(company):
Deepesh Garg567f4c32023-08-10 21:46:34 +0530227 warehouses = frappe.db.get_all("Warehouse", {"company": company, "is_group": 0})
228 return warehouses[randint(0, 3)].name