Merge branch 'develop' into patch-5

This commit is contained in:
Dany Robert
2021-07-29 16:47:28 +05:30
committed by GitHub
228 changed files with 6065 additions and 3099 deletions

View File

@@ -74,7 +74,7 @@
"stock_received_but_not_billed",
"service_received_but_not_billed",
"expenses_included_in_valuation",
"fixed_asset_depreciation_settings",
"fixed_asset_defaults",
"accumulated_depreciation_account",
"depreciation_expense_account",
"series_for_depreciation_entry",
@@ -83,6 +83,7 @@
"disposal_account",
"depreciation_cost_center",
"capital_work_in_progress_account",
"repair_and_maintenance_account",
"asset_received_but_not_billed",
"budget_detail",
"exception_budget_approver_role",
@@ -519,12 +520,6 @@
"no_copy": 1,
"options": "Account"
},
{
"collapsible": 1,
"fieldname": "fixed_asset_depreciation_settings",
"fieldtype": "Section Break",
"label": "Fixed Asset Depreciation Settings"
},
{
"fieldname": "accumulated_depreciation_account",
"fieldtype": "Link",
@@ -734,6 +729,18 @@
"fieldtype": "Link",
"label": "Default Payment Discount Account",
"options": "Account"
},
{
"collapsible": 1,
"fieldname": "fixed_asset_defaults",
"fieldtype": "Section Break",
"label": "Fixed Asset Defaults"
},
{
"fieldname": "repair_and_maintenance_account",
"fieldtype": "Link",
"label": "Repair and Maintenance Account",
"options": "Account"
}
],
"icon": "fa fa-building",
@@ -741,7 +748,7 @@
"image_field": "company_logo",
"is_tree": 1,
"links": [],
"modified": "2021-05-07 03:11:28.189740",
"modified": "2021-05-12 16:51:08.187233",
"modified_by": "Administrator",
"module": "Setup",
"name": "Company",

View File

@@ -110,7 +110,7 @@ class Company(NestedSet):
self.create_default_warehouses()
if frappe.flags.country_change:
install_country_fixtures(self.name)
install_country_fixtures(self.name, self.country)
self.create_default_tax_template()
if not frappe.db.get_value("Department", {"company": self.name}):
@@ -291,7 +291,7 @@ class Company(NestedSet):
cash = frappe.db.get_value('Mode of Payment', {'type': 'Cash'}, 'name')
if cash and self.default_cash_account \
and not frappe.db.get_value('Mode of Payment Account', {'company': self.name, 'parent': cash}):
mode_of_payment = frappe.get_doc('Mode of Payment', cash)
mode_of_payment = frappe.get_doc('Mode of Payment', cash, for_update=True)
mode_of_payment.append('accounts', {
'company': self.name,
'default_account': self.default_cash_account
@@ -395,7 +395,7 @@ class Company(NestedSet):
@frappe.whitelist()
def enqueue_replace_abbr(company, old, new):
kwargs = dict(company=company, old=old, new=new)
kwargs = dict(queue="long", company=company, old=old, new=new)
frappe.enqueue('erpnext.setup.doctype.company.company.replace_abbr', **kwargs)
@@ -440,16 +440,15 @@ def get_name_with_abbr(name, company):
return " - ".join(parts)
def install_country_fixtures(company):
company_doc = frappe.get_doc("Company", company)
path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(company_doc.country))
def install_country_fixtures(company, country):
path = frappe.get_app_path('erpnext', 'regional', frappe.scrub(country))
if os.path.exists(path.encode("utf-8")):
try:
module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(company_doc.country))
frappe.get_attr(module_name)(company_doc, False)
module_name = "erpnext.regional.{0}.setup.setup".format(frappe.scrub(country))
frappe.get_attr(module_name)(company, False)
except Exception as e:
frappe.log_error()
frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(company_doc.country)))
frappe.throw(_("Failed to setup defaults for country {0}. Please contact support@erpnext.com").format(frappe.bold(country)))
def update_company_current_month_sales(company):

View File

@@ -87,8 +87,8 @@ class ItemGroup(NestedSet, WebsiteGenerator):
if not field_filters:
field_filters = {}
# Ensure the query remains within current item group
field_filters['item_group'] = self.name
# Ensure the query remains within current item group & sub group
field_filters['item_group'] = [ig[0] for ig in get_child_groups(self.name)]
engine = ProductQuery()
context.items = engine.query(attribute_filters, field_filters, search, start, item_group=self.name)

View File

@@ -12,10 +12,14 @@ from frappe.desk.notifications import clear_notifications
class TransactionDeletionRecord(Document):
def validate(self):
frappe.only_for('System Manager')
self.validate_doctypes_to_be_ignored()
def validate_doctypes_to_be_ignored(self):
doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
for doctype in self.doctypes_to_be_ignored:
if doctype.doctype_name not in doctypes_to_be_ignored_list:
frappe.throw(_("DocTypes should not be added manually to the 'Excluded DocTypes' table. You are only allowed to remove entries from it. "), title=_("Not Allowed"))
frappe.throw(_("DocTypes should not be added manually to the 'Excluded DocTypes' table. You are only allowed to remove entries from it. "),
title=_("Not Allowed"))
def before_submit(self):
if not self.doctypes_to_be_ignored:
@@ -23,54 +27,9 @@ class TransactionDeletionRecord(Document):
self.delete_bins()
self.delete_lead_addresses()
company_obj = frappe.get_doc('Company', self.company)
# reset company values
company_obj.total_monthly_sales = 0
company_obj.sales_monthly_history = None
company_obj.save()
# Clear notification counts
self.reset_company_values()
clear_notifications()
singles = frappe.get_all('DocType', filters = {'issingle': 1}, pluck = 'name')
tables = frappe.get_all('DocType', filters = {'istable': 1}, pluck = 'name')
doctypes_to_be_ignored_list = singles
for doctype in self.doctypes_to_be_ignored:
doctypes_to_be_ignored_list.append(doctype.doctype_name)
docfields = frappe.get_all('DocField',
filters = {
'fieldtype': 'Link',
'options': 'Company',
'parent': ['not in', doctypes_to_be_ignored_list]},
fields=['parent', 'fieldname'])
for docfield in docfields:
if docfield['parent'] != self.doctype:
no_of_docs = frappe.db.count(docfield['parent'], {
docfield['fieldname'] : self.company
})
if no_of_docs > 0:
self.delete_version_log(docfield['parent'], docfield['fieldname'])
self.delete_communications(docfield['parent'], docfield['fieldname'])
# populate DocTypes table
if docfield['parent'] not in tables:
self.append('doctypes', {
'doctype_name' : docfield['parent'],
'no_of_docs' : no_of_docs
})
# delete the docs linked with the specified company
frappe.db.delete(docfield['parent'], {
docfield['fieldname'] : self.company
})
naming_series = frappe.db.get_value('DocType', docfield['parent'], 'autoname')
if naming_series:
if '#' in naming_series:
self.update_naming_series(naming_series, docfield['parent'])
self.delete_company_transactions()
def populate_doctypes_to_be_ignored_table(self):
doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
@@ -79,6 +38,111 @@ class TransactionDeletionRecord(Document):
'doctype_name' : doctype
})
def delete_bins(self):
frappe.db.sql("""delete from tabBin where warehouse in
(select name from tabWarehouse where company=%s)""", self.company)
def delete_lead_addresses(self):
"""Delete addresses to which leads are linked"""
leads = frappe.get_all('Lead', filters={'company': self.company})
leads = ["'%s'" % row.get("name") for row in leads]
addresses = []
if leads:
addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
in ({leads})""".format(leads=",".join(leads)))
if addresses:
addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
name not in (select distinct dl1.parent from `tabDynamic Link` dl1
inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
def reset_company_values(self):
company_obj = frappe.get_doc('Company', self.company)
company_obj.total_monthly_sales = 0
company_obj.sales_monthly_history = None
company_obj.save()
def delete_company_transactions(self):
doctypes_to_be_ignored_list = self.get_doctypes_to_be_ignored_list()
docfields = self.get_doctypes_with_company_field(doctypes_to_be_ignored_list)
tables = self.get_all_child_doctypes()
for docfield in docfields:
if docfield['parent'] != self.doctype:
no_of_docs = self.get_number_of_docs_linked_with_specified_company(docfield['parent'], docfield['fieldname'])
if no_of_docs > 0:
self.delete_version_log(docfield['parent'], docfield['fieldname'])
self.delete_communications(docfield['parent'], docfield['fieldname'])
self.populate_doctypes_table(tables, docfield['parent'], no_of_docs)
self.delete_child_tables(docfield['parent'], docfield['fieldname'])
self.delete_docs_linked_with_specified_company(docfield['parent'], docfield['fieldname'])
naming_series = frappe.db.get_value('DocType', docfield['parent'], 'autoname')
if naming_series:
if '#' in naming_series:
self.update_naming_series(naming_series, docfield['parent'])
def get_doctypes_to_be_ignored_list(self):
singles = frappe.get_all('DocType', filters = {'issingle': 1}, pluck = 'name')
doctypes_to_be_ignored_list = singles
for doctype in self.doctypes_to_be_ignored:
doctypes_to_be_ignored_list.append(doctype.doctype_name)
return doctypes_to_be_ignored_list
def get_doctypes_with_company_field(self, doctypes_to_be_ignored_list):
docfields = frappe.get_all('DocField',
filters = {
'fieldtype': 'Link',
'options': 'Company',
'parent': ['not in', doctypes_to_be_ignored_list]},
fields=['parent', 'fieldname'])
return docfields
def get_all_child_doctypes(self):
return frappe.get_all('DocType', filters = {'istable': 1}, pluck = 'name')
def get_number_of_docs_linked_with_specified_company(self, doctype, company_fieldname):
return frappe.db.count(doctype, {company_fieldname : self.company})
def populate_doctypes_table(self, tables, doctype, no_of_docs):
if doctype not in tables:
self.append('doctypes', {
'doctype_name' : doctype,
'no_of_docs' : no_of_docs
})
def delete_child_tables(self, doctype, company_fieldname):
parent_docs_to_be_deleted = frappe.get_all(doctype, {
company_fieldname : self.company
}, pluck = 'name')
child_tables = frappe.get_all('DocField', filters = {
'fieldtype': 'Table',
'parent': doctype
}, pluck = 'options')
for table in child_tables:
frappe.db.delete(table, {
'parent': ['in', parent_docs_to_be_deleted]
})
def delete_docs_linked_with_specified_company(self, doctype, company_fieldname):
frappe.db.delete(doctype, {
company_fieldname : self.company
})
def update_naming_series(self, naming_series, doctype_name):
if '.' in naming_series:
prefix, hashes = naming_series.rsplit('.', 1)
@@ -107,32 +171,6 @@ class TransactionDeletionRecord(Document):
frappe.delete_doc('Communication', communication_names, ignore_permissions=True)
def delete_bins(self):
frappe.db.sql("""delete from tabBin where warehouse in
(select name from tabWarehouse where company=%s)""", self.company)
def delete_lead_addresses(self):
"""Delete addresses to which leads are linked"""
leads = frappe.get_all('Lead', filters={'company': self.company})
leads = ["'%s'" % row.get("name") for row in leads]
addresses = []
if leads:
addresses = frappe.db.sql_list("""select parent from `tabDynamic Link` where link_name
in ({leads})""".format(leads=",".join(leads)))
if addresses:
addresses = ["%s" % frappe.db.escape(addr) for addr in addresses]
frappe.db.sql("""delete from tabAddress where name in ({addresses}) and
name not in (select distinct dl1.parent from `tabDynamic Link` dl1
inner join `tabDynamic Link` dl2 on dl1.parent=dl2.parent
and dl1.link_doctype<>dl2.link_doctype)""".format(addresses=",".join(addresses)))
frappe.db.sql("""delete from `tabDynamic Link` where link_doctype='Lead'
and parenttype='Address' and link_name in ({leads})""".format(leads=",".join(leads)))
frappe.db.sql("""update tabCustomer set lead_name=NULL where lead_name in ({leads})""".format(leads=",".join(leads)))
@frappe.whitelist()
def get_doctypes_to_be_ignored():
doctypes_to_be_ignored_list = ['Account', 'Cost Center', 'Warehouse', 'Budget',