diff --git a/erpnext/hooks.py b/erpnext/hooks.py index bf6894c906b2..2d3df5c4fa89 100644 --- a/erpnext/hooks.py +++ b/erpnext/hooks.py @@ -26,7 +26,7 @@ # setup wizard setup_wizard_requires = "assets/erpnext/js/setup_wizard.js" -setup_wizard_complete = "erpnext.setup.setup_wizard.setup_wizard.setup_complete" +setup_wizard_stages = "erpnext.setup.setup_wizard.setup_wizard.get_setup_stages" setup_wizard_test = "erpnext.setup.setup_wizard.test_setup_wizard.run_setup_wizard_test" before_install = "erpnext.setup.install.check_setup_wizard_not_completed" diff --git a/erpnext/patches/v7_1/update_lead_source.py b/erpnext/patches/v7_1/update_lead_source.py index 444159d8c428..7fd4c14ed150 100644 --- a/erpnext/patches/v7_1/update_lead_source.py +++ b/erpnext/patches/v7_1/update_lead_source.py @@ -2,7 +2,7 @@ from frappe import _ def execute(): - from erpnext.setup.setup_wizard.install_fixtures import default_lead_sources + from erpnext.setup.setup_wizard.operations.install_fixtures import default_lead_sources frappe.reload_doc('selling', 'doctype', 'lead_source') diff --git a/erpnext/setup/setup_wizard/data/__init__.py b/erpnext/setup/setup_wizard/data/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/erpnext/setup/setup_wizard/industry_type.py b/erpnext/setup/setup_wizard/data/industry_type.py similarity index 100% rename from erpnext/setup/setup_wizard/industry_type.py rename to erpnext/setup/setup_wizard/data/industry_type.py diff --git a/erpnext/setup/setup_wizard/operations/__init__.py b/erpnext/setup/setup_wizard/operations/__init__.py new file mode 100644 index 000000000000..e69de29bb2d1 diff --git a/erpnext/setup/setup_wizard/operations/company_setup.py b/erpnext/setup/setup_wizard/operations/company_setup.py new file mode 100644 index 000000000000..7fe7f0c2bc81 --- /dev/null +++ b/erpnext/setup/setup_wizard/operations/company_setup.py @@ -0,0 +1,125 @@ +# 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 +from frappe import _ +from frappe.utils import cstr, getdate +from frappe.utils.file_manager import save_file +from .default_website import website_maker +from erpnext.accounts.doctype.account.account import RootNotEditable + +def create_fiscal_year_and_company(args): + if (args.get('fy_start_date')): + curr_fiscal_year = get_fy_details(args.get('fy_start_date'), args.get('fy_end_date')) + frappe.get_doc({ + "doctype":"Fiscal Year", + 'year': curr_fiscal_year, + 'year_start_date': args.get('fy_start_date'), + 'year_end_date': args.get('fy_end_date'), + }).insert() + + if (args.get('company_name')): + frappe.get_doc({ + "doctype":"Company", + 'company_name':args.get('company_name'), + 'enable_perpetual_inventory': 1, + 'abbr':args.get('company_abbr'), + 'default_currency':args.get('currency'), + 'country': args.get('country'), + 'create_chart_of_accounts_based_on': 'Standard Template', + 'chart_of_accounts': args.get('chart_of_accounts'), + 'domain': args.get('domains')[0] + }).insert() + +def enable_shopping_cart(args): + # Needs price_lists + frappe.get_doc({ + "doctype": "Shopping Cart Settings", + "enabled": 1, + 'company': args.get('company_name') , + 'price_list': frappe.db.get_value("Price List", {"selling": 1}), + 'default_customer_group': _("Individual"), + 'quotation_series': "QTN-", + }).insert() + +def create_bank_account(args): + if args.get("bank_account"): + company_name = args.get('company_name') + bank_account_group = frappe.db.get_value("Account", + {"account_type": "Bank", "is_group": 1, "root_type": "Asset", + "company": company_name}) + if bank_account_group: + bank_account = frappe.get_doc({ + "doctype": "Account", + 'account_name': args.get("bank_account"), + 'parent_account': bank_account_group, + 'is_group':0, + 'company': company_name, + "account_type": "Bank", + }) + try: + return bank_account.insert() + except RootNotEditable: + frappe.throw(_("Bank account cannot be named as {0}").format(args.get("bank_account"))) + except frappe.DuplicateEntryError: + # bank account same as a CoA entry + pass + +def create_email_digest(): + from frappe.utils.user import get_system_managers + system_managers = get_system_managers(only_name=True) + if not system_managers: + return + + companies = frappe.db.sql_list("select name FROM `tabCompany`") + for company in companies: + if not frappe.db.exists("Email Digest", "Default Weekly Digest - " + company): + edigest = frappe.get_doc({ + "doctype": "Email Digest", + "name": "Default Weekly Digest - " + company, + "company": company, + "frequency": "Weekly", + "recipient_list": "\n".join(system_managers) + }) + + for df in edigest.meta.get("fields", {"fieldtype": "Check"}): + if df.fieldname != "scheduler_errors": + edigest.set(df.fieldname, 1) + + edigest.insert() + + # scheduler errors digest + if companies: + edigest = frappe.new_doc("Email Digest") + edigest.update({ + "name": "Scheduler Errors", + "company": companies[0], + "frequency": "Daily", + "recipient_list": "\n".join(system_managers), + "scheduler_errors": 1, + "enabled": 1 + }) + edigest.insert() + +def create_logo(args): + if args.get("attach_logo"): + attach_logo = args.get("attach_logo").split(",") + if len(attach_logo)==3: + filename, filetype, content = attach_logo + fileurl = save_file(filename, content, "Website Settings", "Website Settings", + decode=True).file_url + frappe.db.set_value("Website Settings", "Website Settings", "brand_html", + " {1}".format(fileurl, args.get("company_name") )) + +def create_website(args): + if args.get('setup_website'): + website_maker(args) + +def get_fy_details(fy_start_date, fy_end_date): + start_year = getdate(fy_start_date).year + if start_year == getdate(fy_end_date).year: + fy = cstr(start_year) + else: + fy = cstr(start_year) + '-' + cstr(start_year + 1) + return fy \ No newline at end of file diff --git a/erpnext/setup/setup_wizard/default_website.py b/erpnext/setup/setup_wizard/operations/default_website.py similarity index 100% rename from erpnext/setup/setup_wizard/default_website.py rename to erpnext/setup/setup_wizard/operations/default_website.py diff --git a/erpnext/setup/setup_wizard/operations/defaults_setup.py b/erpnext/setup/setup_wizard/operations/defaults_setup.py new file mode 100644 index 000000000000..b54d94e9ff35 --- /dev/null +++ b/erpnext/setup/setup_wizard/operations/defaults_setup.py @@ -0,0 +1,126 @@ +# 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 +from frappe import _ +from frappe.utils import cstr, getdate +from frappe.core.doctype.communication.comment import add_info_comment + +def set_default_settings(args): + # enable default currency + frappe.db.set_value("Currency", args.get("currency"), "enabled", 1) + + global_defaults = frappe.get_doc("Global Defaults", "Global Defaults") + global_defaults.update({ + 'current_fiscal_year': get_fy_details(args.get('fy_start_date'), args.get('fy_end_date')), + 'default_currency': args.get('currency'), + 'default_company':args.get('company_name') , + "country": args.get("country"), + }) + + global_defaults.save() + + system_settings = frappe.get_doc("System Settings") + system_settings.email_footer_address = args.get("company_name") + system_settings.save() + + domain_settings = frappe.get_single('Domain Settings') + domain_settings.set_active_domains(args.get('domains')) + domain_settings.save() + + stock_settings = frappe.get_doc("Stock Settings") + stock_settings.item_naming_by = "Item Code" + stock_settings.valuation_method = "FIFO" + stock_settings.default_warehouse = frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')}) + stock_settings.stock_uom = _("Nos") + stock_settings.auto_indent = 1 + stock_settings.auto_insert_price_list_rate_if_missing = 1 + stock_settings.automatically_set_serial_nos_based_on_fifo = 1 + stock_settings.save() + + selling_settings = frappe.get_doc("Selling Settings") + selling_settings.cust_master_name = "Customer Name" + selling_settings.so_required = "No" + selling_settings.dn_required = "No" + selling_settings.allow_multiple_items = 1 + selling_settings.save() + + buying_settings = frappe.get_doc("Buying Settings") + buying_settings.supp_master_name = "Supplier Name" + buying_settings.po_required = "No" + buying_settings.pr_required = "No" + buying_settings.maintain_same_rate = 1 + buying_settings.allow_multiple_items = 1 + buying_settings.save() + + notification_control = frappe.get_doc("Notification Control") + notification_control.quotation = 1 + notification_control.sales_invoice = 1 + notification_control.purchase_order = 1 + notification_control.save() + + hr_settings = frappe.get_doc("HR Settings") + hr_settings.emp_created_by = "Naming Series" + hr_settings.save() + +def set_no_copy_fields_in_variant_settings(): + # set no copy fields of an item doctype to item variant settings + doc = frappe.get_doc('Item Variant Settings') + doc.set_default_fields() + doc.save() + +def create_price_lists(args): + for pl_type, pl_name in (("Selling", _("Standard Selling")), ("Buying", _("Standard Buying"))): + frappe.get_doc({ + "doctype": "Price List", + "price_list_name": pl_name, + "enabled": 1, + "buying": 1 if pl_type == "Buying" else 0, + "selling": 1 if pl_type == "Selling" else 0, + "currency": args["currency"] + }).insert() + +def create_employee_for_self(args): + if frappe.session.user == 'Administrator': + return + + # create employee for self + emp = frappe.get_doc({ + "doctype": "Employee", + "employee_name": " ".join(filter(None, [args.get("first_name"), args.get("last_name")])), + "user_id": frappe.session.user, + "status": "Active", + "company": args.get("company_name") + }) + emp.flags.ignore_mandatory = True + emp.insert(ignore_permissions = True) + +def create_territories(): + """create two default territories, one for home country and one named Rest of the World""" + from frappe.utils.nestedset import get_root_of + country = frappe.db.get_default("country") + root_territory = get_root_of("Territory") + + for name in (country, _("Rest Of The World")): + if name and not frappe.db.exists("Territory", name): + frappe.get_doc({ + "doctype": "Territory", + "territory_name": name.replace("'", ""), + "parent_territory": root_territory, + "is_group": "No" + }).insert() + +def create_feed_and_todo(): + """update Activity feed and create todo for creation of item, customer, vendor""" + add_info_comment(**{ + "subject": _("ERPNext Setup Complete!") + }) + +def get_fy_details(fy_start_date, fy_end_date): + start_year = getdate(fy_start_date).year + if start_year == getdate(fy_end_date).year: + fy = cstr(start_year) + else: + fy = cstr(start_year) + '-' + cstr(start_year + 1) + return fy diff --git a/erpnext/setup/setup_wizard/install_fixtures.py b/erpnext/setup/setup_wizard/operations/install_fixtures.py similarity index 99% rename from erpnext/setup/setup_wizard/install_fixtures.py rename to erpnext/setup/setup_wizard/operations/install_fixtures.py index 68a157855ebd..dce3c288b851 100644 --- a/erpnext/setup/setup_wizard/install_fixtures.py +++ b/erpnext/setup/setup_wizard/operations/install_fixtures.py @@ -248,7 +248,7 @@ def install(country=None): ] - from erpnext.setup.setup_wizard.industry_type import get_industry_types + from erpnext.setup.setup_wizard.data.industry_type import get_industry_types records += [{"doctype":"Industry Type", "industry": d} for d in get_industry_types()] # records += [{"doctype":"Operation", "operation": d} for d in get_operations()] diff --git a/erpnext/setup/setup_wizard/sample_data.py b/erpnext/setup/setup_wizard/operations/sample_data.py similarity index 100% rename from erpnext/setup/setup_wizard/sample_data.py rename to erpnext/setup/setup_wizard/operations/sample_data.py diff --git a/erpnext/setup/setup_wizard/operations/taxes_setup.py b/erpnext/setup/setup_wizard/operations/taxes_setup.py new file mode 100644 index 000000000000..ee225d3e086d --- /dev/null +++ b/erpnext/setup/setup_wizard/operations/taxes_setup.py @@ -0,0 +1,95 @@ +# 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, copy, os, json +from frappe.utils import flt +from erpnext.accounts.doctype.account.account import RootNotEditable + +def create_sales_tax(args): + country_wise_tax = get_country_wise_tax(args.get("country")) + if country_wise_tax and len(country_wise_tax) > 0: + for sales_tax, tax_data in country_wise_tax.items(): + make_tax_account_and_template( + args.get("company_name"), + tax_data.get('account_name'), + tax_data.get('tax_rate'), sales_tax) + +def make_tax_account_and_template(company, account_name, tax_rate, template_name=None): + try: + if not isinstance(account_name, (list, tuple)): + account_name = [account_name] + tax_rate = [tax_rate] + + accounts = [] + for i, name in enumerate(account_name): + tax_account = make_tax_account(company, account_name[i], tax_rate[i]) + if tax_account: + accounts.append(tax_account) + + if accounts: + make_sales_and_purchase_tax_templates(accounts, template_name) + except frappe.NameError: + pass + except RootNotEditable: + pass + +def make_tax_account(company, account_name, tax_rate): + tax_group = get_tax_account_group(company) + if tax_group: + return frappe.get_doc({ + "doctype":"Account", + "company": company, + "parent_account": tax_group, + "account_name": account_name, + "is_group": 0, + "report_type": "Balance Sheet", + "root_type": "Liability", + "account_type": "Tax", + "tax_rate": flt(tax_rate) if tax_rate else None + }).insert(ignore_permissions=True) + +def make_sales_and_purchase_tax_templates(accounts, template_name=None): + if not template_name: + template_name = accounts[0].name + + sales_tax_template = { + "doctype": "Sales Taxes and Charges Template", + "title": template_name, + "company": accounts[0].company, + 'taxes': [] + } + + for account in accounts: + sales_tax_template['taxes'].append({ + "category": "Valuation and Total", + "charge_type": "On Net Total", + "account_head": account.name, + "description": "{0} @ {1}".format(account.account_name, account.tax_rate), + "rate": account.tax_rate + }) + # Sales + frappe.get_doc(copy.deepcopy(sales_tax_template)).insert(ignore_permissions=True) + + # Purchase + purchase_tax_template = copy.deepcopy(sales_tax_template) + purchase_tax_template["doctype"] = "Purchase Taxes and Charges Template" + + doc = frappe.get_doc(purchase_tax_template) + doc.insert(ignore_permissions=True) + +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 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 \ No newline at end of file diff --git a/erpnext/setup/setup_wizard/setup_wizard.py b/erpnext/setup/setup_wizard/setup_wizard.py index e861a96ee2e3..2c5f7e845634 100644 --- a/erpnext/setup/setup_wizard/setup_wizard.py +++ b/erpnext/setup/setup_wizard/setup_wizard.py @@ -2,393 +2,139 @@ # License: GNU General Public License v3. See license.txt from __future__ import unicode_literals -import frappe, copy -import os -import json -from frappe.utils import cstr, flt, getdate +import frappe from frappe import _ -from frappe.utils.file_manager import save_file -from .default_website import website_maker -import install_fixtures -from .sample_data import make_sample_data -from erpnext.accounts.doctype.account.account import RootNotEditable -from frappe.core.doctype.communication.comment import add_info_comment -from erpnext.setup.doctype.company.company import install_country_fixtures +from operations import install_fixtures, taxes_setup, defaults_setup, company_setup, sample_data -def setup_complete(args=None): +def get_setup_stages(args=None): if frappe.db.sql("select name from tabCompany"): - frappe.throw(_("Setup Already Complete!!")) + stages = [ + { + 'status': _('Wrapping up'), + 'fail_msg': _('Failed to login'), + 'tasks': [ + { + 'fn': fin, + 'args': args, + 'fail_msg': _("Failed to login") + } + ] + } + ] + else: + stages = [ + { + 'status': _('Installing presets'), + 'fail_msg': _('Failed to install presets'), + 'tasks': [ + { + 'fn': stage_fixtures, + 'args': args, + 'fail_msg': _("Failed to install presets") + } + ] + }, + { + 'status': _('Setting up company and taxes'), + 'fail_msg': _('Failed to setup company'), + 'tasks': [ + { + 'fn': setup_company, + 'args': args, + 'fail_msg': _("Failed to setup company") + }, + { + 'fn': setup_taxes, + 'args': args, + 'fail_msg': _("Failed to setup taxes") + } + ] + }, + { + 'status': _('Setting defaults'), + 'fail_msg': 'Failed to set defaults', + 'tasks': [ + { + 'fn': stage_three, + 'args': args, + 'fail_msg': _("Failed to set defaults") + } + ] + }, + { + 'status': _('Making website'), + 'fail_msg': _('Failed to create website'), + 'tasks': [ + { + 'fn': stage_four, + 'args': args, + 'fail_msg': _("Failed to create website") + } + ] + }, + { + 'status': _('Wrapping up'), + 'fail_msg': _('Failed to login'), + 'tasks': [ + { + 'fn': fin, + 'args': args, + 'fail_msg': _("Failed to login") + } + ] + } + ] + + return stages +def setup_complete(args=None): + stage_fixtures(args) + setup_company(args) + setup_taxes(args) + stage_three(args) + stage_four(args) + fin(args) + +def stage_fixtures(args): install_fixtures.install(args.get("country")) - create_price_lists(args) - create_fiscal_year_and_company(args) - create_sales_tax(args) - create_employee_for_self(args) - set_defaults(args) - create_territories() - create_feed_and_todo() - create_email_digest() - create_letter_head(args) - set_no_copy_fields_in_variant_settings() - - if args.get('setup_website'): - website_maker(args) +def setup_company(args): + defaults_setup.create_price_lists(args) + company_setup.create_fiscal_year_and_company(args) + company_setup.enable_shopping_cart(args) + company_setup.create_bank_account(args) - create_logo(args) +def setup_taxes(args): + taxes_setup.create_sales_tax(args) - frappe.local.message_log = [] +def stage_three(args): + defaults_setup.create_employee_for_self(args) + defaults_setup.set_default_settings(args) + defaults_setup.create_territories() + defaults_setup.create_feed_and_todo() + defaults_setup.set_no_copy_fields_in_variant_settings() - domains = args.get('domains') - domain_settings = frappe.get_single('Domain Settings') - domain_settings.set_active_domains(domains) +def stage_four(args): + company_setup.create_website(args) + company_setup.create_email_digest() + company_setup.create_logo(args) - frappe.db.commit() +def fin(args): + frappe.local.message_log = [] login_as_first_user(args) - frappe.db.commit() - frappe.clear_cache() + make_sample_data(args.get('domains')) +def make_sample_data(domains): try: - make_sample_data(domains) - frappe.clear_cache() + sample_data.make_sample_data(domains) except: # clear message if frappe.message_log: frappe.message_log.pop() - pass -def create_fiscal_year_and_company(args): - if (args.get('fy_start_date')): - curr_fiscal_year = get_fy_details(args.get('fy_start_date'), args.get('fy_end_date')) - frappe.get_doc({ - "doctype":"Fiscal Year", - 'year': curr_fiscal_year, - 'year_start_date': args.get('fy_start_date'), - 'year_end_date': args.get('fy_end_date'), - }).insert() - args["curr_fiscal_year"] = curr_fiscal_year - - # Company - if (args.get('company_name')): - frappe.get_doc({ - "doctype":"Company", - 'company_name':args.get('company_name'), - 'enable_perpetual_inventory': 1, - 'abbr':args.get('company_abbr'), - 'default_currency':args.get('currency'), - 'country': args.get('country'), - 'create_chart_of_accounts_based_on': 'Standard Template', - 'chart_of_accounts': args.get('chart_of_accounts'), - 'domain': args.get('domains')[0] - }).insert() - - #Enable shopping cart - enable_shopping_cart(args) - - # Bank Account - create_bank_account(args) - -def enable_shopping_cart(args): - frappe.get_doc({ - "doctype": "Shopping Cart Settings", - "enabled": 1, - 'company': args.get('company_name') , - 'price_list': frappe.db.get_value("Price List", {"selling": 1}), - 'default_customer_group': _("Individual"), - 'quotation_series': "QTN-", - }).insert() - -def create_bank_account(args): - if args.get("bank_account"): - company_name = args.get('company_name') - bank_account_group = frappe.db.get_value("Account", - {"account_type": "Bank", "is_group": 1, "root_type": "Asset", - "company": company_name}) - if bank_account_group: - bank_account = frappe.get_doc({ - "doctype": "Account", - 'account_name': args.get("bank_account"), - 'parent_account': bank_account_group, - 'is_group':0, - 'company': company_name, - "account_type": "Bank", - }) - try: - return bank_account.insert() - except RootNotEditable: - frappe.throw(_("Bank account cannot be named as {0}").format(args.get("bank_account"))) - except frappe.DuplicateEntryError: - # bank account same as a CoA entry - pass - -def create_price_lists(args): - for pl_type, pl_name in (("Selling", _("Standard Selling")), ("Buying", _("Standard Buying"))): - frappe.get_doc({ - "doctype": "Price List", - "price_list_name": pl_name, - "enabled": 1, - "buying": 1 if pl_type == "Buying" else 0, - "selling": 1 if pl_type == "Selling" else 0, - "currency": args["currency"] - }).insert() - -def set_defaults(args): - # enable default currency - frappe.db.set_value("Currency", args.get("currency"), "enabled", 1) - - global_defaults = frappe.get_doc("Global Defaults", "Global Defaults") - global_defaults.update({ - 'current_fiscal_year': args.get('curr_fiscal_year'), - 'default_currency': args.get('currency'), - 'default_company':args.get('company_name') , - "country": args.get("country"), - }) - - global_defaults.save() - - system_settings = frappe.get_doc("System Settings") - system_settings.email_footer_address = args.get("company") - system_settings.save() - - stock_settings = frappe.get_doc("Stock Settings") - stock_settings.item_naming_by = "Item Code" - stock_settings.valuation_method = "FIFO" - stock_settings.default_warehouse = frappe.db.get_value('Warehouse', {'warehouse_name': _('Stores')}) - stock_settings.stock_uom = _("Nos") - stock_settings.auto_indent = 1 - stock_settings.auto_insert_price_list_rate_if_missing = 1 - stock_settings.automatically_set_serial_nos_based_on_fifo = 1 - stock_settings.save() - - selling_settings = frappe.get_doc("Selling Settings") - selling_settings.cust_master_name = "Customer Name" - selling_settings.so_required = "No" - selling_settings.dn_required = "No" - selling_settings.allow_multiple_items = 1 - selling_settings.save() - - buying_settings = frappe.get_doc("Buying Settings") - buying_settings.supp_master_name = "Supplier Name" - buying_settings.po_required = "No" - buying_settings.pr_required = "No" - buying_settings.maintain_same_rate = 1 - buying_settings.allow_multiple_items = 1 - buying_settings.save() - - notification_control = frappe.get_doc("Notification Control") - notification_control.quotation = 1 - notification_control.sales_invoice = 1 - notification_control.purchase_order = 1 - notification_control.save() - - hr_settings = frappe.get_doc("HR Settings") - hr_settings.emp_created_by = "Naming Series" - hr_settings.save() - -def create_feed_and_todo(): - """update Activity feed and create todo for creation of item, customer, vendor""" - add_info_comment(**{ - "subject": _("ERPNext Setup Complete!") - }) - -def create_email_digest(): - from frappe.utils.user import get_system_managers - system_managers = get_system_managers(only_name=True) - if not system_managers: - return - - companies = frappe.db.sql_list("select name FROM `tabCompany`") - for company in companies: - if not frappe.db.exists("Email Digest", "Default Weekly Digest - " + company): - edigest = frappe.get_doc({ - "doctype": "Email Digest", - "name": "Default Weekly Digest - " + company, - "company": company, - "frequency": "Weekly", - "recipient_list": "\n".join(system_managers) - }) - - for df in edigest.meta.get("fields", {"fieldtype": "Check"}): - if df.fieldname != "scheduler_errors": - edigest.set(df.fieldname, 1) - - edigest.insert() - - # scheduler errors digest - if companies: - edigest = frappe.new_doc("Email Digest") - edigest.update({ - "name": "Scheduler Errors", - "company": companies[0], - "frequency": "Daily", - "recipient_list": "\n".join(system_managers), - "scheduler_errors": 1, - "enabled": 1 - }) - edigest.insert() - -def get_fy_details(fy_start_date, fy_end_date): - start_year = getdate(fy_start_date).year - if start_year == getdate(fy_end_date).year: - fy = cstr(start_year) - else: - fy = cstr(start_year) + '-' + cstr(start_year + 1) - return fy - -def create_sales_tax(args): - country_wise_tax = get_country_wise_tax(args.get("country")) - if country_wise_tax and len(country_wise_tax) > 0: - for sales_tax, tax_data in country_wise_tax.items(): - make_tax_account_and_template( - args.get("company_name"), - tax_data.get('account_name'), - tax_data.get('tax_rate'), sales_tax) - -# 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)): - account_name = [account_name] - tax_rate = [tax_rate] - - accounts = [] - for i, name in enumerate(account_name): - tax_account = make_tax_account(company, account_name[i], tax_rate[i]) - if tax_account: - accounts.append(tax_account) - - if accounts: - make_sales_and_purchase_tax_templates(accounts, template_name) - except frappe.NameError: - pass - except RootNotEditable: - pass - -def make_tax_account(company, account_name, tax_rate): - tax_group = get_tax_account_group(company) - if tax_group: - return frappe.get_doc({ - "doctype":"Account", - "company": company, - "parent_account": tax_group, - "account_name": account_name, - "is_group": 0, - "report_type": "Balance Sheet", - "root_type": "Liability", - "account_type": "Tax", - "tax_rate": flt(tax_rate) if tax_rate else None - }).insert(ignore_permissions=True) - -def make_sales_and_purchase_tax_templates(accounts, template_name=None): - if not template_name: - template_name = accounts[0].name - - sales_tax_template = { - "doctype": "Sales Taxes and Charges Template", - "title": template_name, - "company": accounts[0].company, - 'taxes': [] - } - - for account in accounts: - sales_tax_template['taxes'].append({ - "category": "Valuation and Total", - "charge_type": "On Net Total", - "account_head": account.name, - "description": "{0} @ {1}".format(account.account_name, account.tax_rate), - "rate": account.tax_rate - }) - # Sales - frappe.get_doc(copy.deepcopy(sales_tax_template)).insert(ignore_permissions=True) - - # Purchase - purchase_tax_template = copy.deepcopy(sales_tax_template) - purchase_tax_template["doctype"] = "Purchase Taxes and Charges Template" - - doc = frappe.get_doc(purchase_tax_template) - doc.insert(ignore_permissions=True) - -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 - -# Tax utils end - -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_letter_head(args): - if args.get("attach_letterhead"): - frappe.get_doc({ - "doctype":"Letter Head", - "letter_head_name": _("Standard"), - "is_default": 1 - }).insert() - - attach_letterhead = args.get("attach_letterhead").split(",") - if len(attach_letterhead)==3: - filename, filetype, content = attach_letterhead - fileurl = save_file(filename, content, "Letter Head", _("Standard"), decode=True).file_url - frappe.db.set_value("Letter Head", _("Standard"), "content", "" % fileurl) - -def set_no_copy_fields_in_variant_settings(): - # set no copy fields of an item doctype to item variant settings - doc = frappe.get_doc('Item Variant Settings') - doc.set_default_fields() - doc.save() - -def create_logo(args): - if args.get("attach_logo"): - attach_logo = args.get("attach_logo").split(",") - if len(attach_logo)==3: - filename, filetype, content = attach_logo - fileurl = save_file(filename, content, "Website Settings", "Website Settings", - decode=True).file_url - frappe.db.set_value("Website Settings", "Website Settings", "brand_html", - " {1}".format(fileurl, args.get("company_name") )) - -def create_territories(): - """create two default territories, one for home country and one named Rest of the World""" - from frappe.utils.nestedset import get_root_of - country = frappe.db.get_default("country") - root_territory = get_root_of("Territory") - for name in (country, _("Rest Of The World")): - if name and not frappe.db.exists("Territory", name): - frappe.get_doc({ - "doctype": "Territory", - "territory_name": name.replace("'", ""), - "parent_territory": root_territory, - "is_group": "No" - }).insert() - def login_as_first_user(args): if args.get("email") and hasattr(frappe.local, "login_manager"): frappe.local.login_manager.login_as(args.get("email")) - -def create_employee_for_self(args): - if frappe.session.user == 'Administrator': - return - - # create employee for self - emp = frappe.get_doc({ - "doctype": "Employee", - "employee_name": " ".join(filter(None, [args.get("first_name"), args.get("last_name")])), - "user_id": frappe.session.user, - "status": "Active", - "company": args.get("company_name") - }) - emp.flags.ignore_mandatory = True - emp.insert(ignore_permissions = True) -