User Progress (#10336)
* [user-progress] first cut
* [user-progress] Add users slide, remove taxes, make sample data
* wip tests
* [setup-wiz] UI test
* [user-progress] notif test, docs trim
* wip
* [user-progress] Setup Progress single to update action states, fixtures
* setup progress actions patch
* rename sales_target field patch
* [progress] wip reform slide data
* [progress] remove slide data
* [setup] add roles for GST doctypes, remove commit from fixtures
diff --git a/.travis.yml b/.travis.yml
index a70062f..92c15e0 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -58,4 +58,5 @@
- bench reinstall --yes
- bench execute erpnext.setup.setup_wizard.utils.complete
- bench execute erpnext.setup.utils.enable_all_roles_and_domains
+ - bench --verbose run-setup-wizard-ui-test
- bench run-ui-tests --app erpnext
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/index.md b/erpnext/docs/user/manual/en/setting-up/setup-wizard/index.md
index 244d893..c05c4af 100644
--- a/erpnext/docs/user/manual/en/setting-up/setup-wizard/index.md
+++ b/erpnext/docs/user/manual/en/setting-up/setup-wizard/index.md
@@ -1,6 +1,6 @@
# Setup Wizard
-The Setup Wizard helps you quickly setup your ERPnext by helping you create your company, Items, Customer, Suppliers and will also setup a basic website with this data.
+The Setup Wizard helps you quickly setup ERPnext as per your locale and sets up your organisation.
Here is a quick overview of the steps:
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/index.txt b/erpnext/docs/user/manual/en/setting-up/setup-wizard/index.txt
index eb76558..b2f680a 100644
--- a/erpnext/docs/user/manual/en/setting-up/setup-wizard/index.txt
+++ b/erpnext/docs/user/manual/en/setting-up/setup-wizard/index.txt
@@ -1,10 +1,5 @@
step-1-language
step-2-currency-and-timezone
step-3-user-details
+step-4-two-factor-authentication
step-5-company-details
-step-6-letterhead-and-logo
-step-7-add-users
-step-8-tax-details
-step-9-customer-names
-step-10-suppliers
-step-11-item
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-10-suppliers.md b/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-10-suppliers.md
deleted file mode 100644
index 364b4d6..0000000
--- a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-10-suppliers.md
+++ /dev/null
@@ -1,12 +0,0 @@
-# Step 10: Suppliers
-
-Enter a few of your Suppliers' names.
-
-<img alt="Suppliers" class="screenshot"
-src="/docs/assets/img/setup-wizard/step-9.png">
-
----
-
-To understand Suppliers in detail visit [Supplier Master](/docs/user/manual/en/buying/supplier.html)
-
-{next}
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-11-item.md b/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-11-item.md
deleted file mode 100644
index 42d7e3d..0000000
--- a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-11-item.md
+++ /dev/null
@@ -1,16 +0,0 @@
-# Step 11: Item Names
-
-In this final step, please enter the names of the Items you buy or sell.
-
-<img alt="Add Items" class="screenshot"
-src="/docs/assets/img/setup-wizard/step-10.png">
-
-Please set the group of the item (Product / Service) and unit of measure. Don't worry you will be able to edit all of this later.
-
----
-
-## Thats it!
-
-Once you are done with the setup wizard you will see the familiar desktop page.
-
-{next}
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-6-letterhead-and-logo.md b/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-6-letterhead-and-logo.md
deleted file mode 100644
index 0286a3e..0000000
--- a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-6-letterhead-and-logo.md
+++ /dev/null
@@ -1,23 +0,0 @@
-# Step 6: Letterhead and Logo
-
-Attach Company Letterhead and Company Logo.
-
-<img alt="Company Logo and Letterhead" class="screenshot" src="/docs/assets/img/setup-wizard/step-5.png">
-
----
-
-### Letterhead
-
-A letterhead is the heading at the top of a sheet of letter paper (stationery). That heading usually consists of a name and an address, and a logo or corporate design.
-
-Click on the box ‘Attach Letterhead’ . Select the image file from the place it is stored and click enter.
-
-You may choose to skip this step if your letterhead is not ready.
-
-To select letterhead later through the setup module, read [Letter-head](/docs/user/manual/en/setting-up/print/letter-head.html)
-
-#### To "attach as web-link"
-
-For any attachments in ERPNext, you can also attach as a web-link. If you are using other tools like Dropbox or Google Docs to manage your files, you can set its public link.
-
-{next}
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-7-add-users.md b/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-7-add-users.md
deleted file mode 100644
index c92721c..0000000
--- a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-7-add-users.md
+++ /dev/null
@@ -1,7 +0,0 @@
-# Step 7: Add Users
-
-Add other users and assign them roles based on their job responsibilities.
-
-<img alt="Users" class="screenshot" src="/docs/assets/img/setup-wizard/step-6.png">
-
-{next}
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-8-tax-details.md b/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-8-tax-details.md
deleted file mode 100644
index dae88e4..0000000
--- a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-8-tax-details.md
+++ /dev/null
@@ -1,21 +0,0 @@
-# Step 8: Tax Details
-
-Enter any three types of taxes which you regularly pay. This wizard will create a tax master which will calculate the taxes as per the tax-type.
-
-<img alt="Tax Details" class="screenshot" src="/docs/assets/img/setup-wizard/step-7.png">
-
-Just set the tax name and the standard percentage levied.
-
----
-
-Some examples of tax types are given below.
-
-#### VAT
-
-A value added tax (VAT) is a form of consumption tax. From the perspective of the buyer, it is a tax on the purchase price. From that of the seller, it is a tax only on the value added to a product, material, or a service. From an accounting point of view, by the stage of its manufacture or distribution. The manufacturer remits to the government the difference between these two amounts, and retains the rest for themselves to offset the taxes they had previously paid on the inputs.
-
-The purpose of VAT is to generate tax revenues to the government similar to the corporate income tax or the personal income tax. For Example: When you shop at a departmental store and avail discount on the products, the store charges you 5% extra on the total bill as the VAT.
-
-To setup VAT in the setup wizard , simply enter the percentage amount levied by your government. To setup VAT at a later stage read [setting-up-taxes](/docs/user/manual/en/setting-up/setting-up-taxes.html)
-
-{next}
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-9-customer-names.md b/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-9-customer-names.md
deleted file mode 100644
index e348943..0000000
--- a/erpnext/docs/user/manual/en/setting-up/setup-wizard/step-9-customer-names.md
+++ /dev/null
@@ -1,22 +0,0 @@
-# Step 9: Customers
-
-Enter your Customer names and the contact person from that organisation.
-
-
-<img alt="Customers" class="screenshot" src="/docs/assets/img/setup-wizard/step-8.png">
-
----
-
-#### Difference between a customer name and a contact name
-
-A customer name is the name of the organisation and a contact name is the name of the person from that organisation.
-
-For Example: If American Power Mills is an organisation name and their founder Shiv Agarwal has installed ERPNext on his system. Then,
-
-Customer Name: American Power Mills
-
-Contact Name: Shiv Agarwal
-
-To understand Customer in detail visit [Customer Details](/docs/user/manual/en/CRM/customer.html)
-
-{next}
diff --git a/erpnext/hooks.py b/erpnext/hooks.py
index 7e65fc9..e5d9ef9 100644
--- a/erpnext/hooks.py
+++ b/erpnext/hooks.py
@@ -27,6 +27,8 @@
# setup wizard
setup_wizard_requires = "assets/erpnext/js/setup_wizard.js"
setup_wizard_complete = "erpnext.setup.setup_wizard.setup_wizard.setup_complete"
+setup_wizard_success = "erpnext.setup.setup_wizard.setup_wizard.setup_success"
+setup_wizard_test = "erpnext.setup.setup_wizard.test_setup_wizard.run_setup_wizard_test"
before_install = "erpnext.setup.install.check_setup_wizard_not_completed"
after_install = "erpnext.setup.install.after_install"
@@ -34,6 +36,8 @@
boot_session = "erpnext.startup.boot.boot_session"
notification_config = "erpnext.startup.notifications.get_notification_config"
get_help_messages = "erpnext.utilities.activation.get_help_messages"
+get_user_progress_slides = "erpnext.utilities.user_progress.get_user_progress_slides"
+update_and_get_user_progress = "erpnext.utilities.user_progress_utils.update_default_domain_actions_and_get_state"
on_session_creation = "erpnext.shopping_cart.utils.set_cart_count"
on_logout = "erpnext.shopping_cart.utils.clear_cart_count"
diff --git a/erpnext/patches.txt b/erpnext/patches.txt
index 7ec2753..c14cbab 100644
--- a/erpnext/patches.txt
+++ b/erpnext/patches.txt
@@ -434,4 +434,6 @@
erpnext.patches.v8_5.remove_project_type_property_setter
erpnext.patches.v8_7.add_more_gst_fields
erpnext.patches.v8_7.fix_purchase_receipt_status
-erpnext.patches.v8_6.rename_bom_update_tool
\ No newline at end of file
+erpnext.patches.v8_6.rename_bom_update_tool
+erpnext.patches.v8_9.add_setup_progress_actions
+erpnext.patches.v8_9.rename_company_sales_target_field
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/__init__.py b/erpnext/patches/v8_9/__init__.py
similarity index 100%
rename from erpnext/docs/user/manual/en/setting-up/setup-wizard/__init__.py
rename to erpnext/patches/v8_9/__init__.py
diff --git a/erpnext/patches/v8_9/add_setup_progress_actions.py b/erpnext/patches/v8_9/add_setup_progress_actions.py
new file mode 100644
index 0000000..25698cc
--- /dev/null
+++ b/erpnext/patches/v8_9/add_setup_progress_actions.py
@@ -0,0 +1,37 @@
+
+from __future__ import unicode_literals
+import frappe
+from frappe import _
+
+def execute():
+ """Add setup progress actions"""
+ frappe.reload_doc("setup", "doctype", "setup_progress")
+ frappe.reload_doc("setup", "doctype", "setup_progress_action")
+
+ actions = [
+ {"action_name": _("Add Company"), "action_doctype": "Company", "min_doc_count": 1, "is_completed": 1,
+ "domains": '[]' },
+ {"action_name": _("Add Customers"), "action_doctype": "Customer", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' },
+ {"action_name": _("Add Suppliers"), "action_doctype": "Supplier", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' },
+ {"action_name": _("Add Products"), "action_doctype": "Item", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' },
+ {"action_name": _("Add Programs"), "action_doctype": "Program", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Education"]' },
+ {"action_name": _("Add Instructors"), "action_doctype": "Instructor", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Education"]' },
+ {"action_name": _("Add Courses"), "action_doctype": "Course", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Education"]' },
+ {"action_name": _("Add Rooms"), "action_doctype": "Room", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Education"]' },
+ {"action_name": _("Add Users"), "action_doctype": "User", "min_doc_count": 4, "is_completed": 0,
+ "domains": '[]' }
+ ]
+
+ setup_progress = frappe.get_doc("Setup Progress", "Setup Progress")
+ for action in actions:
+ setup_progress.append("actions", action)
+
+ setup_progress.save(ignore_permissions=True)
+
diff --git a/erpnext/patches/v8_9/rename_company_sales_target_field.py b/erpnext/patches/v8_9/rename_company_sales_target_field.py
new file mode 100644
index 0000000..8c54283
--- /dev/null
+++ b/erpnext/patches/v8_9/rename_company_sales_target_field.py
@@ -0,0 +1,7 @@
+from __future__ import unicode_literals
+import frappe
+from frappe.model.utils.rename_field import rename_field
+
+def execute():
+ frappe.reload_doc("setup", "doctype", "company")
+ rename_field("Company", "sales_target", "monthly_sales_target")
diff --git a/erpnext/public/images/illustrations/shop.jpg b/erpnext/public/images/illustrations/shop.jpg
new file mode 100644
index 0000000..f92f7db
--- /dev/null
+++ b/erpnext/public/images/illustrations/shop.jpg
Binary files differ
diff --git a/erpnext/public/images/illustrations/shop2.jpg b/erpnext/public/images/illustrations/shop2.jpg
new file mode 100644
index 0000000..62e4649
--- /dev/null
+++ b/erpnext/public/images/illustrations/shop2.jpg
Binary files differ
diff --git a/erpnext/public/js/setup_wizard.js b/erpnext/public/js/setup_wizard.js
index d551885..320d871 100644
--- a/erpnext/public/js/setup_wizard.js
+++ b/erpnext/public/js/setup_wizard.js
@@ -7,7 +7,11 @@
}
};
-var erpnext_slides = [
+frappe.setup.on("before_load", function () {
+ erpnext.setup.slides_settings.map(frappe.setup.add_slide);
+});
+
+erpnext.setup.slides_settings = [
{
// Domain
name: 'domain',
@@ -18,14 +22,14 @@
fieldname: 'domain', label: __('Domain'), fieldtype: 'Select',
options: [
{ "label": __("Distribution"), "value": "Distribution" },
- { "label": __("Education"), "value": "Education" },
{ "label": __("Manufacturing"), "value": "Manufacturing" },
{ "label": __("Retail"), "value": "Retail" },
- { "label": __("Services"), "value": "Services" }
+ { "label": __("Services"), "value": "Services" },
+ { "label": __("Education"), "value": "Education" }
], reqd: 1
},
],
- help: __('Select the nature of your business.'),
+ // help: __('Select the nature of your business.'),
onload: function (slide) {
slide.get_input("domain").on("change", function () {
frappe.setup.domain = $(this).val();
@@ -40,7 +44,7 @@
domains: ["all"],
icon: "fa fa-bookmark",
title: __("The Brand"),
- help: __('Upload your letter head and logo. (you can edit them later).'),
+ // help: __('Upload your letter head and logo. (you can edit them later).'),
fields: [
{
fieldtype: "Attach Image", fieldname: "attach_logo",
@@ -79,6 +83,12 @@
slide.get_field("company_abbr").set_value("");
}
});
+ },
+ validate: function() {
+ if (!this.values.company_abbr) {
+ return false;
+ }
+ return true;
}
},
{
@@ -87,9 +97,9 @@
domains: ["all"],
title: __("Your Organization"),
icon: "fa fa-building",
- help: (frappe.setup.domain === 'Education' ?
- __('The name of the institute for which you are setting up this system.') :
- __('The name of your company for which you are setting up this system.')),
+ // help: (frappe.setup.domain === 'Education' ?
+ // __('The name of the institute for which you are setting up this system.') :
+ // __('The name of your company for which you are setting up this system.')),
fields: [
{
fieldname: 'company_tagline',
@@ -189,213 +199,6 @@
slide.form.fields_dict.fy_end_date.set_value(year_end_date);
});
}
- },
-
- {
- // Users
- name: 'users',
- domains: ["all"],
- title: __("Add Users"),
- help: __("Add users to your organization, other than yourself"),
- add_more: 1,
- max_count: 3,
- fields: [
- {fieldtype:"Section Break"},
- {fieldtype:"Data", fieldname:"user_fullname",
- label:__("Full Name"), static: 1},
- {fieldtype:"Data", fieldname:"user_email", label:__("Email ID"),
- placeholder:__("user@example.com"), options: "Email", static: 1},
- {fieldtype:"Column Break"},
- {fieldtype: "Check", fieldname: "user_sales",
- label:__("Sales"), "default": 1, static: 1,
- hidden: frappe.setup.domain==='Education' ? 1 : 0},
- {fieldtype: "Check", fieldname: "user_purchaser",
- label:__("Purchaser"), "default": 1, static: 1,
- hidden: frappe.setup.domain==='Education' ? 1 : 0},
- {fieldtype: "Check", fieldname: "user_accountant",
- label:__("Accountant"), "default": 1, static: 1,
- hidden: frappe.setup.domain==='Education' ? 1 : 0},
- ]
- },
-
- {
- // Sales Target
- name: 'Goals',
- domains: ['manufacturing', 'services', 'retail', 'distribution'],
- title: __("Set your Target"),
- help: __("Set a sales target you'd like to achieve."),
- fields: [
- {fieldtype:"Currency", fieldname:"sales_target", label:__("Monthly Sales Target")},
- ]
- },
-
- {
- // Taxes
- name: 'taxes',
- domains: ['manufacturing', 'services', 'retail', 'distribution'],
- icon: "fa fa-money",
- title: __("Add Taxes"),
- help: __("List your tax heads (e.g. VAT, Customs etc; they should have unique names) and their standard rates. This will create a standard template, which you can edit and add more later."),
- add_more: 1,
- max_count: 3,
- mandatory_entry: 0,
- fields: [
- {fieldtype:"Section Break"},
- {fieldtype:"Data", fieldname:"tax", label:__("Tax"),
- placeholder:__("e.g. VAT")},
- {fieldtype:"Column Break"},
- {fieldtype:"Float", fieldname:"tax_rate", label:__("Rate (%)"), placeholder:__("e.g. 5")}
- ]
- },
-
- {
- // Customers
- name: 'customers',
- domains: ['manufacturing', 'services', 'retail', 'distribution'],
- icon: "fa fa-group",
- title: __("Add Customers"),
- help: __("List a few of your customers. They could be organizations or individuals."),
- add_more: 1,
- max_count: 5,
- mandatory_entry: 1,
- fields: [
- {fieldtype:"Section Break"},
- {fieldtype:"Data", fieldname:"customer", label:__("Customer"),
- placeholder:__("Customer Name")},
- {fieldtype:"Column Break"},
- {fieldtype:"Data", fieldname:"customer_contact",
- label:__("Contact Name"), placeholder:__("Contact Name")}
- ],
- },
-
- {
- // Suppliers
- name: 'suppliers',
- domains: ['manufacturing', 'services', 'retail', 'distribution'],
- icon: "fa fa-group",
- title: __("Your Suppliers"),
- help: __("List a few of your suppliers. They could be organizations or individuals."),
- add_more: 1,
- max_count: 5,
- mandatory_entry: 1,
- fields: [
- {fieldtype:"Section Break"},
- {fieldtype:"Data", fieldname:"supplier", label:__("Supplier"),
- placeholder:__("Supplier Name")},
- {fieldtype:"Column Break"},
- {fieldtype:"Data", fieldname:"supplier_contact",
- label:__("Contact Name"), placeholder:__("Contact Name")},
- ]
- },
-
- {
- // Products
- name: 'products',
- domains: ['manufacturing', 'services', 'retail', 'distribution'],
- icon: "fa fa-barcode",
- title: __("Your Products or Services"),
- help: __("List your products or services that you buy or sell. Make sure to check the Item Group, Unit of Measure and other properties when you start."),
- add_more: 1,
- max_count: 5,
- mandatory_entry: 1,
- fields: [
- {fieldtype:"Section Break", show_section_border: true},
- {fieldtype:"Data", fieldname:"item", label:__("Item"),
- placeholder:__("A Product or Service")},
- {fieldtype:"Select", label:__("Group"), fieldname:"item_group",
- options:[__("Products"), __("Services"),
- __("Raw Material"), __("Consumable"), __("Sub Assemblies")],
- "default": __("Products"), static: 1},
- {fieldtype:"Select", fieldname:"item_uom", label:__("UOM"),
- options:[__("Unit"), __("Nos"), __("Box"), __("Pair"), __("Kg"), __("Set"),
- __("Hour"), __("Minute"), __("Litre"), __("Meter"), __("Gram")],
- "default": __("Unit"), static: 1},
- {fieldtype: "Check", fieldname: "is_sales_item",
- label:__("We sell this Item"), default: 1, static: 1},
- {fieldtype: "Check", fieldname: "is_purchase_item",
- label:__("We buy this Item"), default: 1, static: 1},
- {fieldtype:"Column Break"},
- {fieldtype:"Currency", fieldname:"item_price", label:__("Rate"), static: 1},
- {fieldtype:"Attach Image", fieldname:"item_img", label:__("Attach Image"), is_private: 0, static: 1},
- ],
- get_item_count: function() {
- return this.item_count;
- }
- },
-
- {
- // Program
- name: 'program',
- domains: ["education"],
- title: __("Program"),
- help: __("Example: Masters in Computer Science"),
- add_more: 1,
- max_count: 5,
- mandatory_entry: 1,
- fields: [
- {fieldtype:"Section Break", show_section_border: true},
- {fieldtype:"Data", fieldname:"program", label:__("Program"), placeholder: __("Program Name")},
- ],
- },
-
- {
- // Course
- name: 'course',
- domains: ["education"],
- title: __("Course"),
- help: __("Example: Basic Mathematics"),
- add_more: 1,
- max_count: 5,
- mandatory_entry: 1,
- fields: [
- {fieldtype:"Section Break", show_section_border: true},
- {fieldtype:"Data", fieldname:"course", label:__("Course"), placeholder: __("Course Name")},
- ]
- },
-
- {
- // Instructor
- name: 'instructor',
- domains: ["education"],
- title: __("Instructor"),
- help: __("People who teach at your organisation"),
- add_more: 1,
- max_count: 5,
- mandatory_entry: 1,
- fields: [
- {fieldtype:"Section Break", show_section_border: true},
- {fieldtype:"Data", fieldname:"instructor", label:__("Instructor"), placeholder: __("Instructor Name")},
- ]
- },
-
- {
- // Room
- name: 'room',
- domains: ["education"],
- title: __("Room"),
- help: __("Classrooms/ Laboratories etc where lectures can be scheduled."),
- add_more: 1,
- max_count: 3,
- mandatory_entry: 1,
- fields: [
- {fieldtype:"Section Break", show_section_border: true},
- {fieldtype:"Data", fieldname:"room", label:__("Room")},
- {fieldtype:"Column Break"},
- {fieldtype:"Int", fieldname:"room_capacity", label:__("Room") + " Capacity", static: 1},
- ]
- },
-
- {
- // last slide: Sample Data
- name: 'bootstrap',
- domains: ["all"],
- title: __("Sample Data"),
- fields: [{fieldtype: "Section Break"},
- {fieldtype: "Check", fieldname: "add_sample_data",
- label: __("Add a few sample records"), "default": 1},
- {fieldtype: "Check", fieldname: "setup_website",
- label: __("Setup a simple website for my organization"), "default": 1}
- ]
}
];
@@ -422,23 +225,19 @@
"United Kingdom": ["04-01", "03-31"],
};
-frappe.setup.on("before_load", function () {
- erpnext_slides.map(frappe.setup.add_slide);
-});
-
-var test_values_edu = {
- "language": "english",
- "domain": "Education",
- "country": "India",
- "timezone": "Asia/Kolkata",
- "currency": "INR",
- "first_name": "Tester",
- "email": "test@example.com",
- "password": "test",
- "company_name": "Hogwarts",
- "company_abbr": "HS",
- "company_tagline": "School for magicians",
- "bank_account": "Gringotts Wizarding Bank",
- "fy_start_date": "2016-04-01",
- "fy_end_date": "2017-03-31"
-}
+// var test_values_edu = {
+// "language": "english",
+// "domain": "Education",
+// "country": "India",
+// "timezone": "Asia/Kolkata",
+// "currency": "INR",
+// "first_name": "Tester",
+// "email": "test@example.com",
+// "password": "test",
+// "company_name": "Hogwarts",
+// "company_abbr": "HS",
+// "company_tagline": "School for magicians",
+// "bank_account": "Gringotts Wizarding Bank",
+// "fy_start_date": "2016-04-01",
+// "fy_end_date": "2017-03-31"
+// }
diff --git a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.json b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.json
index 23cf082..7b3a8d6 100644
--- a/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.json
+++ b/erpnext/regional/doctype/gst_hsn_code/gst_hsn_code.json
@@ -84,13 +84,34 @@
"issingle": 0,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-06-30 20:12:57.903983",
- "modified_by": "Administrator",
+ "modified": "2017-08-31 14:38:52.220743",
+ "modified_by": "ewdszx@ed.ews",
"module": "Regional",
"name": "GST HSN Code",
"name_case": "",
"owner": "Administrator",
- "permissions": [],
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 1,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 1,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
diff --git a/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.js b/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.js
new file mode 100644
index 0000000..24c5fd3
--- /dev/null
+++ b/erpnext/regional/doctype/gst_hsn_code/test_gst_hsn_code.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: GST HSN Code", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new GST HSN Code
+ () => frappe.tests.make('GST HSN Code', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/regional/doctype/gst_settings/gst_settings.json b/erpnext/regional/doctype/gst_settings/gst_settings.json
index 61af138..04065e2 100644
--- a/erpnext/regional/doctype/gst_settings/gst_settings.json
+++ b/erpnext/regional/doctype/gst_settings/gst_settings.json
@@ -83,13 +83,34 @@
"issingle": 1,
"istable": 0,
"max_attachments": 0,
- "modified": "2017-06-28 16:20:21.206397",
- "modified_by": "Administrator",
+ "modified": "2017-08-31 14:39:15.625952",
+ "modified_by": "ewdszx@ed.ews",
"module": "Regional",
"name": "GST Settings",
"name_case": "",
"owner": "Administrator",
- "permissions": [],
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 0,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
"quick_entry": 1,
"read_only": 0,
"read_only_onload": 0,
diff --git a/erpnext/regional/doctype/gst_settings/test_gst_settings.js b/erpnext/regional/doctype/gst_settings/test_gst_settings.js
new file mode 100644
index 0000000..00fcca6
--- /dev/null
+++ b/erpnext/regional/doctype/gst_settings/test_gst_settings.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: GST Settings", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new GST Settings
+ () => frappe.tests.make('GST Settings', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/regional/india/setup.py b/erpnext/regional/india/setup.py
index 0c59ba0..46afeec 100644
--- a/erpnext/regional/india/setup.py
+++ b/erpnext/regional/india/setup.py
@@ -39,12 +39,12 @@
hsn_codes = json.loads(f.read())
create_hsn_codes(hsn_codes, code_field="hsn_code")
-
+
# SAC Codes
with open(os.path.join(os.path.dirname(__file__), 'sac_code_data.json'), 'r') as f:
sac_codes = json.loads(f.read())
create_hsn_codes(sac_codes, code_field="sac_code")
-
+
def create_hsn_codes(data, code_field):
for d in data:
if not frappe.db.exists("GST HSN Code", d[code_field]):
@@ -54,8 +54,6 @@
hsn_code.name = d[code_field]
hsn_code.db_insert()
- frappe.db.commit()
-
def add_custom_roles_for_reports():
for report_name in ('GST Sales Register', 'GST Purchase Register',
'GST Itemised Sales Register', 'GST Itemised Purchase Register'):
@@ -101,7 +99,7 @@
dict(fieldname='ecommerce_gstin', label='E-commerce GSTIN',
fieldtype='Data', insert_after='export_type', print_hide=1)
]
-
+
purchase_invoice_gst_fields = [
dict(fieldname='supplier_gstin', label='Supplier GSTIN',
fieldtype='Data', insert_after='supplier_address',
@@ -110,7 +108,7 @@
fieldtype='Data', insert_after='shipping_address',
options='shipping_address.gstin', print_hide=1)
]
-
+
sales_invoice_gst_fields = [
dict(fieldname='customer_gstin', label='Customer GSTIN',
fieldtype='Data', insert_after='shipping_address',
@@ -122,7 +120,7 @@
fieldtype='Data', insert_after='company_address',
options='company_address.gstin', print_hide=1)
]
-
+
custom_fields = {
'Address': [
dict(fieldname='gstin', label='Party GSTIN', fieldtype='Data',
diff --git a/erpnext/setup/doctype/company/company.json b/erpnext/setup/doctype/company/company.json
index c338a81..15e6b4b 100644
--- a/erpnext/setup/doctype/company/company.json
+++ b/erpnext/setup/doctype/company/company.json
@@ -201,6 +201,157 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
+ "fieldname": "sales_settings",
+ "fieldtype": "Section 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,
+ "label": "Sales",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "sales_monthly_history",
+ "fieldtype": "Small Text",
+ "hidden": 1,
+ "ignore_user_permissions": 0,
+ "ignore_xss_filter": 0,
+ "in_filter": 0,
+ "in_global_search": 0,
+ "in_list_view": 0,
+ "in_standard_filter": 0,
+ "label": "Sales Monthly History",
+ "length": 0,
+ "no_copy": 1,
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "monthly_sales_target",
+ "fieldtype": "Currency",
+ "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": "Monthly Sales Target",
+ "length": 0,
+ "no_copy": 0,
+ "options": "default_currency",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "column_break_goals",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "total_monthly_sales",
+ "fieldtype": "Currency",
+ "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": "Total Monthly Sales",
+ "length": 0,
+ "no_copy": 1,
+ "options": "default_currency",
+ "permlevel": 0,
+ "precision": "",
+ "print_hide": 0,
+ "print_hide_if_no_value": 0,
+ "read_only": 1,
+ "remember_last_selected_value": 0,
+ "report_hide": 0,
+ "reqd": 0,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
"fieldname": "charts_section",
"fieldtype": "Section Break",
"hidden": 0,
@@ -506,157 +657,6 @@
"bold": 0,
"collapsible": 0,
"columns": 0,
- "fieldname": "sales_settings",
- "fieldtype": "Section 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,
- "label": "Sales",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sales_monthly_history",
- "fieldtype": "Small Text",
- "hidden": 1,
- "ignore_user_permissions": 0,
- "ignore_xss_filter": 0,
- "in_filter": 0,
- "in_global_search": 0,
- "in_list_view": 0,
- "in_standard_filter": 0,
- "label": "Sales Monthly History",
- "length": 0,
- "no_copy": 1,
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "sales_target",
- "fieldtype": "Currency",
- "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": "Sales Target",
- "length": 0,
- "no_copy": 1,
- "options": "default_currency",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "column_break_goals",
- "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,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
- "fieldname": "total_monthly_sales",
- "fieldtype": "Currency",
- "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": "Total Monthly Sales",
- "length": 0,
- "no_copy": 1,
- "options": "default_currency",
- "permlevel": 0,
- "precision": "",
- "print_hide": 0,
- "print_hide_if_no_value": 0,
- "read_only": 1,
- "remember_last_selected_value": 0,
- "report_hide": 0,
- "reqd": 0,
- "search_index": 0,
- "set_only_once": 0,
- "unique": 0
- },
- {
- "allow_bulk_edit": 0,
- "allow_on_submit": 0,
- "bold": 0,
- "collapsible": 0,
- "columns": 0,
"fieldname": "default_settings",
"fieldtype": "Section Break",
"hidden": 0,
@@ -1991,7 +1991,7 @@
"istable": 0,
"max_attachments": 0,
"menu_index": 0,
- "modified": "2017-08-03 16:17:31.206886",
+ "modified": "2017-08-31 11:48:56.278568",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",
diff --git a/erpnext/setup/doctype/company/company.py b/erpnext/setup/doctype/company/company.py
index b945ee4..d3503cc 100644
--- a/erpnext/setup/doctype/company/company.py
+++ b/erpnext/setup/doctype/company/company.py
@@ -76,7 +76,10 @@
self.create_default_accounts()
self.create_default_warehouses()
- self.install_country_fixtures()
+ if cint(frappe.db.get_single_value('System Settings', 'setup_complete')):
+ # In the case of setup, fixtures should be installed after setup_success
+ # This also prevents db commits before setup is successful
+ install_country_fixtures(self.name)
if not frappe.db.get_value("Cost Center", {"is_group": 0, "company": self.name}):
self.create_default_cost_center()
@@ -95,12 +98,6 @@
frappe.clear_cache()
- def install_country_fixtures(self):
- path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(self.country))
- if os.path.exists(path.encode("utf-8")):
- frappe.get_attr("erpnext.regional.{0}.setup.setup"
- .format(self.country.lower()))(self)
-
def create_default_warehouses(self):
for wh_detail in [
{"warehouse_name": _("All Warehouses"), "is_group": 1},
@@ -311,6 +308,13 @@
return " - ".join(parts)
+def install_country_fixtures(company):
+ company_doc = frappe.get_doc("Company", company)
+ path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(company_doc.country))
+ if os.path.exists(path.encode("utf-8")):
+ frappe.get_attr("erpnext.regional.{0}.setup.setup"
+ .format(company_doc.country.lower()))(company_doc)
+
def update_company_current_month_sales(company):
current_month_year = formatdate(today(), "MM-yyyy")
diff --git a/erpnext/setup/doctype/company/company_dashboard.py b/erpnext/setup/doctype/company/company_dashboard.py
index da7f2b5..d6e250b 100644
--- a/erpnext/setup/doctype/company/company_dashboard.py
+++ b/erpnext/setup/doctype/company/company_dashboard.py
@@ -9,7 +9,7 @@
'graph_method': "frappe.utils.goal.get_monthly_goal_graph_data",
'graph_method_args': {
'title': 'Sales',
- 'goal_value_field': 'sales_target',
+ 'goal_value_field': 'monthly_sales_target',
'goal_total_field': 'total_monthly_sales',
'goal_history_field': 'sales_monthly_history',
'goal_doctype': 'Sales Invoice',
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/__init__.py b/erpnext/setup/doctype/setup_progress/__init__.py
similarity index 100%
copy from erpnext/docs/user/manual/en/setting-up/setup-wizard/__init__.py
copy to erpnext/setup/doctype/setup_progress/__init__.py
diff --git a/erpnext/setup/doctype/setup_progress/setup_progress.js b/erpnext/setup/doctype/setup_progress/setup_progress.js
new file mode 100644
index 0000000..5c78bd5
--- /dev/null
+++ b/erpnext/setup/doctype/setup_progress/setup_progress.js
@@ -0,0 +1,8 @@
+// Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+// For license information, please see license.txt
+
+frappe.ui.form.on('Setup Progress', {
+ refresh: function() {
+
+ }
+});
diff --git a/erpnext/setup/doctype/setup_progress/setup_progress.json b/erpnext/setup/doctype/setup_progress/setup_progress.json
new file mode 100644
index 0000000..2f886af
--- /dev/null
+++ b/erpnext/setup/doctype/setup_progress/setup_progress.json
@@ -0,0 +1,123 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2017-08-27 21:01:42.032109",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "actions_sb",
+ "fieldtype": "Section 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,
+ "label": "Actions",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "actions",
+ "fieldtype": "Table",
+ "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": "Actions",
+ "length": 0,
+ "no_copy": 0,
+ "options": "Setup Progress Action",
+ "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,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 1,
+ "is_submittable": 0,
+ "issingle": 1,
+ "istable": 0,
+ "max_attachments": 0,
+ "modified": "2017-08-28 17:44:43.100932",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Setup Progress",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [
+ {
+ "amend": 0,
+ "apply_user_permissions": 0,
+ "cancel": 0,
+ "create": 1,
+ "delete": 1,
+ "email": 1,
+ "export": 0,
+ "if_owner": 0,
+ "import": 0,
+ "permlevel": 0,
+ "print": 1,
+ "read": 1,
+ "report": 0,
+ "role": "System Manager",
+ "set_user_permissions": 0,
+ "share": 1,
+ "submit": 0,
+ "write": 1
+ }
+ ],
+ "quick_entry": 1,
+ "read_only": 1,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/setup_progress/setup_progress.py b/erpnext/setup/doctype/setup_progress/setup_progress.py
new file mode 100644
index 0000000..26eecd9
--- /dev/null
+++ b/erpnext/setup/doctype/setup_progress/setup_progress.py
@@ -0,0 +1,51 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+import frappe, json
+from frappe.model.document import Document
+
+class SetupProgress(Document):
+ pass
+
+def get_setup_progress():
+ if not getattr(frappe.local, "setup_progress", None):
+ frappe.local.setup_progress = frappe.get_doc("Setup Progress", "Setup Progress")
+
+ return frappe.local.setup_progress
+
+def get_action_completed_state(action_name):
+ return [d.is_completed for d in get_setup_progress().actions
+ if d.action_name == action_name][0]
+
+def update_action_completed_state(action_name):
+ action_table_doc = [d for d in get_setup_progress().actions
+ if d.action_name == action_name][0]
+ update_action(action_table_doc)
+
+def update_action(action_table_doc):
+ if not action_table_doc.is_completed and frappe.db.count(action_table_doc.action_doctype) >= action_table_doc.min_doc_count:
+ action_table_doc.is_completed = 1
+ action_table_doc.save()
+
+def update_domain_actions(domain):
+ for d in get_setup_progress().actions:
+ domains = json.loads(d.domains)
+ if domains == [] or domain in domains:
+ update_action(d)
+
+def get_domain_actions_state(domain):
+ state = {}
+ for d in get_setup_progress().actions:
+ domains = json.loads(d.domains)
+ if domains == [] or domain in domains:
+ state[d.action_name] = d.is_completed
+ return state
+
+@frappe.whitelist()
+def set_action_completed_state(action_name):
+ action_table_doc = [d for d in get_setup_progress().actions
+ if d.action_name == action_name][0]
+ action_table_doc.is_completed = 1
+ action_table_doc.save()
diff --git a/erpnext/setup/doctype/setup_progress/test_setup_progress.js b/erpnext/setup/doctype/setup_progress/test_setup_progress.js
new file mode 100644
index 0000000..9e84e0c
--- /dev/null
+++ b/erpnext/setup/doctype/setup_progress/test_setup_progress.js
@@ -0,0 +1,23 @@
+/* eslint-disable */
+// rename this file from _test_[name] to test_[name] to activate
+// and remove above this line
+
+QUnit.test("test: Setup Progress", function (assert) {
+ let done = assert.async();
+
+ // number of asserts
+ assert.expect(1);
+
+ frappe.run_serially([
+ // insert a new Setup Progress
+ () => frappe.tests.make('Setup Progress', [
+ // values to be set
+ {key: 'value'}
+ ]),
+ () => {
+ assert.equal(cur_frm.doc.key, 'value');
+ },
+ () => done()
+ ]);
+
+});
diff --git a/erpnext/docs/user/manual/en/setting-up/setup-wizard/__init__.py b/erpnext/setup/doctype/setup_progress_action/__init__.py
similarity index 100%
copy from erpnext/docs/user/manual/en/setting-up/setup-wizard/__init__.py
copy to erpnext/setup/doctype/setup_progress_action/__init__.py
diff --git a/erpnext/setup/doctype/setup_progress_action/setup_progress_action.json b/erpnext/setup/doctype/setup_progress_action/setup_progress_action.json
new file mode 100644
index 0000000..030fd99
--- /dev/null
+++ b/erpnext/setup/doctype/setup_progress_action/setup_progress_action.json
@@ -0,0 +1,192 @@
+{
+ "allow_copy": 0,
+ "allow_guest_to_view": 0,
+ "allow_import": 0,
+ "allow_rename": 0,
+ "beta": 0,
+ "creation": "2017-08-27 21:00:40.715360",
+ "custom": 0,
+ "docstatus": 0,
+ "doctype": "DocType",
+ "document_type": "",
+ "editable_grid": 1,
+ "engine": "InnoDB",
+ "fields": [
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "action_name",
+ "fieldtype": "Data",
+ "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": "Action Name",
+ "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": 1,
+ "search_index": 0,
+ "set_only_once": 0,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "action_doctype",
+ "fieldtype": "Link",
+ "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": "Action Doctype",
+ "length": 0,
+ "no_copy": 0,
+ "options": "DocType",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "min_doc_count",
+ "fieldtype": "Int",
+ "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": "Min Doc Count",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "domains",
+ "fieldtype": "Code",
+ "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": "Domains",
+ "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,
+ "unique": 0
+ },
+ {
+ "allow_bulk_edit": 0,
+ "allow_on_submit": 0,
+ "bold": 0,
+ "collapsible": 0,
+ "columns": 0,
+ "fieldname": "is_completed",
+ "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": "Is Completed",
+ "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,
+ "unique": 0
+ }
+ ],
+ "has_web_view": 0,
+ "hide_heading": 0,
+ "hide_toolbar": 0,
+ "idx": 0,
+ "image_view": 0,
+ "in_create": 1,
+ "is_submittable": 0,
+ "issingle": 0,
+ "istable": 1,
+ "max_attachments": 0,
+ "modified": "2017-08-28 17:44:58.008526",
+ "modified_by": "Administrator",
+ "module": "Setup",
+ "name": "Setup Progress Action",
+ "name_case": "",
+ "owner": "Administrator",
+ "permissions": [],
+ "quick_entry": 1,
+ "read_only": 1,
+ "read_only_onload": 0,
+ "show_name_in_global_search": 0,
+ "sort_field": "modified",
+ "sort_order": "DESC",
+ "track_changes": 1,
+ "track_seen": 0
+}
\ No newline at end of file
diff --git a/erpnext/setup/doctype/setup_progress_action/setup_progress_action.py b/erpnext/setup/doctype/setup_progress_action/setup_progress_action.py
new file mode 100644
index 0000000..24af943
--- /dev/null
+++ b/erpnext/setup/doctype/setup_progress_action/setup_progress_action.py
@@ -0,0 +1,9 @@
+# -*- coding: utf-8 -*-
+# Copyright (c) 2017, Frappe Technologies Pvt. Ltd. and contributors
+# For license information, please see license.txt
+
+from __future__ import unicode_literals
+from frappe.model.document import Document
+
+class SetupProgressAction(Document):
+ pass
diff --git a/erpnext/setup/setup_wizard/install_fixtures.py b/erpnext/setup/setup_wizard/install_fixtures.py
index ea6da04..53e58a1 100644
--- a/erpnext/setup/setup_wizard/install_fixtures.py
+++ b/erpnext/setup/setup_wizard/install_fixtures.py
@@ -20,6 +20,28 @@
{ 'doctype': 'Domain', 'domain': _('Services')},
{ 'doctype': 'Domain', 'domain': _('Education')},
+ # Setup Progress
+ {'doctype': "Setup Progress", "actions": [
+ {"action_name": _("Add Company"), "action_doctype": "Company", "min_doc_count": 1, "is_completed": 1,
+ "domains": '[]' },
+ {"action_name": _("Add Customers"), "action_doctype": "Customer", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' },
+ {"action_name": _("Add Suppliers"), "action_doctype": "Supplier", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' },
+ {"action_name": _("Add Products"), "action_doctype": "Item", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Manufacturing", "Services", "Retail", "Distribution"]' },
+ {"action_name": _("Add Programs"), "action_doctype": "Program", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Education"]' },
+ {"action_name": _("Add Instructors"), "action_doctype": "Instructor", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Education"]' },
+ {"action_name": _("Add Courses"), "action_doctype": "Course", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Education"]' },
+ {"action_name": _("Add Rooms"), "action_doctype": "Room", "min_doc_count": 1, "is_completed": 0,
+ "domains": '["Education"]' },
+ {"action_name": _("Add Users"), "action_doctype": "User", "min_doc_count": 4, "is_completed": 0,
+ "domains": '[]' }
+ ]},
+
# address template
{'doctype':"Address Template", "country": country},
diff --git a/erpnext/setup/setup_wizard/sample_data.py b/erpnext/setup/setup_wizard/sample_data.py
index cfc6726..bc26e09 100644
--- a/erpnext/setup/setup_wizard/sample_data.py
+++ b/erpnext/setup/setup_wizard/sample_data.py
@@ -10,26 +10,27 @@
from frappe import _
from markdown2 import markdown
-def make_sample_data(args):
+def make_sample_data(domain, make_dependent = False):
"""Create a few opportunities, quotes, material requests, issues, todos, projects
to help the user get started"""
- items = frappe.get_all("Item", {'is_sales_item': 1})
- customers = frappe.get_all("Customer")
- warehouses = frappe.get_all("Warehouse")
+ if make_dependent:
+ items = frappe.get_all("Item", {'is_sales_item': 1})
+ customers = frappe.get_all("Customer")
+ warehouses = frappe.get_all("Warehouse")
- if items and customers:
- for i in range(3):
- customer = random.choice(customers).name
- make_opportunity(items, customer)
- make_quote(items, customer)
+ if items and customers:
+ for i in range(3):
+ customer = random.choice(customers).name
+ make_opportunity(items, customer)
+ make_quote(items, customer)
- make_projects(args.get('domain'))
+ if items and warehouses:
+ make_material_request(frappe.get_all("Item"))
+
+ make_projects(domain)
import_email_alert()
- if items and warehouses:
- make_material_request(frappe.get_all("Item"))
-
frappe.db.commit()
def make_opportunity(items, customer):
diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py
index 4dec3d7..40d11e5 100644
--- a/erpnext/setup/setup_wizard/setup_wizard.py
+++ b/erpnext/setup/setup_wizard/setup_wizard.py
@@ -15,6 +15,7 @@
from erpnext.accounts.doctype.account.account import RootNotEditable
from frappe.core.doctype.communication.comment import add_info_comment
from erpnext.setup.setup_wizard.domainify import setup_domain
+from erpnext.setup.doctype.company.company import install_country_fixtures
def setup_complete(args=None):
if frappe.db.sql("select name from tabCompany"):
@@ -25,24 +26,16 @@
create_price_lists(args)
create_fiscal_year_and_company(args)
create_sales_tax(args)
- create_users(args)
+ create_employee_for_self(args)
set_defaults(args)
create_territories()
create_feed_and_todo()
create_email_digest()
create_letter_head(args)
- create_taxes(args)
- create_items(args)
- create_customers(args)
- create_suppliers(args)
if args.get('domain').lower() == 'education':
create_academic_year()
create_academic_term()
- create_program(args)
- create_course(args)
- create_instructor(args)
- create_room(args)
if args.get('setup_website'):
website_maker(args)
@@ -58,16 +51,19 @@
frappe.db.commit()
frappe.clear_cache()
- if args.get("add_sample_data"):
- try:
- make_sample_data(args)
- frappe.clear_cache()
- except:
- # clear message
- if frappe.message_log:
- frappe.message_log.pop()
+ try:
+ make_sample_data(args.get('domain'))
+ frappe.clear_cache()
+ except:
+ # clear message
+ if frappe.message_log:
+ frappe.message_log.pop()
- pass
+ pass
+
+def setup_success(args=None):
+ company = frappe.db.sql("select name from tabCompany", as_dict=True)[0]["name"]
+ install_country_fixtures(company)
def create_fiscal_year_and_company(args):
if (args.get('fy_start_date')):
@@ -91,8 +87,7 @@
'country': args.get('country'),
'create_chart_of_accounts_based_on': 'Standard Template',
'chart_of_accounts': args.get('chart_of_accounts'),
- 'domain': args.get('domain'),
- 'sales_target': args.get('sales_target')
+ 'domain': args.get('domain')
}).insert()
#Enable shopping cart
@@ -259,22 +254,7 @@
tax_data.get('account_name'),
tax_data.get('tax_rate'), sales_tax)
-def get_country_wise_tax(country):
- data = {}
- with open (os.path.join(os.path.dirname(__file__), "data", "country_wise_tax.json")) as countrywise_tax:
- data = json.load(countrywise_tax).get(country)
-
- return data
-
-def create_taxes(args):
- for i in xrange(1,6):
- if args.get("tax_" + str(i)):
- # replace % in case someone also enters the % symbol
- tax_rate = cstr(args.get("tax_rate_" + str(i)) or "").replace("%", "")
- account_name = args.get("tax_" + str(i))
-
- make_tax_account_and_template(args.get("company_name") , account_name, tax_rate)
-
+# Tax utils start
def make_tax_account_and_template(company, account_name, tax_rate, template_name=None):
try:
if not isinstance(account_name, (list, tuple)):
@@ -292,15 +272,6 @@
except RootNotEditable:
pass
-def get_tax_account_group(company):
- tax_group = frappe.db.get_value("Account",
- {"account_name": "Duties and Taxes", "is_group": 1, "company": company})
- if not tax_group:
- tax_group = frappe.db.get_value("Account", {"is_group": 1, "root_type": "Liability",
- "account_type": "Tax", "company": company})
-
- return tax_group
-
def make_tax_account(company, account_name, tax_rate):
tax_group = get_tax_account_group(company)
if tax_group:
@@ -345,115 +316,23 @@
doc = frappe.get_doc(purchase_tax_template)
doc.insert(ignore_permissions=True)
-def create_items(args):
- for i in xrange(1,6):
- item = args.get("item_" + str(i))
- if item:
- item_group = _(args.get("item_group_" + str(i)))
- is_sales_item = args.get("is_sales_item_" + str(i))
- is_purchase_item = args.get("is_purchase_item_" + str(i))
- is_stock_item = item_group!=_("Services")
- default_warehouse = ""
- if is_stock_item:
- default_warehouse = frappe.db.get_value("Warehouse", filters={
- "warehouse_name": _("Finished Goods") if is_sales_item else _("Stores"),
- "company": args.get("company_name")
- })
+def get_tax_account_group(company):
+ tax_group = frappe.db.get_value("Account",
+ {"account_name": "Duties and Taxes", "is_group": 1, "company": company})
+ if not tax_group:
+ tax_group = frappe.db.get_value("Account", {"is_group": 1, "root_type": "Liability",
+ "account_type": "Tax", "company": company})
- try:
- frappe.get_doc({
- "doctype":"Item",
- "item_code": item,
- "item_name": item,
- "description": item,
- "show_in_website": 1,
- "is_sales_item": is_sales_item,
- "is_purchase_item": is_purchase_item,
- "is_stock_item": is_stock_item and 1 or 0,
- "item_group": item_group,
- "stock_uom": _(args.get("item_uom_" + str(i))),
- "default_warehouse": default_warehouse
- }).insert()
+ return tax_group
- if args.get("item_img_" + str(i)):
- item_image = args.get("item_img_" + str(i)).split(",")
- if len(item_image)==3:
- filename, filetype, content = item_image
- fileurl = save_file(filename, content, "Item", item, decode=True).file_url
- frappe.db.set_value("Item", item, "image", fileurl)
+# Tax utils end
- if args.get("item_price_" + str(i)):
- item_price = flt(args.get("item_price_" + str(i)))
+def get_country_wise_tax(country):
+ data = {}
+ with open (os.path.join(os.path.dirname(__file__), "data", "country_wise_tax.json")) as countrywise_tax:
+ data = json.load(countrywise_tax).get(country)
- if is_sales_item:
- price_list_name = frappe.db.get_value("Price List", {"selling": 1})
- make_item_price(item, price_list_name, item_price)
-
- if is_purchase_item:
- price_list_name = frappe.db.get_value("Price List", {"buying": 1})
- make_item_price(item, price_list_name, item_price)
-
- except frappe.NameError:
- pass
-
-def make_item_price(item, price_list_name, item_price):
- frappe.get_doc({
- "doctype": "Item Price",
- "price_list": price_list_name,
- "item_code": item,
- "price_list_rate": item_price
- }).insert()
-
-
-def create_customers(args):
- for i in xrange(1,6):
- customer = args.get("customer_" + str(i))
- if customer:
- try:
- doc = frappe.get_doc({
- "doctype":"Customer",
- "customer_name": customer,
- "customer_type": "Company",
- "customer_group": _("Commercial"),
- "territory": args.get("country"),
- "company": args.get("company_name")
- }).insert()
-
- if args.get("customer_contact_" + str(i)):
- create_contact(args.get("customer_contact_" + str(i)),
- "Customer", doc.name)
- except frappe.NameError:
- pass
-
-def create_suppliers(args):
- for i in xrange(1,6):
- supplier = args.get("supplier_" + str(i))
- if supplier:
- try:
- doc = frappe.get_doc({
- "doctype":"Supplier",
- "supplier_name": supplier,
- "supplier_type": _("Local"),
- "company": args.get("company_name")
- }).insert()
-
- if args.get("supplier_contact_" + str(i)):
- create_contact(args.get("supplier_contact_" + str(i)),
- "Supplier", doc.name)
- except frappe.NameError:
- pass
-
-def create_contact(contact, party_type, party):
- """Create contact based on given contact name"""
- contact = contact .split(" ")
-
- contact = frappe.get_doc({
- "doctype":"Contact",
- "first_name":contact[0],
- "last_name": len(contact) > 1 and contact[1] or ""
- })
- contact.append('links', dict(link_doctype=party_type, link_name=party))
- contact.insert()
+ return data
def create_letter_head(args):
if args.get("attach_letterhead"):
@@ -497,7 +376,7 @@
if args.get("email") and hasattr(frappe.local, "login_manager"):
frappe.local.login_manager.login_as(args.get("email"))
-def create_users(args):
+def create_employee_for_self(args):
if frappe.session.user == 'Administrator':
return
@@ -512,50 +391,7 @@
emp.flags.ignore_mandatory = True
emp.insert(ignore_permissions = True)
- for i in xrange(1,5):
- email = args.get("user_email_" + str(i))
- fullname = args.get("user_fullname_" + str(i))
- if email:
- if not fullname:
- fullname = email.split("@")[0]
-
- parts = fullname.split(" ", 1)
-
- user = frappe.get_doc({
- "doctype": "User",
- "email": email,
- "first_name": parts[0],
- "last_name": parts[1] if len(parts) > 1 else "",
- "enabled": 1,
- "user_type": "System User"
- })
-
- # default roles
- user.append_roles("Projects User", "Stock User", "Support Team")
-
- if args.get("user_sales_" + str(i)):
- user.append_roles("Sales User", "Sales Manager", "Accounts User")
- if args.get("user_purchaser_" + str(i)):
- user.append_roles("Purchase User", "Purchase Manager", "Accounts User")
- if args.get("user_accountant_" + str(i)):
- user.append_roles("Accounts Manager", "Accounts User")
-
- user.flags.delay_emails = True
-
- if not frappe.db.get_value("User", email):
- user.insert(ignore_permissions=True)
-
- # create employee
- emp = frappe.get_doc({
- "doctype": "Employee",
- "employee_name": fullname,
- "user_id": email,
- "status": "Active",
- "company": args.get("company_name")
- })
- emp.flags.ignore_mandatory = True
- emp.insert(ignore_permissions = True)
-
+# Schools
def create_academic_term():
at = ["Semester 1", "Semester 2", "Semester 3"]
ay = ["2013-14", "2014-15", "2015-16", "2016-17", "2017-18"]
@@ -578,46 +414,3 @@
academic_year.save()
except frappe.DuplicateEntryError:
pass
-
-def create_program(args):
- for i in xrange(1,6):
- if args.get("program_" + str(i)):
- program = frappe.new_doc("Program")
- program.program_code = args.get("program_" + str(i))
- program.program_name = args.get("program_" + str(i))
- try:
- program.save()
- except frappe.DuplicateEntryError:
- pass
-
-def create_course(args):
- for i in xrange(1,6):
- if args.get("course_" + str(i)):
- course = frappe.new_doc("Course")
- course.course_code = args.get("course_" + str(i))
- course.course_name = args.get("course_" + str(i))
- try:
- course.save()
- except frappe.DuplicateEntryError:
- pass
-
-def create_instructor(args):
- for i in xrange(1,6):
- if args.get("instructor_" + str(i)):
- instructor = frappe.new_doc("Instructor")
- instructor.instructor_name = args.get("instructor_" + str(i))
- try:
- instructor.save()
- except frappe.DuplicateEntryError:
- pass
-
-def create_room(args):
- for i in xrange(1,6):
- if args.get("room_" + str(i)):
- room = frappe.new_doc("Room")
- room.room_name = args.get("room_" + str(i))
- room.seating_capacity = args.get("room_capacity_" + str(i))
- try:
- room.save()
- except frappe.DuplicateEntryError:
- pass
diff --git a/erpnext/setup/setup_wizard/test_setup_wizard.py b/erpnext/setup/setup_wizard/test_setup_wizard.py
new file mode 100644
index 0000000..aed6698
--- /dev/null
+++ b/erpnext/setup/setup_wizard/test_setup_wizard.py
@@ -0,0 +1,57 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+from __future__ import unicode_literals
+
+import frappe, time
+from frappe.utils.selenium_testdriver import TestDriver
+
+def run_setup_wizard_test():
+ driver = TestDriver()
+ frappe.db.set_default('in_selenium', '1')
+
+ driver.login('#page-setup-wizard')
+ print('Running Setup Wizard Test...')
+
+ # Language slide
+ driver.set_select("language", "English (United Kingdom)")
+ driver.wait_for_ajax(True)
+ driver.wait_till_clickable(".next-btn").click()
+
+ # Region slide
+ driver.wait_for_ajax(True)
+ driver.set_select("country", "India")
+ driver.wait_for_ajax(True)
+ driver.wait_till_clickable(".next-btn").click()
+
+ # Profile slide
+ driver.set_field("full_name", "Joe Davis")
+ driver.set_field("email", "joe@example.com")
+ driver.set_field("password", "somethingrandom")
+ driver.wait_till_clickable(".next-btn").click()
+
+ # Brand slide
+ driver.set_select("domain", "Manufacturing")
+ driver.wait_till_clickable(".next-btn").click()
+
+ # Org slide
+ driver.set_field("company_name", "Acme Corp")
+ driver.wait_till_clickable(".next-btn").click()
+ driver.set_field("company_tagline", "Build Tools for Builders")
+ driver.set_field("bank_account", "BNL")
+ driver.wait_till_clickable(".complete-btn").click()
+
+ # Wait for desk (Lock wait timeout error)
+ # driver.wait_for('#page-desktop', timeout=200)
+
+ console = driver.get_console()
+ if frappe.flags.tests_verbose:
+ for line in console:
+ print(line)
+ print('-' * 40)
+ time.sleep(1)
+
+ frappe.db.set_default('in_selenium', None)
+ driver.close()
+
+ return True
\ No newline at end of file
diff --git a/erpnext/startup/notifications.py b/erpnext/startup/notifications.py
index 5b0ce39..b32f41e 100644
--- a/erpnext/startup/notifications.py
+++ b/erpnext/startup/notifications.py
@@ -60,8 +60,8 @@
"targets": {
"Company": {
- "filters" : { "sales_target": ( ">", 0 ) },
- "target_field" : "sales_target",
+ "filters" : { "monthly_sales_target": ( ">", 0 ) },
+ "target_field" : "monthly_sales_target",
"value_field" : "total_monthly_sales"
}
}
diff --git a/erpnext/tests/test_notifications.py b/erpnext/tests/test_notifications.py
index 752badf..467ddd3 100644
--- a/erpnext/tests/test_notifications.py
+++ b/erpnext/tests/test_notifications.py
@@ -9,31 +9,31 @@
class TestNotifications(unittest.TestCase):
def setUp(self):
- test_records = [
+ test_records_company = [
{
- "abbr": "_TC6",
- "company_name": "_Test Company 6",
- "country": "India",
- "default_currency": "INR",
- "doctype": "Company",
- "domain": "Manufacturing",
- "sales_target": 2000,
- "chart_of_accounts": "Standard"
+ "abbr": "_TC6",
+ "company_name": "_Test Company 6",
+ "country": "India",
+ "default_currency": "INR",
+ "doctype": "Company",
+ "domain": "Manufacturing",
+ "monthly_sales_target": 2000,
+ "chart_of_accounts": "Standard"
},
{
- "abbr": "_TC7",
- "company_name": "_Test Company 7",
- "country": "United States",
- "default_currency": "USD",
- "doctype": "Company",
- "domain": "Retail",
- "sales_target": 10000,
- "total_monthly_sales": 1000,
- "chart_of_accounts": "Standard"
+ "abbr": "_TC7",
+ "company_name": "_Test Company 7",
+ "country": "United States",
+ "default_currency": "USD",
+ "doctype": "Company",
+ "domain": "Retail",
+ "monthly_sales_target": 10000,
+ "total_monthly_sales": 1000,
+ "chart_of_accounts": "Standard"
},
]
- make_test_objects('Company', test_records=test_records, reset=True)
+ make_test_objects('Company', test_records=test_records_company, reset=True)
def test_get_notifications_for_targets(self):
'''
diff --git a/erpnext/utilities/activation.py b/erpnext/utilities/activation.py
index 1ae92c1..b694ea6 100644
--- a/erpnext/utilities/activation.py
+++ b/erpnext/utilities/activation.py
@@ -1,3 +1,6 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
import frappe, erpnext
from frappe import _
@@ -51,9 +54,8 @@
if get_level() > 6:
return []
- messages = []
-
domain = frappe.db.get_value('Company', erpnext.get_default_company(), 'domain')
+ messages = []
message_settings = [
frappe._dict(
@@ -138,7 +140,6 @@
)
]
-
for m in message_settings:
if not m.domain or domain in m.domain:
m.count = frappe.db.count(m.doctype)
diff --git a/erpnext/utilities/user_progress.py b/erpnext/utilities/user_progress.py
new file mode 100644
index 0000000..482179b
--- /dev/null
+++ b/erpnext/utilities/user_progress.py
@@ -0,0 +1,241 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe, erpnext
+from frappe import _
+from erpnext.setup.doctype.setup_progress.setup_progress import get_action_completed_state
+
+def get_slide_settings():
+ defaults = frappe.defaults.get_defaults()
+ domain = frappe.db.get_value('Company', erpnext.get_default_company(), 'domain')
+ company = defaults.get("company") or ''
+ # Initial state of slides
+ return [
+ frappe._dict(
+ action_name='Add Company',
+ title=_("Setup Company") if domain != 'Education' else _("Setup Institution"),
+ help=_('Setup your ' + ('company' if domain != 'Education' else 'institution') + ' and brand.'),
+ # image_src="/assets/erpnext/images/illustrations/shop.jpg",
+ fields=[],
+ done_state_title=_("You added " + company),
+ done_state_title_route=["Form", "Company", company],
+ help_links=[
+ {
+ "label": _("Chart of Accounts"),
+ "url": ["https://erpnext.org/docs/user/manual/en/accounts/chart-of-accounts"]
+ },
+ {
+ "label": _("Opening Balances"),
+ "video_id": "U5wPIvEn-0c"
+ }
+ ]
+ )
+ ,
+ frappe._dict(
+ action_name='Add Customers',
+ domains=('Manufacturing', 'Services', 'Retail', 'Distribution'),
+ icon="fa fa-group",
+ title=_("Add Customers"),
+ help=_("List a few of your customers. They could be organizations or individuals."),
+ fields=[
+ {"fieldtype":"Section Break"},
+ {"fieldtype":"Data", "fieldname":"customer", "label":_("Customer"),
+ "placeholder":_("Customer Name")},
+ {"fieldtype":"Column Break"},
+ {"fieldtype":"Data", "fieldname":"customer_contact",
+ "label":_("Contact Name"), "placeholder":_("Contact Name")}
+ ],
+ add_more=1, max_count=3, mandatory_entry=1,
+ submit_method="erpnext.utilities.user_progress_utils.create_customers",
+ done_state_title=_("Go to Customers"),
+ done_state_title_route=["List", "Customer"],
+ help_links=[
+ {
+ "label": _('Learn More'),
+ "url": ["https://erpnext.org/docs/user/manual/en/CRM/customer.html"]
+ }
+ ]
+ ),
+ frappe._dict(
+ action_name='Add Suppliers',
+ domains=('Manufacturing', 'Services', 'Retail', 'Distribution'),
+ icon="fa fa-group",
+ title=_("Your Suppliers"),
+ help=_("List a few of your suppliers. They could be organizations or individuals."),
+ fields=[
+ {"fieldtype":"Section Break"},
+ {"fieldtype":"Data", "fieldname":"supplier", "label":_("Supplier"),
+ "placeholder":_("Supplier Name")},
+ {"fieldtype":"Column Break"},
+ {"fieldtype":"Data", "fieldname":"supplier_contact",
+ "label":_("Contact Name"), "placeholder":_("Contact Name")},
+ ],
+ add_more=1, max_count=3, mandatory_entry=1,
+ submit_method="erpnext.utilities.user_progress_utils.create_suppliers",
+ done_state_title=_("Go to Suppliers"),
+ done_state_title_route=["List", "Supplier"],
+ help_links=[
+ {
+ "label": _('Learn More'),
+ "url": ["https://erpnext.org/docs/user/manual/en/buying/supplier"]
+ },
+ {
+ "label": _('Customers and Suppliers'),
+ "video_id": "zsrrVDk6VBs"
+ },
+ ]
+ ),
+ frappe._dict(
+ action_name='Add Products',
+ domains=['Manufacturing', 'Services', 'Retail', 'Distribution'],
+ icon="fa fa-barcode",
+ title=_("Your Products or Services"),
+ help=_("List your products or services that you buy or sell."),
+ fields=[
+ {"fieldtype":"Section Break", "show_section_border": 1},
+ {"fieldtype":"Data", "fieldname":"item", "label":_("Item"),
+ "placeholder":_("A Product")},
+ {"fieldtype":"Column Break"},
+ {"fieldtype":"Select", "fieldname":"item_uom", "label":_("UOM"),
+ "options":[_("Unit"), _("Nos"), _("Box"), _("Pair"), _("Kg"), _("Set"),
+ _("Hour"), _("Minute"), _("Litre"), _("Meter"), _("Gram")],
+ "default": _("Unit"), "static": 1},
+ {"fieldtype":"Column Break"},
+ {"fieldtype":"Currency", "fieldname":"item_price", "label":_("Rate"), "static": 1}
+ ],
+ add_more=1, max_count=3, mandatory_entry=1,
+ submit_method="erpnext.utilities.user_progress_utils.create_items",
+ done_state_title=_("Go to Items"),
+ done_state_title_route=["List", "Item"],
+ help_links=[
+ {
+ "label": _("Explore Sales Cycle"),
+ "video_id": "1eP90MWoDQM"
+ },
+ ]
+ ),
+
+ # School slides begin
+ frappe._dict(
+ action_name='Add Programs',
+ domains=("Education"),
+ title=_("Program"),
+ help=_("Example: Masters in Computer Science"),
+ fields=[
+ {"fieldtype":"Section Break", "show_section_border": 1},
+ {"fieldtype":"Data", "fieldname":"program", "label":_("Program"), "placeholder": _("Program Name")},
+ ],
+ add_more=1, max_count=3, mandatory_entry=1,
+ submit_method="erpnext.utilities.user_progress_utils.create_program",
+ done_state_title=_("Go to Programs"),
+ done_state_title_route=["List", "Program"],
+ help_links=[
+ {
+ "label": _("Student Application"),
+ "video_id": "l8PUACusN3E"
+ },
+ ]
+
+ ),
+ frappe._dict(
+ action_name='Add Courses',
+ domains=["Education"],
+ title=_("Course"),
+ help=_("Example: Basic Mathematics"),
+ fields=[
+ {"fieldtype":"Section Break", "show_section_border": 1},
+ {"fieldtype":"Data", "fieldname":"course", "label":_("Course"), "placeholder": _("Course Name")},
+ ],
+ add_more=1, max_count=3, mandatory_entry=1,
+ submit_method="erpnext.utilities.user_progress_utils.create_course",
+ done_state_title=_("Go to Courses"),
+ done_state_title_route=["List", "Course"],
+ help_links=[
+ {
+ "label": _('Add Students'),
+ "route": ["List", "Student"]
+ }
+ ]
+ ),
+ frappe._dict(
+ action_name='Add Instructors',
+ domains=["Education"],
+ title=_("Instructor"),
+ help=_("People who teach at your organisation"),
+ fields=[
+ {"fieldtype":"Section Break", "show_section_border": 1},
+ {"fieldtype":"Data", "fieldname":"instructor", "label":_("Instructor"), "placeholder": _("Instructor Name")},
+ ],
+ add_more=1, max_count=3, mandatory_entry=1,
+ submit_method="erpnext.utilities.user_progress_utils.create_instructor",
+ done_state_title=_("Go to Instructors"),
+ done_state_title_route=["List", "Instructor"],
+ help_links=[
+ {
+ "label": _('Student Batches'),
+ "route": ["List", "Student Batch"]
+ }
+ ]
+ ),
+ frappe._dict(
+ action_name='Add Rooms',
+ domains=["Education"],
+ title=_("Room"),
+ help=_("Classrooms/ Laboratories etc where lectures can be scheduled."),
+ fields=[
+ {"fieldtype":"Section Break", "show_section_border": 1},
+ {"fieldtype":"Data", "fieldname":"room", "label":_("Room")},
+ {"fieldtype":"Column Break"},
+ {"fieldtype":"Int", "fieldname":"room_capacity", "label":_("Room Capacity"), "static": 1},
+ ],
+ add_more=1, max_count=3, mandatory_entry=1,
+ submit_method="erpnext.utilities.user_progress_utils.create_room",
+ done_state_title=_("Go to Rooms"),
+ done_state_title_route=["List", "Room"],
+ help_links=[]
+ ),
+ # School slides end
+
+ frappe._dict(
+ action_name='Add Users',
+ title=_("Add Users"),
+ help=_("Add users to your organization, other than yourself."),
+ fields=[
+ {"fieldtype":"Section Break"},
+ {"fieldtype":"Data", "fieldname":"user_email", "label":_("Email ID"),
+ "placeholder":_("user@example.com"), "options": "Email", "static": 1},
+ {"fieldtype":"Column Break"},
+ {"fieldtype":"Data", "fieldname":"user_fullname",
+ "label":_("Full Name"), "static": 1},
+ ],
+ add_more=1, max_count=3, mandatory_entry=1,
+ submit_method="erpnext.utilities.user_progress_utils.create_users",
+ done_state_title=_("Go to Users"),
+ done_state_title_route=["List", "User"],
+ help_links=[
+ {
+ "label": _('Learn More'),
+ "url": ["https://erpnext.org/docs/user/manual/en/setting-up/users-and-permissions"]
+ },
+ {
+ "label": _('Users and Permissions'),
+ "video_id": "8Slw1hsTmUI"
+ },
+ ]
+ )
+ ]
+
+def get_user_progress_slides():
+ slides = []
+ slide_settings = get_slide_settings()
+
+ domain = frappe.db.get_value('Company', erpnext.get_default_company(), 'domain')
+
+ for s in slide_settings:
+ if not s.domains or (domain and domain in s.domains):
+ s.mark_as_done_method = "erpnext.setup.doctype.setup_progress.setup_progress.set_action_completed_state"
+ s.done = get_action_completed_state(s.action_name) or 0
+ slides.append(s)
+
+ return slides
+
diff --git a/erpnext/utilities/user_progress_utils.py b/erpnext/utilities/user_progress_utils.py
new file mode 100644
index 0000000..1c9c9e8
--- /dev/null
+++ b/erpnext/utilities/user_progress_utils.py
@@ -0,0 +1,214 @@
+# Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
+# License: GNU General Public License v3. See license.txt
+
+import frappe, erpnext
+
+import json
+from frappe import _
+from frappe.utils import flt
+from erpnext.setup.doctype.setup_progress.setup_progress import update_domain_actions, get_domain_actions_state
+
+@frappe.whitelist()
+def create_customers(args_data):
+ args = json.loads(args_data)
+ defaults = frappe.defaults.get_defaults()
+ for i in xrange(1,4):
+ customer = args.get("customer_" + str(i))
+ if customer:
+ try:
+ doc = frappe.get_doc({
+ "doctype":"Customer",
+ "customer_name": customer,
+ "customer_type": "Company",
+ "customer_group": _("Commercial"),
+ "territory": defaults.get("country"),
+ "company": defaults.get("company")
+ }).insert()
+
+ if args.get("customer_contact_" + str(i)):
+ create_contact(args.get("customer_contact_" + str(i)),
+ "Customer", doc.name)
+ except frappe.NameError:
+ pass
+
+@frappe.whitelist()
+def create_suppliers(args_data):
+ args = json.loads(args_data)
+ defaults = frappe.defaults.get_defaults()
+ for i in xrange(1,4):
+ supplier = args.get("supplier_" + str(i))
+ if supplier:
+ try:
+ doc = frappe.get_doc({
+ "doctype":"Supplier",
+ "supplier_name": supplier,
+ "supplier_type": _("Local"),
+ "company": defaults.get("company")
+ }).insert()
+
+ if args.get("supplier_contact_" + str(i)):
+ create_contact(args.get("supplier_contact_" + str(i)),
+ "Supplier", doc.name)
+ except frappe.NameError:
+ pass
+
+def create_contact(contact, party_type, party):
+ """Create contact based on given contact name"""
+ contact = contact .split(" ")
+
+ contact = frappe.get_doc({
+ "doctype":"Contact",
+ "first_name":contact[0],
+ "last_name": len(contact) > 1 and contact[1] or ""
+ })
+ contact.append('links', dict(link_doctype=party_type, link_name=party))
+ contact.insert()
+
+@frappe.whitelist()
+def create_items(args_data):
+ args = json.loads(args_data)
+ defaults = frappe.defaults.get_defaults()
+ for i in xrange(1,4):
+ item = args.get("item_" + str(i))
+ if item:
+ default_warehouse = ""
+ default_warehouse = frappe.db.get_value("Warehouse", filters={
+ "warehouse_name": _("Finished Goods"),
+ "company": defaults.get("company_name")
+ })
+
+ try:
+ frappe.get_doc({
+ "doctype":"Item",
+ "item_code": item,
+ "item_name": item,
+ "description": item,
+ "show_in_website": 1,
+ "is_sales_item": 1,
+ "is_purchase_item": 1,
+ "is_stock_item": 1,
+ "item_group": "Products",
+ "stock_uom": _(args.get("item_uom_" + str(i))),
+ "default_warehouse": default_warehouse
+ }).insert()
+
+ if args.get("item_price_" + str(i)):
+ item_price = flt(args.get("item_price_" + str(i)))
+
+ price_list_name = frappe.db.get_value("Price List", {"selling": 1})
+ make_item_price(item, price_list_name, item_price)
+ price_list_name = frappe.db.get_value("Price List", {"buying": 1})
+ make_item_price(item, price_list_name, item_price)
+
+ except frappe.NameError:
+ pass
+
+def make_item_price(item, price_list_name, item_price):
+ frappe.get_doc({
+ "doctype": "Item Price",
+ "price_list": price_list_name,
+ "item_code": item,
+ "price_list_rate": item_price
+ }).insert()
+
+# Schools
+@frappe.whitelist()
+def create_program(args_data):
+ args = json.loads(args_data)
+ for i in xrange(1,4):
+ if args.get("program_" + str(i)):
+ program = frappe.new_doc("Program")
+ program.program_code = args.get("program_" + str(i))
+ program.program_name = args.get("program_" + str(i))
+ try:
+ program.save()
+ except frappe.DuplicateEntryError:
+ pass
+
+@frappe.whitelist()
+def create_course(args_data):
+ args = json.loads(args_data)
+ for i in xrange(1,4):
+ if args.get("course_" + str(i)):
+ course = frappe.new_doc("Course")
+ course.course_code = args.get("course_" + str(i))
+ course.course_name = args.get("course_" + str(i))
+ try:
+ course.save()
+ except frappe.DuplicateEntryError:
+ pass
+
+@frappe.whitelist()
+def create_instructor(args_data):
+ args = json.loads(args_data)
+ for i in xrange(1,4):
+ if args.get("instructor_" + str(i)):
+ instructor = frappe.new_doc("Instructor")
+ instructor.instructor_name = args.get("instructor_" + str(i))
+ try:
+ instructor.save()
+ except frappe.DuplicateEntryError:
+ pass
+
+@frappe.whitelist()
+def create_room(args_data):
+ args = json.loads(args_data)
+ for i in xrange(1,4):
+ if args.get("room_" + str(i)):
+ room = frappe.new_doc("Room")
+ room.room_name = args.get("room_" + str(i))
+ room.seating_capacity = args.get("room_capacity_" + str(i))
+ try:
+ room.save()
+ except frappe.DuplicateEntryError:
+ pass
+
+@frappe.whitelist()
+def create_users(args_data):
+ if frappe.session.user == 'Administrator':
+ return
+ args = json.loads(args_data)
+ defaults = frappe.defaults.get_defaults()
+ for i in xrange(1,4):
+ email = args.get("user_email_" + str(i))
+ fullname = args.get("user_fullname_" + str(i))
+ if email:
+ if not fullname:
+ fullname = email.split("@")[0]
+
+ parts = fullname.split(" ", 1)
+
+ user = frappe.get_doc({
+ "doctype": "User",
+ "email": email,
+ "first_name": parts[0],
+ "last_name": parts[1] if len(parts) > 1 else "",
+ "enabled": 1,
+ "user_type": "System User"
+ })
+
+ # default roles
+ user.append_roles("Projects User", "Stock User", "Support Team")
+ user.flags.delay_emails = True
+
+ if not frappe.db.get_value("User", email):
+ user.insert(ignore_permissions=True)
+
+ # create employee
+ emp = frappe.get_doc({
+ "doctype": "Employee",
+ "employee_name": fullname,
+ "user_id": email,
+ "status": "Active",
+ "company": defaults.get("company")
+ })
+ emp.flags.ignore_mandatory = True
+ emp.insert(ignore_permissions = True)
+
+# Ennumerate the setup hooks you're going to need, apart from the slides
+
+@frappe.whitelist()
+def update_default_domain_actions_and_get_state():
+ domain = frappe.db.get_value('Company', erpnext.get_default_company(), 'domain')
+ update_domain_actions(domain)
+ return get_domain_actions_state(domain)