diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js index 98276535a0a..87f5bdc0a5a 100644 --- a/erpnext/public/js/setup_wizard.js +++ b/erpnext/public/js/setup_wizard.js @@ -19,6 +19,101 @@ frappe.setup.on("before_load", function () { }); erpnext.setup.slides_settings = [ + { + // Persona — help us tailor the setup + name: "persona", + title: __("A little about you"), + // subtitle shown under the title + help: __("A few quick questions so we can set things up the way you work."), + fields: [ + { + fieldname: "persona_implementing_for", + label: __("Who are you setting this up for?"), + fieldtype: "Select", + options: ["", "My own business", "A company I work for", "A client I'm consulting for"].join( + "\n" + ), + reqd: 1, + }, + { + fieldname: "persona_company_size", + label: __("How big is the team?"), + fieldtype: "Select", + options: ["", "1–10", "11–50", "51–200", "201–1,000", "1,000+"].join("\n"), + reqd: 1, + }, + { + fieldname: "persona_industry", + label: __("What kind of work do you do?"), + fieldtype: "Select", + options: [ + "", + "Manufacturing", + "Retail", + "Wholesale / Distribution", + "E-commerce", + "Services / Consulting", + "Construction / Real Estate", + "Technology / Software", + "Healthcare", + "Education", + "Agriculture", + "Food & Beverage", + "Non Profit", + "Other", + ].join("\n"), + reqd: 1, + }, + { + fieldname: "persona_current_system", + label: __("What do you use today?"), + fieldtype: "Select", + options: [ + "", + "Tally", + "QuickBooks", + "Zoho", + "Sage", + "SAP", + "Microsoft Dynamics", + "Oracle NetSuite", + "Xero", + "Excel / Spreadsheets", + "Nothing yet - starting fresh", + "Other", + ].join("\n"), + reqd: 1, + }, + { + fieldtype: "Section Break", + description: __("Select the modules that you plan to implement"), + }, + { fieldname: "module_accounting", label: __("Accounting"), fieldtype: "Check" }, + { fieldname: "module_stock", label: __("Stock"), fieldtype: "Check" }, + { fieldtype: "Column Break" }, + { fieldname: "module_manufacturing", label: __("Manufacturing"), fieldtype: "Check" }, + { fieldname: "module_projects", label: __("Project Management"), fieldtype: "Check" }, + ], + + onload: function (slide) { + this.bind_industry_modules(slide); + }, + + bind_industry_modules: function (slide) { + let me = this; + slide.get_input("persona_industry").on("change", function () { + me.apply_industry_modules(slide); + }); + }, + + apply_industry_modules: function (slide) { + let industry = slide.get_field("persona_industry").get_value(); + let modules = erpnext.setup.industry_modules[industry] || ["accounting"]; + ["accounting", "stock", "manufacturing", "projects"].forEach(function (module) { + slide.get_field("module_" + module).set_value(modules.includes(module) ? 1 : 0); + }); + }, + }, { // Organization name: "organization", @@ -243,6 +338,24 @@ erpnext.setup.slides_settings = [ }, ]; +// Modules pre-selected on the persona slide based on the chosen industry. +// Keys must match the persona_industry option values. Accounting is always on. +erpnext.setup.industry_modules = { + Manufacturing: ["accounting", "stock", "manufacturing"], + Retail: ["accounting", "stock"], + "Wholesale / Distribution": ["accounting", "stock"], + "E-commerce": ["accounting", "stock"], + "Services / Consulting": ["accounting", "projects"], + "Construction / Real Estate": ["accounting", "stock", "projects"], + "Technology / Software": ["accounting", "projects"], + Healthcare: ["accounting", "stock"], + Education: ["accounting", "projects"], + Agriculture: ["accounting", "stock"], + "Food & Beverage": ["accounting", "stock", "manufacturing"], + "Non Profit": ["accounting", "projects"], + Other: ["accounting"], +}; + // Source: https://en.wikipedia.org/wiki/Fiscal_year // default 1st Jan - 31st Dec diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py index 20330d89631..0f43fe9a860 100644 --- a/erpnext/setup/setup_wizard/setup_wizard.py +++ b/erpnext/setup/setup_wizard/setup_wizard.py @@ -4,12 +4,13 @@ import frappe from frappe import _ +from frappe.utils.telemetry import capture 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): +def get_setup_stages(args=None): # nosemgrep stages = [ { "status": _("Installing presets"), @@ -28,6 +29,13 @@ def get_setup_stages(args=None): {"fn": setup_defaults, "args": args, "fail_msg": _("Failed to setup defaults")}, ], }, + { + "status": _("Personalizing your setup"), + "fail_msg": _("Failed to personalize your setup"), + "tasks": [ + {"fn": capture_user_persona, "args": args, "fail_msg": _("Failed to personalize your setup")} + ], + }, ] if args.get("setup_demo"): @@ -42,15 +50,38 @@ def get_setup_stages(args=None): return stages -def stage_fixtures(args): +def capture_user_persona(args): # nosemgrep + """Send the persona answers captured on the setup slide to telemetry.""" + if not args: + return + + capture( + "user_persona_submitted", + "erpnext", + properties={ + "implementing_for": args.get("persona_implementing_for"), + "company_size": args.get("persona_company_size"), + "industry": args.get("persona_industry"), + "current_system": args.get("persona_current_system"), + "module_accounting": bool(args.get("module_accounting")), + "module_stock": bool(args.get("module_stock")), + "module_manufacturing": bool(args.get("module_manufacturing")), + "module_projects": bool(args.get("module_projects")), + "country": args.get("country"), + "language": args.get("language"), + }, + ) + + +def stage_fixtures(args): # nosemgrep fixtures.install(args.get("country")) -def setup_company(args): +def setup_company(args): # nosemgrep fixtures.install_company(args) -def setup_defaults(args): +def setup_defaults(args): # nosemgrep fixtures.install_defaults(frappe._dict(args)) @@ -59,7 +90,7 @@ def setup_demo(args): # nosemgrep # Only for programmatical use -def setup_complete(args=None): +def setup_complete(args=None): # nosemgrep stage_fixtures(args) setup_company(args) setup_defaults(args)