From ee4b8bee338b9b582f59b28ad68a67cd970ff962 Mon Sep 17 00:00:00 2001 From: Rushabh Mehta Date: Wed, 31 Dec 2014 15:01:48 +0530 Subject: [PATCH] Revert "[patches] removed 4.0 patches" This reverts commit 6f7cba8d730bcc3a7ac6d7102cce0a8369419956. --- erpnext/patches/v4_0/__init__.py | 0 .../patches/v4_0/apply_user_permissions.py | 51 ++++++++ erpnext/patches/v4_0/countrywise_coa.py | 29 +++++ ...custom_fields_for_india_specific_fields.py | 63 ++++++++++ .../v4_0/create_price_list_if_missing.py | 35 ++++++ .../v4_0/customer_discount_to_pricing_rule.py | 33 ++++++ erpnext/patches/v4_0/fields_to_be_renamed.py | 109 ++++++++++++++++++ erpnext/patches/v4_0/fix_address_template.py | 12 ++ .../patches/v4_0/fix_case_of_hr_module_def.py | 13 +++ erpnext/patches/v4_0/fix_contact_address.py | 12 ++ erpnext/patches/v4_0/fix_employee_user_id.py | 23 ++++ .../global_defaults_to_system_settings.py | 39 +++++++ erpnext/patches/v4_0/import_country_codes.py | 13 +++ .../v4_0/map_charge_to_taxes_and_charges.py | 16 +++ .../move_warehouse_user_to_restrictions.py | 13 +++ erpnext/patches/v4_0/new_address_template.py | 13 +++ .../patches/v4_0/reload_sales_print_format.py | 8 ++ .../remove_employee_role_if_no_employee.py | 18 +++ .../patches/v4_0/remove_module_home_pages.py | 10 ++ .../patches/v4_0/rename_sitemap_to_route.py | 16 +++ .../v4_0/reset_permissions_for_masters.py | 20 ++++ .../patches/v4_0/save_default_letterhead.py | 13 +++ .../v4_0/set_naming_series_property_setter.py | 98 ++++++++++++++++ .../set_pricing_rule_for_buying_or_selling.py | 13 +++ erpnext/patches/v4_0/split_email_settings.py | 67 +++++++++++ .../patches/v4_0/update_account_root_type.py | 34 ++++++ ...custom_print_formats_for_renamed_fields.py | 36 ++++++ ...to_sales_person_in_maintenance_schedule.py | 12 ++ ...harges_in_custom_purchase_print_formats.py | 12 ++ .../v4_0/update_tax_amount_after_discount.py | 20 ++++ .../patches/v4_0/update_user_properties.py | 51 ++++++++ .../v4_0/update_users_report_view_settings.py | 12 ++ erpnext/patches/v4_0/validate_v3_patch.py | 11 ++ erpnext/patches/v4_1/__init__.py | 0 .../v4_1/fix_delivery_and_billing_status.py | 12 ++ erpnext/patches/v4_1/fix_jv_remarks.py | 21 ++++ .../v4_1/fix_sales_order_delivered_status.py | 15 +++ .../patches/v4_1/set_outgoing_email_footer.py | 12 ++ erpnext/patches/v4_2/__init__.py | 0 .../patches/v4_2/add_currency_turkish_lira.py | 11 ++ erpnext/patches/v4_2/default_website_style.py | 10 ++ .../patches/v4_2/delete_old_print_formats.py | 23 ++++ .../patches/v4_2/fix_account_master_type.py | 12 ++ .../fix_gl_entries_for_stock_transactions.py | 52 +++++++++ erpnext/patches/v4_2/party_model.py | 97 ++++++++++++++++ erpnext/patches/v4_2/recalculate_bom_cost.py | 16 +++ .../v4_2/repost_stock_reconciliation.py | 31 +++++ .../v4_2/seprate_manufacture_and_repack.py | 9 ++ erpnext/patches/v4_2/set_company_country.py | 15 +++ erpnext/patches/v4_2/toggle_rounded_total.py | 9 ++ .../patches/v4_2/update_project_milestones.py | 8 ++ .../v4_2/update_requested_and_ordered_qty.py | 24 ++++ .../update_sales_order_invoice_field_name.py | 6 + 53 files changed, 1308 insertions(+) create mode 100644 erpnext/patches/v4_0/__init__.py create mode 100644 erpnext/patches/v4_0/apply_user_permissions.py create mode 100644 erpnext/patches/v4_0/countrywise_coa.py create mode 100644 erpnext/patches/v4_0/create_custom_fields_for_india_specific_fields.py create mode 100644 erpnext/patches/v4_0/create_price_list_if_missing.py create mode 100644 erpnext/patches/v4_0/customer_discount_to_pricing_rule.py create mode 100644 erpnext/patches/v4_0/fields_to_be_renamed.py create mode 100644 erpnext/patches/v4_0/fix_address_template.py create mode 100644 erpnext/patches/v4_0/fix_case_of_hr_module_def.py create mode 100644 erpnext/patches/v4_0/fix_contact_address.py create mode 100644 erpnext/patches/v4_0/fix_employee_user_id.py create mode 100644 erpnext/patches/v4_0/global_defaults_to_system_settings.py create mode 100644 erpnext/patches/v4_0/import_country_codes.py create mode 100644 erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py create mode 100644 erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py create mode 100644 erpnext/patches/v4_0/new_address_template.py create mode 100644 erpnext/patches/v4_0/reload_sales_print_format.py create mode 100644 erpnext/patches/v4_0/remove_employee_role_if_no_employee.py create mode 100644 erpnext/patches/v4_0/remove_module_home_pages.py create mode 100644 erpnext/patches/v4_0/rename_sitemap_to_route.py create mode 100644 erpnext/patches/v4_0/reset_permissions_for_masters.py create mode 100644 erpnext/patches/v4_0/save_default_letterhead.py create mode 100644 erpnext/patches/v4_0/set_naming_series_property_setter.py create mode 100644 erpnext/patches/v4_0/set_pricing_rule_for_buying_or_selling.py create mode 100644 erpnext/patches/v4_0/split_email_settings.py create mode 100644 erpnext/patches/v4_0/update_account_root_type.py create mode 100644 erpnext/patches/v4_0/update_custom_print_formats_for_renamed_fields.py create mode 100644 erpnext/patches/v4_0/update_incharge_name_to_sales_person_in_maintenance_schedule.py create mode 100644 erpnext/patches/v4_0/update_other_charges_in_custom_purchase_print_formats.py create mode 100644 erpnext/patches/v4_0/update_tax_amount_after_discount.py create mode 100644 erpnext/patches/v4_0/update_user_properties.py create mode 100644 erpnext/patches/v4_0/update_users_report_view_settings.py create mode 100644 erpnext/patches/v4_0/validate_v3_patch.py create mode 100644 erpnext/patches/v4_1/__init__.py create mode 100644 erpnext/patches/v4_1/fix_delivery_and_billing_status.py create mode 100644 erpnext/patches/v4_1/fix_jv_remarks.py create mode 100644 erpnext/patches/v4_1/fix_sales_order_delivered_status.py create mode 100644 erpnext/patches/v4_1/set_outgoing_email_footer.py create mode 100644 erpnext/patches/v4_2/__init__.py create mode 100644 erpnext/patches/v4_2/add_currency_turkish_lira.py create mode 100644 erpnext/patches/v4_2/default_website_style.py create mode 100644 erpnext/patches/v4_2/delete_old_print_formats.py create mode 100644 erpnext/patches/v4_2/fix_account_master_type.py create mode 100644 erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py create mode 100644 erpnext/patches/v4_2/party_model.py create mode 100644 erpnext/patches/v4_2/recalculate_bom_cost.py create mode 100644 erpnext/patches/v4_2/repost_stock_reconciliation.py create mode 100644 erpnext/patches/v4_2/seprate_manufacture_and_repack.py create mode 100644 erpnext/patches/v4_2/set_company_country.py create mode 100644 erpnext/patches/v4_2/toggle_rounded_total.py create mode 100644 erpnext/patches/v4_2/update_project_milestones.py create mode 100644 erpnext/patches/v4_2/update_requested_and_ordered_qty.py create mode 100644 erpnext/patches/v4_2/update_sales_order_invoice_field_name.py diff --git a/erpnext/patches/v4_0/__init__.py b/erpnext/patches/v4_0/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/patches/v4_0/apply_user_permissions.py b/erpnext/patches/v4_0/apply_user_permissions.py new file mode 100644 index 00000000000..7dae02f7855 --- /dev/null +++ b/erpnext/patches/v4_0/apply_user_permissions.py @@ -0,0 +1,51 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from erpnext.hr.doctype.employee.employee import EmployeeUserDisabledError + +def execute(): + update_hr_permissions() + update_permissions() + remove_duplicate_user_permissions() + frappe.clear_cache() + +def update_hr_permissions(): + from frappe.core.page.user_permissions import user_permissions + + # add set user permissions rights to HR Manager + frappe.db.sql("""update `tabDocPerm` set `set_user_permissions`=1 where parent in ('Employee', 'Leave Application') + and role='HR Manager' and permlevel=0 and `read`=1""") + + # apply user permissions on Employee and Leave Application + frappe.db.sql("""update `tabDocPerm` set `apply_user_permissions`=1 where parent in ('Employee', 'Leave Application') + and role in ('Employee', 'Leave Approver') and permlevel=0 and `read`=1""") + + frappe.clear_cache() + + # save employees to run on_update events + for employee in frappe.db.sql_list("""select name from `tabEmployee` where docstatus < 2"""): + try: + emp = frappe.get_doc("Employee", employee) + emp.ignore_mandatory = True + emp.save() + except EmployeeUserDisabledError: + pass + +def update_permissions(): + # clear match conditions other than owner + frappe.db.sql("""update tabDocPerm set `match`='' + where ifnull(`match`,'') not in ('', 'owner')""") + +def remove_duplicate_user_permissions(): + # remove duplicate user_permissions (if they exist) + for d in frappe.db.sql("""select parent, defkey, defvalue, + count(*) as cnt from tabDefaultValue + where parent not in ('__global', '__default') + group by parent, defkey, defvalue""", as_dict=1): + if d.cnt > 1: + # order by parenttype so that user permission does not get removed! + frappe.db.sql("""delete from tabDefaultValue where `parent`=%s and `defkey`=%s and + `defvalue`=%s order by parenttype limit %s""", (d.parent, d.defkey, d.defvalue, d.cnt-1)) + diff --git a/erpnext/patches/v4_0/countrywise_coa.py b/erpnext/patches/v4_0/countrywise_coa.py new file mode 100644 index 00000000000..f11bdb7dbd4 --- /dev/null +++ b/erpnext/patches/v4_0/countrywise_coa.py @@ -0,0 +1,29 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc("setup", 'doctype', "company") + frappe.reload_doc("accounts", 'doctype', "account") + + frappe.db.sql("""update tabAccount set account_type='Cash' + where account_type='Bank or Cash' and account_name in ('Cash', 'Cash In Hand')""") + + frappe.db.sql("""update tabAccount set account_type='Stock' + where account_name = 'Stock Assets'""") + + ac_types = {"Fixed Asset Account": "Fixed Asset", "Bank or Cash": "Bank"} + for old, new in ac_types.items(): + frappe.db.sql("""update tabAccount set account_type=%s + where account_type=%s""", (new, old)) + + try: + frappe.db.sql("""update `tabAccount` set report_type = + if(is_pl_account='Yes', 'Profit and Loss', 'Balance Sheet')""") + + frappe.db.sql("""update `tabAccount` set balance_must_be=debit_or_credit + where ifnull(allow_negative_balance, 0) = 0""") + except: + pass diff --git a/erpnext/patches/v4_0/create_custom_fields_for_india_specific_fields.py b/erpnext/patches/v4_0/create_custom_fields_for_india_specific_fields.py new file mode 100644 index 00000000000..5bca5e69628 --- /dev/null +++ b/erpnext/patches/v4_0/create_custom_fields_for_india_specific_fields.py @@ -0,0 +1,63 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.custom.doctype.custom_field.custom_field import create_custom_field_if_values_exist + +def execute(): + frappe.reload_doc("stock", "doctype", "purchase_receipt") + frappe.reload_doc("hr", "doctype", "employee") + frappe.reload_doc("hr", "doctype", "salary_slip") + + india_specific_fields = { + "Purchase Receipt": [{ + "label": "Supplier Shipment No", + "fieldname": "challan_no", + "fieldtype": "Data", + "insert_after": "is_subcontracted" + }, { + "label": "Supplier Shipment Date", + "fieldname": "challan_date", + "fieldtype": "Date", + "insert_after": "is_subcontracted" + }], + "Employee": [{ + "label": "PAN Number", + "fieldname": "pan_number", + "fieldtype": "Data", + "insert_after": "company_email" + }, { + "label": "Gratuity LIC Id", + "fieldname": "gratuity_lic_id", + "fieldtype": "Data", + "insert_after": "company_email" + }, { + "label": "Esic Card No", + "fieldname": "esic_card_no", + "fieldtype": "Data", + "insert_after": "bank_ac_no" + }, { + "label": "PF Number", + "fieldname": "pf_number", + "fieldtype": "Data", + "insert_after": "bank_ac_no" + }], + "Salary Slip": [{ + "label": "Esic No", + "fieldname": "esic_no", + "fieldtype": "Data", + "insert_after": "letter_head", + "permlevel": 1 + }, { + "label": "PF Number", + "fieldname": "pf_no", + "fieldtype": "Data", + "insert_after": "letter_head", + "permlevel": 1 + }] + } + + for dt, docfields in india_specific_fields.items(): + for df in docfields: + create_custom_field_if_values_exist(dt, df) diff --git a/erpnext/patches/v4_0/create_price_list_if_missing.py b/erpnext/patches/v4_0/create_price_list_if_missing.py new file mode 100644 index 00000000000..f65b7cb571a --- /dev/null +++ b/erpnext/patches/v4_0/create_price_list_if_missing.py @@ -0,0 +1,35 @@ +# Copyright (c) 2013, Web Notes 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.nestedset import get_root_of + +def execute(): + # setup not complete + if not frappe.db.sql("""select name from tabCompany limit 1"""): + return + + if "shopping_cart" in frappe.get_installed_apps(): + frappe.reload_doc("shopping_cart", "doctype", "shopping_cart_settings") + + if not frappe.db.sql("select name from `tabPrice List` where buying=1"): + create_price_list(_("Standard Buying"), buying=1) + + if not frappe.db.sql("select name from `tabPrice List` where selling=1"): + create_price_list(_("Standard Selling"), selling=1) + +def create_price_list(pl_name, buying=0, selling=0): + price_list = frappe.get_doc({ + "doctype": "Price List", + "price_list_name": pl_name, + "enabled": 1, + "buying": buying, + "selling": selling, + "currency": frappe.db.get_default("currency"), + "valid_for_territories": [{ + "territory": get_root_of("Territory") + }] + }) + price_list.insert() diff --git a/erpnext/patches/v4_0/customer_discount_to_pricing_rule.py b/erpnext/patches/v4_0/customer_discount_to_pricing_rule.py new file mode 100644 index 00000000000..bd27174a0e8 --- /dev/null +++ b/erpnext/patches/v4_0/customer_discount_to_pricing_rule.py @@ -0,0 +1,33 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils.nestedset import get_root_of + +def execute(): + frappe.reload_doc("accounts", "doctype", "pricing_rule") + + frappe.db.auto_commit_on_many_writes = True + + default_item_group = get_root_of("Item Group") + + for d in frappe.db.sql("""select * from `tabCustomer Discount` + where ifnull(parent, '') != ''""", as_dict=1): + if not d.discount: + continue + + frappe.get_doc({ + "doctype": "Pricing Rule", + "apply_on": "Item Group", + "item_group": d.item_group or default_item_group, + "applicable_for": "Customer", + "customer": d.parent, + "price_or_discount": "Discount Percentage", + "discount_percentage": d.discount, + "selling": 1 + }).insert() + + frappe.db.auto_commit_on_many_writes = False + + frappe.delete_doc("DocType", "Customer Discount") diff --git a/erpnext/patches/v4_0/fields_to_be_renamed.py b/erpnext/patches/v4_0/fields_to_be_renamed.py new file mode 100644 index 00000000000..642a0b49aae --- /dev/null +++ b/erpnext/patches/v4_0/fields_to_be_renamed.py @@ -0,0 +1,109 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.model import rename_field +from frappe.modules import scrub, get_doctype_module + +rename_map = { + "Quotation Item": [ + ["ref_rate", "price_list_rate"], + ["base_ref_rate", "base_price_list_rate"], + ["adj_rate", "discount_percentage"], + ["export_rate", "rate"], + ["basic_rate", "base_rate"], + ["amount", "base_amount"], + ["export_amount", "amount"] + ], + + "Sales Order Item": [ + ["ref_rate", "price_list_rate"], + ["base_ref_rate", "base_price_list_rate"], + ["adj_rate", "discount_percentage"], + ["export_rate", "rate"], + ["basic_rate", "base_rate"], + ["amount", "base_amount"], + ["export_amount", "amount"], + ["reserved_warehouse", "warehouse"] + ], + + "Delivery Note Item": [ + ["ref_rate", "price_list_rate"], + ["base_ref_rate", "base_price_list_rate"], + ["adj_rate", "discount_percentage"], + ["export_rate", "rate"], + ["basic_rate", "base_rate"], + ["amount", "base_amount"], + ["export_amount", "amount"] + ], + + "Sales Invoice Item": [ + ["ref_rate", "price_list_rate"], + ["base_ref_rate", "base_price_list_rate"], + ["adj_rate", "discount_percentage"], + ["export_rate", "rate"], + ["basic_rate", "base_rate"], + ["amount", "base_amount"], + ["export_amount", "amount"] + ], + + "Supplier Quotation Item": [ + ["import_ref_rate", "price_list_rate"], + ["purchase_ref_rate", "base_price_list_rate"], + ["discount_rate", "discount_percentage"], + ["import_rate", "rate"], + ["purchase_rate", "base_rate"], + ["amount", "base_amount"], + ["import_amount", "amount"] + ], + + "Purchase Order Item": [ + ["import_ref_rate", "price_list_rate"], + ["purchase_ref_rate", "base_price_list_rate"], + ["discount_rate", "discount_percentage"], + ["import_rate", "rate"], + ["purchase_rate", "base_rate"], + ["amount", "base_amount"], + ["import_amount", "amount"] + ], + + "Purchase Receipt Item": [ + ["import_ref_rate", "price_list_rate"], + ["purchase_ref_rate", "base_price_list_rate"], + ["discount_rate", "discount_percentage"], + ["import_rate", "rate"], + ["purchase_rate", "base_rate"], + ["amount", "base_amount"], + ["import_amount", "amount"] + ], + + "Purchase Invoice Item": [ + ["import_ref_rate", "price_list_rate"], + ["purchase_ref_rate", "base_price_list_rate"], + ["discount_rate", "discount_percentage"], + ["import_rate", "rate"], + ["rate", "base_rate"], + ["amount", "base_amount"], + ["import_amount", "amount"], + ["expense_head", "expense_account"] + ], + + "Item": [ + ["purchase_account", "expense_account"], + ["default_sales_cost_center", "selling_cost_center"], + ["cost_center", "buying_cost_center"], + ["default_income_account", "income_account"], + ], + "Item Price": [ + ["ref_rate", "price_list_rate"] + ] +} + +def execute(): + for dn in rename_map: + frappe.reload_doc(get_doctype_module(dn), "doctype", scrub(dn)) + + for dt, field_list in rename_map.items(): + for field in field_list: + rename_field(dt, field[0], field[1]) diff --git a/erpnext/patches/v4_0/fix_address_template.py b/erpnext/patches/v4_0/fix_address_template.py new file mode 100644 index 00000000000..5aed489775e --- /dev/null +++ b/erpnext/patches/v4_0/fix_address_template.py @@ -0,0 +1,12 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors + +from __future__ import unicode_literals +import frappe + +def execute(): + missing_line = """{{ address_line1 }}
""" + for name, template in frappe.db.sql("select name, template from `tabAddress Template`"): + if missing_line not in template: + d = frappe.get_doc("Address Template", name) + d.template = missing_line + d.template + d.save() diff --git a/erpnext/patches/v4_0/fix_case_of_hr_module_def.py b/erpnext/patches/v4_0/fix_case_of_hr_module_def.py new file mode 100644 index 00000000000..73b4e7f56c8 --- /dev/null +++ b/erpnext/patches/v4_0/fix_case_of_hr_module_def.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors + +from __future__ import unicode_literals +import frappe + +def execute(): + hr = frappe.db.get_value("Module Def", "HR") + if hr == "Hr": + frappe.rename_doc("Module Def", "Hr", "HR") + frappe.db.set_value("Module Def", "HR", "module_name", "HR") + + frappe.clear_cache() + frappe.setup_module_map() diff --git a/erpnext/patches/v4_0/fix_contact_address.py b/erpnext/patches/v4_0/fix_contact_address.py new file mode 100644 index 00000000000..91d1a0b0c6f --- /dev/null +++ b/erpnext/patches/v4_0/fix_contact_address.py @@ -0,0 +1,12 @@ +import frappe + +def execute(): + frappe.reload_doc("website", "doctype", "contact_us_settings") + address = frappe.db.get_value("Contact Us Settings", None, "address") + if address: + address = frappe.get_doc("Address", address) + contact = frappe.get_doc("Contact Us Settings", "Contact Us Settings") + for f in ("address_title", "address_line1", "address_line2", "city", "state", "country", "pincode"): + contact.set(f, address.get(f)) + + contact.save() \ No newline at end of file diff --git a/erpnext/patches/v4_0/fix_employee_user_id.py b/erpnext/patches/v4_0/fix_employee_user_id.py new file mode 100644 index 00000000000..d366fa44482 --- /dev/null +++ b/erpnext/patches/v4_0/fix_employee_user_id.py @@ -0,0 +1,23 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +import frappe +from frappe.utils import get_fullname + +def execute(): + for user_id in frappe.db.sql_list("""select distinct user_id from `tabEmployee` + where ifnull(user_id, '')!='' + group by user_id having count(name) > 1"""): + + fullname = get_fullname(user_id) + employee = frappe.db.get_value("Employee", {"employee_name": fullname, "user_id": user_id}) + + if employee: + frappe.db.sql("""update `tabEmployee` set user_id=null + where user_id=%s and name!=%s""", (user_id, employee)) + else: + count = frappe.db.sql("""select count(*) from `tabEmployee` where user_id=%s""", user_id)[0][0] + frappe.db.sql("""update `tabEmployee` set user_id=null + where user_id=%s limit %s""", (user_id, count - 1)) diff --git a/erpnext/patches/v4_0/global_defaults_to_system_settings.py b/erpnext/patches/v4_0/global_defaults_to_system_settings.py new file mode 100644 index 00000000000..57b21aea41b --- /dev/null +++ b/erpnext/patches/v4_0/global_defaults_to_system_settings.py @@ -0,0 +1,39 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals + +import frappe +from collections import Counter +from frappe.core.doctype.user.user import STANDARD_USERS + +def execute(): + frappe.reload_doc("core", "doctype", "system_settings") + system_settings = frappe.get_doc("System Settings") + + # set values from global_defauls + global_defaults = frappe.db.get_value("Global Defaults", None, + ["time_zone", "date_format", "number_format", "float_precision", "session_expiry"], as_dict=True) + + if global_defaults: + for key, val in global_defaults.items(): + if not system_settings.get(key): + system_settings.set(key, val) + + # language + if not system_settings.get("language"): + # find most common language + lang = frappe.db.sql_list("""select language from `tabUser` + where ifnull(language, '')!='' and language not like "Loading%%" and name not in ({standard_users})""".format( + standard_users=", ".join(["%s"]*len(STANDARD_USERS))), tuple(STANDARD_USERS)) + lang = Counter(lang).most_common(1) + lang = (len(lang) > 0) and lang[0][0] or "english" + + system_settings.language = lang + + system_settings.ignore_mandatory = True + system_settings.save() + + global_defaults = frappe.get_doc("Global Defaults") + global_defaults.ignore_mandatory = True + global_defaults.save() diff --git a/erpnext/patches/v4_0/import_country_codes.py b/erpnext/patches/v4_0/import_country_codes.py new file mode 100644 index 00000000000..e2e9f9d1f46 --- /dev/null +++ b/erpnext/patches/v4_0/import_country_codes.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# MIT License. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.geo.country_info import get_all +from erpnext.setup.install import import_country_and_currency + +def execute(): + frappe.reload_doc("setup", "doctype", "country") + import_country_and_currency() + for name, country in get_all().iteritems(): + frappe.set_value("Country", name, "code", country.get("code")) \ No newline at end of file diff --git a/erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py b/erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py new file mode 100644 index 00000000000..a8142451799 --- /dev/null +++ b/erpnext/patches/v4_0/map_charge_to_taxes_and_charges.py @@ -0,0 +1,16 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + # udpate sales cycle + for d in ['Sales Invoice', 'Sales Order', 'Quotation', 'Delivery Note']: + frappe.db.sql("""update `tab%s` set taxes_and_charges=charge""" % d) + + # udpate purchase cycle + for d in ['Purchase Invoice', 'Purchase Order', 'Supplier Quotation', 'Purchase Receipt']: + frappe.db.sql("""update `tab%s` set taxes_and_charges=purchase_other_charges""" % d) + + frappe.db.sql("""update `tabPurchase Taxes and Charges` set parentfield='other_charges'""") diff --git a/erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py b/erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py new file mode 100644 index 00000000000..35b3c8661df --- /dev/null +++ b/erpnext/patches/v4_0/move_warehouse_user_to_restrictions.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +import frappe.permissions + +def execute(): + for warehouse, user in frappe.db.sql("""select parent, user from `tabWarehouse User`"""): + frappe.permissions.add_user_permission("Warehouse", warehouse, user) + + frappe.delete_doc_if_exists("DocType", "Warehouse User") + frappe.reload_doc("stock", "doctype", "warehouse") diff --git a/erpnext/patches/v4_0/new_address_template.py b/erpnext/patches/v4_0/new_address_template.py new file mode 100644 index 00000000000..7a5dabc006f --- /dev/null +++ b/erpnext/patches/v4_0/new_address_template.py @@ -0,0 +1,13 @@ +import frappe + +def execute(): + frappe.reload_doc("utilities", "doctype", "address_template") + if not frappe.db.sql("select name from `tabAddress Template`"): + try: + d = frappe.new_doc("Address Template") + d.update({"country":frappe.db.get_default("country") or + frappe.db.get_value("Global Defaults", "Global Defaults", "country")}) + d.insert() + except: + print frappe.get_traceback() + diff --git a/erpnext/patches/v4_0/reload_sales_print_format.py b/erpnext/patches/v4_0/reload_sales_print_format.py new file mode 100644 index 00000000000..99184e36ef1 --- /dev/null +++ b/erpnext/patches/v4_0/reload_sales_print_format.py @@ -0,0 +1,8 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc('accounts', 'Print Format', 'POS Invoice') diff --git a/erpnext/patches/v4_0/remove_employee_role_if_no_employee.py b/erpnext/patches/v4_0/remove_employee_role_if_no_employee.py new file mode 100644 index 00000000000..c1f368949f5 --- /dev/null +++ b/erpnext/patches/v4_0/remove_employee_role_if_no_employee.py @@ -0,0 +1,18 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +import frappe.permissions + +def execute(): + for user in frappe.db.sql_list("select distinct parent from `tabUserRole` where role='Employee'"): + # if employee record does not exists, remove employee role! + if not frappe.db.get_value("Employee", {"user_id": user}): + try: + user = frappe.get_doc("User", user) + for role in user.get("user_roles", {"role": "Employee"}): + user.get("user_roles").remove(role) + user.save() + except frappe.DoesNotExistError: + pass diff --git a/erpnext/patches/v4_0/remove_module_home_pages.py b/erpnext/patches/v4_0/remove_module_home_pages.py new file mode 100644 index 00000000000..f7407a6c05f --- /dev/null +++ b/erpnext/patches/v4_0/remove_module_home_pages.py @@ -0,0 +1,10 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for page in ("accounts-home", "website-home", "support-home", "stock-home", "selling-home", "projects-home", + "manufacturing-home", "hr-home", "buying-home"): + frappe.delete_doc("Page", page) \ No newline at end of file diff --git a/erpnext/patches/v4_0/rename_sitemap_to_route.py b/erpnext/patches/v4_0/rename_sitemap_to_route.py new file mode 100644 index 00000000000..b933e364b40 --- /dev/null +++ b/erpnext/patches/v4_0/rename_sitemap_to_route.py @@ -0,0 +1,16 @@ +import frappe +import frappe.model + +def execute(): + frappe.reload_doc("setup", "doctype", "item_group") + frappe.reload_doc("stock", "doctype", "item") + frappe.reload_doc("setup", "doctype", "sales_partner") + + try: + frappe.model.rename_field("Item Group", "parent_website_sitemap", "parent_website_route") + frappe.model.rename_field("Item", "parent_website_sitemap", "parent_website_route") + frappe.model.rename_field("Sales Partner", "parent_website_sitemap", + "parent_website_route") + except Exception, e: + if e.args[0]!=1054: + raise \ No newline at end of file diff --git a/erpnext/patches/v4_0/reset_permissions_for_masters.py b/erpnext/patches/v4_0/reset_permissions_for_masters.py new file mode 100644 index 00000000000..b0bc1230b09 --- /dev/null +++ b/erpnext/patches/v4_0/reset_permissions_for_masters.py @@ -0,0 +1,20 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +from frappe.permissions import reset_perms + +def execute(): + for doctype in ("About Us Settings", "Accounts Settings", "Activity Type", + "Blog Category", "Blog Settings", "Blogger", "Branch", "Brand", "Buying Settings", + "Comment", "Communication", "Company", "Contact Us Settings", + "Country", "Currency", "Currency Exchange", "Deduction Type", "Department", + "Designation", "Earning Type", "Event", "Feed", "File Data", "Fiscal Year", + "HR Settings", "Industry Type", "Leave Type", "Letter Head", + "Mode of Payment", "Module Def", "Naming Series", "POS Setting", "Print Heading", + "Report", "Role", "Selling Settings", "Stock Settings", "Supplier Type", "UOM"): + try: + reset_perms(doctype) + except: + print "Error resetting perms for", doctype + raise diff --git a/erpnext/patches/v4_0/save_default_letterhead.py b/erpnext/patches/v4_0/save_default_letterhead.py new file mode 100644 index 00000000000..a6db0cdece1 --- /dev/null +++ b/erpnext/patches/v4_0/save_default_letterhead.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + """save default letterhead to set default_letter_head_content""" + try: + letter_head = frappe.get_doc("Letter Head", {"is_default": 1}) + letter_head.save() + except frappe.DoesNotExistError: + pass diff --git a/erpnext/patches/v4_0/set_naming_series_property_setter.py b/erpnext/patches/v4_0/set_naming_series_property_setter.py new file mode 100644 index 00000000000..7ebcc1e1f0d --- /dev/null +++ b/erpnext/patches/v4_0/set_naming_series_property_setter.py @@ -0,0 +1,98 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +import frappe +from frappe.custom.doctype.property_setter.property_setter import make_property_setter + +doctype_series_map = { + 'Attendance': 'ATT-', + 'C-Form': 'C-FORM-', + 'Customer': 'CUST-', + 'Customer Issue': 'CI-', + 'Delivery Note': 'DN-', + 'Installation Note': 'IN-', + 'Item': 'ITEM-', + 'Journal Voucher': 'JV-', + 'Lead': 'LEAD-', + 'Opportunity': 'OPTY-', + 'Packing Slip': 'PS-', + 'Production Order': 'PRO-', + 'Purchase Invoice': 'PINV-', + 'Purchase Order': 'PO-', + 'Purchase Receipt': 'PREC-', + 'Quality Inspection': 'QI-', + 'Quotation': 'QTN-', + 'Sales Invoice': 'SINV-', + 'Sales Order': 'SO-', + 'Stock Entry': 'STE-', + 'Supplier': 'SUPP-', + 'Supplier Quotation': 'SQTN-', + 'Issue': 'SUP-' +} + +def execute(): + series_to_set = get_series_to_set() + for doctype, opts in series_to_set.items(): + print "Setting naming series", doctype, opts + set_series(doctype, opts["options"], opts["default"]) + +def set_series(doctype, options, default): + make_property_setter(doctype, "naming_series", "options", options, "Text") + make_property_setter(doctype, "naming_series", "default", default, "Text") + +def get_series_to_set(): + series_to_set = {} + + for doctype, new_series in doctype_series_map.items(): + # you can't fix what does not exist :) + if not frappe.db.a_row_exists(doctype): + continue + + series_to_preserve = get_series_to_preserve(doctype, new_series) + + if not series_to_preserve: + continue + + default_series = get_default_series(doctype, new_series) + if not default_series: + continue + + existing_series = (frappe.get_meta(doctype).get_field("naming_series").options or "").split("\n") + existing_series = filter(None, [d.strip() for d in existing_series]) + + if (not (set(existing_series).difference(series_to_preserve) or set(series_to_preserve).difference(existing_series)) + and len(series_to_preserve)==len(existing_series)): + # print "No change for", doctype, ":", existing_series, "=", series_to_preserve + continue + + # set naming series property setter + series_to_preserve = list(set(series_to_preserve + existing_series)) + if new_series in series_to_preserve: + series_to_preserve.remove(new_series) + + if series_to_preserve: + series_to_set[doctype] = {"options": "\n".join(series_to_preserve), "default": default_series} + + return series_to_set + +def get_series_to_preserve(doctype, new_series): + series_to_preserve = frappe.db.sql_list("""select distinct naming_series from `tab{doctype}` + where ifnull(naming_series, '') not in ('', %s)""".format(doctype=doctype), new_series) + + series_to_preserve.sort() + + return series_to_preserve + +def get_default_series(doctype, new_series): + default_series = frappe.db.sql("""select naming_series from `tab{doctype}` where ifnull(naming_series, '') not in ('', %s) + and creation=(select max(creation) from `tab{doctype}` + where ifnull(naming_series, '') not in ('', %s)) order by creation desc limit 1""".format(doctype=doctype), + (new_series, new_series)) + + if not (default_series and default_series[0][0]): + print "[Skipping] Cannot guess which naming series to use for", doctype + return + + return default_series[0][0] diff --git a/erpnext/patches/v4_0/set_pricing_rule_for_buying_or_selling.py b/erpnext/patches/v4_0/set_pricing_rule_for_buying_or_selling.py new file mode 100644 index 00000000000..8be846ff162 --- /dev/null +++ b/erpnext/patches/v4_0/set_pricing_rule_for_buying_or_selling.py @@ -0,0 +1,13 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc("accounts", "doctype", "pricing_rule") + frappe.db.sql("""update `tabPricing Rule` set selling=1 where ifnull(applicable_for, '') in + ('', 'Customer', 'Customer Group', 'Territory', 'Sales Partner', 'Campaign')""") + + frappe.db.sql("""update `tabPricing Rule` set buying=1 where ifnull(applicable_for, '') in + ('', 'Supplier', 'Supplier Type')""") diff --git a/erpnext/patches/v4_0/split_email_settings.py b/erpnext/patches/v4_0/split_email_settings.py new file mode 100644 index 00000000000..c04e1d52461 --- /dev/null +++ b/erpnext/patches/v4_0/split_email_settings.py @@ -0,0 +1,67 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + print "WARNING!!!! Email Settings not migrated. Please setup your email again." + + # this will happen if you are migrating very old accounts + # comment out this line below and remember to create new Email Accounts + # for incoming and outgoing mails + raise Exception + + return + + + frappe.reload_doc("core", "doctype", "outgoing_email_settings") + frappe.reload_doc("support", "doctype", "support_email_settings") + + email_settings = get_email_settings() + map_outgoing_email_settings(email_settings) + map_support_email_settings(email_settings) + + +def map_outgoing_email_settings(email_settings): + outgoing_email_settings = frappe.get_doc("Outgoing Email Settings") + for fieldname in (("outgoing_mail_server", "mail_server"), + "use_ssl", "mail_port", "mail_login", "mail_password", + "always_use_login_id_as_sender", "auto_email_id"): + + if isinstance(fieldname, tuple): + from_fieldname, to_fieldname = fieldname + else: + from_fieldname = to_fieldname = fieldname + + outgoing_email_settings.set(to_fieldname, email_settings.get(from_fieldname)) + + outgoing_email_settings._fix_numeric_types() + outgoing_email_settings.save() + +def map_support_email_settings(email_settings): + support_email_settings = frappe.get_doc("Support Email Settings") + + for fieldname in ("sync_support_mails", "support_email", + ("support_host", "mail_server"), + ("support_use_ssl", "use_ssl"), + ("support_username", "mail_login"), + ("support_password", "mail_password"), + "support_signature", "send_autoreply", "support_autoreply"): + + if isinstance(fieldname, tuple): + from_fieldname, to_fieldname = fieldname + else: + from_fieldname = to_fieldname = fieldname + + support_email_settings.set(to_fieldname, email_settings.get(from_fieldname)) + + support_email_settings._fix_numeric_types() + support_email_settings.save() + +def get_email_settings(): + ret = {} + for field, value in frappe.db.sql("select field, value from tabSingles where doctype='Email Settings'"): + ret[field] = value + return ret + diff --git a/erpnext/patches/v4_0/update_account_root_type.py b/erpnext/patches/v4_0/update_account_root_type.py new file mode 100644 index 00000000000..10f6cda3c89 --- /dev/null +++ b/erpnext/patches/v4_0/update_account_root_type.py @@ -0,0 +1,34 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc("accounts", "doctype", "account") + + account_table_columns = frappe.db.get_table_columns("Account") + if "debit_or_credit" in account_table_columns and "is_pl_account" in account_table_columns: + frappe.db.sql("""UPDATE tabAccount + SET root_type = CASE + WHEN (debit_or_credit='Debit' and is_pl_account = 'No') THEN 'Asset' + WHEN (debit_or_credit='Credit' and is_pl_account = 'No') THEN 'Liability' + WHEN (debit_or_credit='Debit' and is_pl_account = 'Yes') THEN 'Expense' + WHEN (debit_or_credit='Credit' and is_pl_account = 'Yes') THEN 'Income' + END + WHERE ifnull(parent_account, '') = '' + """) + + else: + for key, root_type in (("asset", "Asset"), ("liabilities", "Liability"), ("expense", "Expense"), + ("income", "Income")): + frappe.db.sql("""update tabAccount set root_type=%s where name like %s + and ifnull(parent_account, '')=''""", (root_type, "%" + key + "%")) + + for root in frappe.db.sql("""SELECT name, lft, rgt, root_type FROM `tabAccount` + WHERE ifnull(parent_account, '')=''""", as_dict=True): + if root.root_type: + frappe.db.sql("""UPDATE tabAccount SET root_type=%s WHERE lft>%s and rgt<%s""", + (root.root_type, root.lft, root.rgt)) + else: + print b"Root type not found for {0}".format(root.name.encode("utf-8")) diff --git a/erpnext/patches/v4_0/update_custom_print_formats_for_renamed_fields.py b/erpnext/patches/v4_0/update_custom_print_formats_for_renamed_fields.py new file mode 100644 index 00000000000..60d45cf6a63 --- /dev/null +++ b/erpnext/patches/v4_0/update_custom_print_formats_for_renamed_fields.py @@ -0,0 +1,36 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +import re + +def execute(): + # NOTE: sequence is important + fields_list = ( + ("amount", "base_amount"), + ("ref_rate", "price_list_rate"), + ("base_ref_rate", "base_price_list_rate"), + ("adj_rate", "discount_percentage"), + ("export_rate", "rate"), + ("basic_rate", "base_rate"), + ("export_amount", "amount"), + ("reserved_warehouse", "warehouse"), + ("import_ref_rate", "price_list_rate"), + ("purchase_ref_rate", "base_price_list_rate"), + ("discount_rate", "discount_percentage"), + ("import_rate", "rate"), + ("purchase_rate", "base_rate"), + ("import_amount", "amount") + ) + + condition = " or ".join("""html like "%%{}%%" """.format(d[0].replace("_", "\\_")) for d in fields_list + if d[0] != "amount") + + for name, html in frappe.db.sql("""select name, html from `tabPrint Format` + where standard = 'No' and ({}) and html not like '%%frappe.%%'""".format(condition)): + html = html.replace("wn.", "frappe.") + for from_field, to_field in fields_list: + html = re.sub(r"\b{}\b".format(from_field), to_field, html) + + frappe.db.set_value("Print Format", name, "html", html) diff --git a/erpnext/patches/v4_0/update_incharge_name_to_sales_person_in_maintenance_schedule.py b/erpnext/patches/v4_0/update_incharge_name_to_sales_person_in_maintenance_schedule.py new file mode 100644 index 00000000000..11f00905527 --- /dev/null +++ b/erpnext/patches/v4_0/update_incharge_name_to_sales_person_in_maintenance_schedule.py @@ -0,0 +1,12 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc("support", "doctype", "maintenance_schedule_detail") + frappe.reload_doc("support", "doctype", "maintenance_schedule_item") + + frappe.db.sql("""update `tabMaintenance Schedule Detail` set sales_person=incharge_name""") + frappe.db.sql("""update `tabMaintenance Schedule Item` set sales_person=incharge_name""") \ No newline at end of file diff --git a/erpnext/patches/v4_0/update_other_charges_in_custom_purchase_print_formats.py b/erpnext/patches/v4_0/update_other_charges_in_custom_purchase_print_formats.py new file mode 100644 index 00000000000..c0f9ee008f4 --- /dev/null +++ b/erpnext/patches/v4_0/update_other_charges_in_custom_purchase_print_formats.py @@ -0,0 +1,12 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +import re + +def execute(): + for name, html in frappe.db.sql("""select name, html from `tabPrint Format` + where standard = 'No' and html like '%%purchase\\_tax\\_details%%'"""): + html = re.sub(r"\bpurchase_tax_details\b", "other_charges", html) + frappe.db.set_value("Print Format", name, "html", html) diff --git a/erpnext/patches/v4_0/update_tax_amount_after_discount.py b/erpnext/patches/v4_0/update_tax_amount_after_discount.py new file mode 100644 index 00000000000..e935bc4088d --- /dev/null +++ b/erpnext/patches/v4_0/update_tax_amount_after_discount.py @@ -0,0 +1,20 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc("accounts", "doctype", "sales_taxes_and_charges") + docs_with_discount_amount = frappe._dict() + for dt in ["Quotation", "Sales Order", "Delivery Note", "Sales Invoice"]: + records = frappe.db.sql_list("""select name from `tab%s` + where ifnull(discount_amount, 0) > 0 and docstatus=1""" % dt) + docs_with_discount_amount[dt] = records + + for dt, discounted_records in docs_with_discount_amount.items(): + frappe.db.sql("""update `tabSales Taxes and Charges` + set tax_amount_after_discount_amount = tax_amount + where parenttype = %s and parent not in (%s)""" % + ('%s', ', '.join(['%s']*(len(discounted_records)+1))), + tuple([dt, ''] + discounted_records)) diff --git a/erpnext/patches/v4_0/update_user_properties.py b/erpnext/patches/v4_0/update_user_properties.py new file mode 100644 index 00000000000..a5b7bfd1851 --- /dev/null +++ b/erpnext/patches/v4_0/update_user_properties.py @@ -0,0 +1,51 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +import frappe.permissions +import frappe.defaults + +def execute(): + frappe.reload_doc("core", "doctype", "docfield") + frappe.reload_doc("hr", "doctype", "employee") + + set_print_email_permissions() + migrate_user_properties_to_user_permissions() + + frappe.clear_cache() + +def migrate_user_properties_to_user_permissions(): + for d in frappe.db.sql("""select parent, defkey, defvalue from tabDefaultValue + where parent not in ('__global', '__default')""", as_dict=True): + df = frappe.db.sql("""select options from tabDocField + where fieldname=%s and fieldtype='Link'""", d.defkey, as_dict=True) + + if df: + frappe.db.sql("""update tabDefaultValue + set defkey=%s, parenttype='User Permission' + where defkey=%s and + parent not in ('__global', '__default')""", (df[0].options, d.defkey)) + +def set_print_email_permissions(): + # reset Page perms + from frappe.core.page.permission_manager.permission_manager import reset + reset("Page") + reset("Report") + + if "allow_print" not in frappe.db.get_table_columns("DocType"): + return + + # patch to move print, email into DocPerm + # NOTE: allow_print and allow_email are misnamed. They were used to hide print / hide email + for doctype, hide_print, hide_email in frappe.db.sql("""select name, ifnull(allow_print, 0), ifnull(allow_email, 0) + from `tabDocType` where ifnull(issingle, 0)=0 and ifnull(istable, 0)=0 and + (ifnull(allow_print, 0)=0 or ifnull(allow_email, 0)=0)"""): + + if not hide_print: + frappe.db.sql("""update `tabDocPerm` set `print`=1 + where permlevel=0 and `read`=1 and parent=%s""", doctype) + + if not hide_email: + frappe.db.sql("""update `tabDocPerm` set `email`=1 + where permlevel=0 and `read`=1 and parent=%s""", doctype) diff --git a/erpnext/patches/v4_0/update_users_report_view_settings.py b/erpnext/patches/v4_0/update_users_report_view_settings.py new file mode 100644 index 00000000000..8883dc26f52 --- /dev/null +++ b/erpnext/patches/v4_0/update_users_report_view_settings.py @@ -0,0 +1,12 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals + +from frappe.model import update_users_report_view_settings +from erpnext.patches.v4_0.fields_to_be_renamed import rename_map + +def execute(): + for dt, field_list in rename_map.items(): + for field in field_list: + update_users_report_view_settings(dt, field[0], field[1]) diff --git a/erpnext/patches/v4_0/validate_v3_patch.py b/erpnext/patches/v4_0/validate_v3_patch.py new file mode 100644 index 00000000000..21258b6d6d2 --- /dev/null +++ b/erpnext/patches/v4_0/validate_v3_patch.py @@ -0,0 +1,11 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + from frappe.modules.patch_handler import executed + last_v3_patch = 'patches.1401.fix_pos_outstanding' + if not executed(last_v3_patch): + raise Exception, "site not ready to migrate to version 4" diff --git a/erpnext/patches/v4_1/__init__.py b/erpnext/patches/v4_1/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/patches/v4_1/fix_delivery_and_billing_status.py b/erpnext/patches/v4_1/fix_delivery_and_billing_status.py new file mode 100644 index 00000000000..2dbc8250850 --- /dev/null +++ b/erpnext/patches/v4_1/fix_delivery_and_billing_status.py @@ -0,0 +1,12 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.db.sql("""update `tabSales Order` set delivery_status = 'Not Delivered' + where delivery_status = 'Delivered' and ifnull(per_delivered, 0) = 0 and ifnull(docstatus, 0) in (0, 1)""") + + frappe.db.sql("""update `tabSales Order` set billing_status = 'Not Billed' + where billing_status = 'Billed' and ifnull(per_billed, 0) = 0 and ifnull(docstatus, 0) in (0, 1)""") diff --git a/erpnext/patches/v4_1/fix_jv_remarks.py b/erpnext/patches/v4_1/fix_jv_remarks.py new file mode 100644 index 00000000000..3b2f3422312 --- /dev/null +++ b/erpnext/patches/v4_1/fix_jv_remarks.py @@ -0,0 +1,21 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + reference_date = guess_reference_date() + for name in frappe.db.sql_list("""select name from `tabJournal Voucher` + where date(creation)>=%s""", reference_date): + jv = frappe.get_doc("Journal Voucher", name) + try: + jv.create_remarks() + except frappe.MandatoryError: + pass + else: + frappe.db.set_value("Journal Voucher", jv.name, "remark", jv.remark) + +def guess_reference_date(): + return (frappe.db.get_value("Patch Log", {"patch": "erpnext.patches.v4_0.validate_v3_patch"}, "creation") + or "2014-05-06") diff --git a/erpnext/patches/v4_1/fix_sales_order_delivered_status.py b/erpnext/patches/v4_1/fix_sales_order_delivered_status.py new file mode 100644 index 00000000000..f66d85657da --- /dev/null +++ b/erpnext/patches/v4_1/fix_sales_order_delivered_status.py @@ -0,0 +1,15 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for si in frappe.db.sql_list("""select name + from `tabSales Invoice` + where ifnull(update_stock,0) = 1 and docstatus = 1 and exists( + select name from `tabSales Invoice Item` where parent=`tabSales Invoice`.name and + ifnull(so_detail, "") != "")"""): + + invoice = frappe.get_doc("Sales Invoice", si) + invoice.update_qty() diff --git a/erpnext/patches/v4_1/set_outgoing_email_footer.py b/erpnext/patches/v4_1/set_outgoing_email_footer.py new file mode 100644 index 00000000000..73d8d607f29 --- /dev/null +++ b/erpnext/patches/v4_1/set_outgoing_email_footer.py @@ -0,0 +1,12 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from erpnext.setup.install import default_mail_footer + +def execute(): + return + mail_footer = frappe.db.get_default('mail_footer') or '' + mail_footer += default_mail_footer + frappe.db.set_value("Outgoing Email Settings", "Outgoing Email Settings", "footer", mail_footer) diff --git a/erpnext/patches/v4_2/__init__.py b/erpnext/patches/v4_2/__init__.py new file mode 100644 index 00000000000..e69de29bb2d diff --git a/erpnext/patches/v4_2/add_currency_turkish_lira.py b/erpnext/patches/v4_2/add_currency_turkish_lira.py new file mode 100644 index 00000000000..d768d58f3b2 --- /dev/null +++ b/erpnext/patches/v4_2/add_currency_turkish_lira.py @@ -0,0 +1,11 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.geo.country_info import get_country_info +from erpnext.setup.install import add_country_and_currency + +def execute(): + country = get_country_info(country="Turkey") + add_country_and_currency("Turkey", country) diff --git a/erpnext/patches/v4_2/default_website_style.py b/erpnext/patches/v4_2/default_website_style.py new file mode 100644 index 00000000000..6f375b9ab58 --- /dev/null +++ b/erpnext/patches/v4_2/default_website_style.py @@ -0,0 +1,10 @@ +import frappe +from frappe.templates.pages.style_settings import default_properties + +def execute(): + frappe.reload_doc('website', 'doctype', 'style_settings') + style_settings = frappe.get_doc("Style Settings", "Style Settings") + if not style_settings.apply_style: + style_settings.update(default_properties) + style_settings.apply_style = 1 + style_settings.save() diff --git a/erpnext/patches/v4_2/delete_old_print_formats.py b/erpnext/patches/v4_2/delete_old_print_formats.py new file mode 100644 index 00000000000..75c3619ae4f --- /dev/null +++ b/erpnext/patches/v4_2/delete_old_print_formats.py @@ -0,0 +1,23 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + old_formats = ("Sales Invoice", "Sales Invoice Spartan", "Sales Invoice Modern", + "Sales Invoice Classic", + "Sales Order Spartan", "Sales Order Modern", "Sales Order Classic", + "Purchase Order Spartan", "Purchase Order Modern", "Purchase Order Classic", + "Quotation Spartan", "Quotation Modern", "Quotation Classic", + "Delivery Note Spartan", "Delivery Note Modern", "Delivery Note Classic") + + for fmt in old_formats: + # update property setter + for ps in frappe.db.sql_list("""select name from `tabProperty Setter` + where property='default_print_format' and value=%s""", fmt): + ps = frappe.get_doc("Property Setter", ps) + ps.value = "Standard" + ps.save(ignore_permissions = True) + + frappe.delete_doc_if_exists("Print Format", fmt) diff --git a/erpnext/patches/v4_2/fix_account_master_type.py b/erpnext/patches/v4_2/fix_account_master_type.py new file mode 100644 index 00000000000..d4603f24f59 --- /dev/null +++ b/erpnext/patches/v4_2/fix_account_master_type.py @@ -0,0 +1,12 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for d in frappe.db.sql("""select name from `tabAccount` + where ifnull(master_type, '') not in ('Customer', 'Supplier', 'Employee', '') and docstatus=0"""): + ac = frappe.get_doc("Account", d[0]) + ac.master_type = None + ac.save() diff --git a/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py b/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py new file mode 100644 index 00000000000..a72b95480a5 --- /dev/null +++ b/erpnext/patches/v4_2/fix_gl_entries_for_stock_transactions.py @@ -0,0 +1,52 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +from frappe.utils import flt + +def execute(): + from erpnext.utilities.repost_stock import repost + repost(allow_zero_rate=True, only_actual=True) + + warehouse_account = frappe.db.sql("""select name, master_name from tabAccount + where ifnull(account_type, '') = 'Warehouse'""") + if warehouse_account: + warehouses = [d[1] for d in warehouse_account] + accounts = [d[0] for d in warehouse_account] + + stock_vouchers = frappe.db.sql("""select distinct sle.voucher_type, sle.voucher_no + from `tabStock Ledger Entry` sle + where sle.warehouse in (%s) + order by sle.posting_date""" % + ', '.join(['%s']*len(warehouses)), tuple(warehouses)) + + rejected = [] + for voucher_type, voucher_no in stock_vouchers: + stock_bal = frappe.db.sql("""select sum(stock_value_difference) from `tabStock Ledger Entry` + where voucher_type=%s and voucher_no =%s and warehouse in (%s)""" % + ('%s', '%s', ', '.join(['%s']*len(warehouses))), tuple([voucher_type, voucher_no] + warehouses)) + + account_bal = frappe.db.sql("""select ifnull(sum(ifnull(debit, 0) - ifnull(credit, 0)), 0) + from `tabGL Entry` + where voucher_type=%s and voucher_no =%s and account in (%s) + group by voucher_type, voucher_no""" % + ('%s', '%s', ', '.join(['%s']*len(accounts))), tuple([voucher_type, voucher_no] + accounts)) + + if stock_bal and account_bal and abs(flt(stock_bal[0][0]) - flt(account_bal[0][0])) > 0.1: + try: + print voucher_type, voucher_no, stock_bal[0][0], account_bal[0][0] + + frappe.db.sql("""delete from `tabGL Entry` + where voucher_type=%s and voucher_no=%s""", (voucher_type, voucher_no)) + + voucher = frappe.get_doc(voucher_type, voucher_no) + voucher.make_gl_entries(repost_future_gle=False) + frappe.db.commit() + except Exception, e: + print frappe.get_traceback() + rejected.append([voucher_type, voucher_no]) + frappe.db.rollback() + + print "Failed to repost: " + print rejected diff --git a/erpnext/patches/v4_2/party_model.py b/erpnext/patches/v4_2/party_model.py new file mode 100644 index 00000000000..7bcb6ce2fd5 --- /dev/null +++ b/erpnext/patches/v4_2/party_model.py @@ -0,0 +1,97 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.reload_doc("accounts", "doctype", "account") + frappe.reload_doc("setup", "doctype", "company") + frappe.reload_doc("accounts", "doctype", "journal_voucher_detail") + frappe.reload_doc("accounts", "doctype", "gl_entry") + receivable_payable_accounts = create_receivable_payable_account() + if receivable_payable_accounts: + set_party_in_jv_and_gl_entry(receivable_payable_accounts) + delete_individual_party_account() + remove_customer_supplier_account_report() + + +def link_warehouse_account(): + frappe.db.sql("""update tabAccount set warehouse=master_name + where ifnull(account_type, '') = 'Warehouse' and ifnull(master_name, '') != ''""") + +def create_receivable_payable_account(): + receivable_payable_accounts = frappe._dict() + + def _create_account(args): + account = frappe.new_doc("Account") + account.group_or_ledger = "Ledger" + account.update(args) + account.insert() + + frappe.db.set_value("Company", args["company"], ("default_receivable_account" + if args["account_type"]=="Receivable" else "default_payable_account"), account.name) + + receivable_payable_accounts.setdefault(args["company"], {}).setdefault(args["account_type"], account.name) + + for company in frappe.db.sql_list("select name from tabCompany"): + _create_account({ + "account_name": "Debtors", + "account_type": "Receivable", + "company": company, + "parent_account": get_parent_account(company, "Customer") + }) + + _create_account({ + "account_name": "Creditors", + "account_type": "Payable", + "company": company, + "parent_account": get_parent_account(company, "Supplier") + }) + + return receivable_payable_accounts + +def get_parent_account(company, master_type): + parent_account = frappe.db.get_value("Company", company, + "receivables_group" if master_type=="Customer" else "payables_group") + if not parent_account: + parent_account = frappe.db.get_value("Account", {"company": company, + "account_name": "Accounts Receivable" if master_type=="Customer" else "Accounts Payable"}) + + if not parent_account: + parent_account = frappe.db.sql_list("""select parent_account from tabAccount + where company=%s and ifnull(master_type, '')=%s and ifnull(master_name, '')!='' limit 1""", + (company, master_type)) + parent_account = parent_account[0][0] if parent_account else None + + return parent_account + +def set_party_in_jv_and_gl_entry(receivable_payable_accounts): + accounts = frappe.db.sql("""select name, master_type, master_name, company from `tabAccount` + where ifnull(master_type, '') in ('Customer', 'Supplier') and ifnull(master_name, '') != ''""", as_dict=1) + + account_map = frappe._dict() + for d in accounts: + account_map.setdefault(d.name, d) + + if not account_map: + return + + for dt in ["Journal Voucher Detail", "GL Entry"]: + records = frappe.db.sql("""select name, account from `tab%s` where account in (%s)""" % + (dt, ", ".join(['%s']*len(account_map))), tuple(account_map.keys()), as_dict=1) + for d in records: + account_details = account_map.get(d.account, {}) + account_type = "Receivable" if account_details.get("master_type")=="Customer" else "Payable" + new_account = receivable_payable_accounts[account_details.get("company")][account_type] + + frappe.db.sql("update `tab{0}` set account=%s, party_type=%s, party=%s where name=%s".format(dt), + (new_account, account_details.get("master_type"), account_details.get("master_name"), d.name)) + +def delete_individual_party_account(): + frappe.db.sql("""delete from `tabAccount` where ifnull(master_type, '') in ('Customer', 'Supplier') + and ifnull(master_name, '') != ''""") + +def remove_customer_supplier_account_report(): + for d in ["Customer Account Head", "Supplier Account Head"]: + frappe.delete_doc("Report", d) diff --git a/erpnext/patches/v4_2/recalculate_bom_cost.py b/erpnext/patches/v4_2/recalculate_bom_cost.py new file mode 100644 index 00000000000..3a194ff195f --- /dev/null +++ b/erpnext/patches/v4_2/recalculate_bom_cost.py @@ -0,0 +1,16 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + for d in frappe.db.sql("select name from `tabBOM` where docstatus < 2"): + try: + document = frappe.get_doc('BOM', d[0]) + if document.docstatus == 1: + document.ignore_validate_update_after_submit = True + document.calculate_cost() + document.save() + except: + pass \ No newline at end of file diff --git a/erpnext/patches/v4_2/repost_stock_reconciliation.py b/erpnext/patches/v4_2/repost_stock_reconciliation.py new file mode 100644 index 00000000000..73cb36d487d --- /dev/null +++ b/erpnext/patches/v4_2/repost_stock_reconciliation.py @@ -0,0 +1,31 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe +import json + +def execute(): + existing_allow_negative_stock = frappe.db.get_value("Stock Settings", None, "allow_negative_stock") + frappe.db.set_value("Stock Settings", None, "allow_negative_stock", 1) + + head_row = ["Item Code", "Warehouse", "Quantity", "Valuation Rate"] + stock_reco_to_be_reposted = [] + for d in frappe.db.sql("""select name, reconciliation_json from `tabStock Reconciliation` + where docstatus=1 and creation > '2014-03-01'""", as_dict=1): + data = json.loads(d.reconciliation_json) + for row in data[data.index(head_row)+1:]: + if row[3] in ["", None]: + stock_reco_to_be_reposted.append(d.name) + break + + for dn in stock_reco_to_be_reposted: + reco = frappe.get_doc("Stock Reconciliation", dn) + reco.docstatus = 2 + reco.on_cancel() + + reco.docstatus = 1 + reco.validate() + reco.on_submit() + + frappe.db.set_value("Stock Settings", None, "allow_negative_stock", existing_allow_negative_stock) diff --git a/erpnext/patches/v4_2/seprate_manufacture_and_repack.py b/erpnext/patches/v4_2/seprate_manufacture_and_repack.py new file mode 100644 index 00000000000..5b36289bc91 --- /dev/null +++ b/erpnext/patches/v4_2/seprate_manufacture_and_repack.py @@ -0,0 +1,9 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + frappe.db.sql("""update `tabStock Entry` set purpose='Manufacture' where purpose='Manufacture/Repack' and ifnull(production_order,"")!="" """) + frappe.db.sql("""update `tabStock Entry` set purpose='Repack' where purpose='Manufacture/Repack' and ifnull(production_order,"")="" """) \ No newline at end of file diff --git a/erpnext/patches/v4_2/set_company_country.py b/erpnext/patches/v4_2/set_company_country.py new file mode 100644 index 00000000000..6992f02202d --- /dev/null +++ b/erpnext/patches/v4_2/set_company_country.py @@ -0,0 +1,15 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + country = frappe.db.get_single_value("Global Defaults", "country") + if not country: + print "Country not specified in Global Defaults" + return + + for company in frappe.db.sql_list("""select name from `tabCompany` + where ifnull(country, '')=''"""): + frappe.db.set_value("Company", company, "country", country) diff --git a/erpnext/patches/v4_2/toggle_rounded_total.py b/erpnext/patches/v4_2/toggle_rounded_total.py new file mode 100644 index 00000000000..aa63fdccd3f --- /dev/null +++ b/erpnext/patches/v4_2/toggle_rounded_total.py @@ -0,0 +1,9 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + global_defaults = frappe.get_doc("Global Defaults", "Global Defaults") + global_defaults.toggle_rounded_total() diff --git a/erpnext/patches/v4_2/update_project_milestones.py b/erpnext/patches/v4_2/update_project_milestones.py new file mode 100644 index 00000000000..4f93eb9172b --- /dev/null +++ b/erpnext/patches/v4_2/update_project_milestones.py @@ -0,0 +1,8 @@ +import frappe + +def execute(): + for project in frappe.db.sql_list("select name from tabProject"): + frappe.reload_doc("projects", "doctype", "project") + p = frappe.get_doc("Project", project) + p.update_milestones_completed() + p.db_set("percent_milestones_completed", p.percent_milestones_completed) diff --git a/erpnext/patches/v4_2/update_requested_and_ordered_qty.py b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py new file mode 100644 index 00000000000..d6cabd8c236 --- /dev/null +++ b/erpnext/patches/v4_2/update_requested_and_ordered_qty.py @@ -0,0 +1,24 @@ +# Copyright (c) 2013, Web Notes Technologies Pvt. Ltd. and Contributors +# License: GNU General Public License v3. See license.txt + +from __future__ import unicode_literals +import frappe + +def execute(): + from erpnext.utilities.repost_stock import update_bin_qty, get_indented_qty, get_ordered_qty + + count=0 + for item_code, warehouse in frappe.db.sql("""select distinct item_code, warehouse from + (select item_code, warehouse from tabBin + union + select item_code, warehouse from `tabStock Ledger Entry`) a"""): + try: + count += 1 + update_bin_qty(item_code, warehouse, { + "indented_qty": get_indented_qty(item_code, warehouse), + "ordered_qty": get_ordered_qty(item_code, warehouse) + }) + if count % 200 == 0: + frappe.db.commit() + except: + frappe.db.rollback() diff --git a/erpnext/patches/v4_2/update_sales_order_invoice_field_name.py b/erpnext/patches/v4_2/update_sales_order_invoice_field_name.py new file mode 100644 index 00000000000..a8303a0aaef --- /dev/null +++ b/erpnext/patches/v4_2/update_sales_order_invoice_field_name.py @@ -0,0 +1,6 @@ +import frappe + +def execute(): + frappe.reload_doc('accounts', 'doctype', 'sales_invoice') + frappe.db.sql("""update `tabSales Invoice` set from_date = invoice_period_from_date, + to_date = invoice_period_to_date, is_recurring = convert_into_recurring_invoice""")