fix: delete child docs when parent doc is deleted (#26239)
This commit is contained in:
parent
f4fc1384a5
commit
05d7c69aa2
@ -12,10 +12,14 @@ from frappe.desk.notifications import clear_notifications
|
|||||||
class TransactionDeletionRecord(Document):
|
class TransactionDeletionRecord(Document):
|
||||||
def validate(self):
|
def validate(self):
|
||||||
frappe.only_for('System Manager')
|
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()
|
doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
|
||||||
for doctype in self.doctypes_to_be_ignored:
|
for doctype in self.doctypes_to_be_ignored:
|
||||||
if doctype.doctype_name not in doctypes_to_be_ignored_list:
|
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):
|
def before_submit(self):
|
||||||
if not self.doctypes_to_be_ignored:
|
if not self.doctypes_to_be_ignored:
|
||||||
@ -23,54 +27,9 @@ class TransactionDeletionRecord(Document):
|
|||||||
|
|
||||||
self.delete_bins()
|
self.delete_bins()
|
||||||
self.delete_lead_addresses()
|
self.delete_lead_addresses()
|
||||||
|
self.reset_company_values()
|
||||||
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
|
|
||||||
clear_notifications()
|
clear_notifications()
|
||||||
|
self.delete_company_transactions()
|
||||||
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'])
|
|
||||||
|
|
||||||
def populate_doctypes_to_be_ignored_table(self):
|
def populate_doctypes_to_be_ignored_table(self):
|
||||||
doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
|
doctypes_to_be_ignored_list = get_doctypes_to_be_ignored()
|
||||||
@ -79,6 +38,111 @@ class TransactionDeletionRecord(Document):
|
|||||||
'doctype_name' : doctype
|
'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):
|
def update_naming_series(self, naming_series, doctype_name):
|
||||||
if '.' in naming_series:
|
if '.' in naming_series:
|
||||||
prefix, hashes = naming_series.rsplit('.', 1)
|
prefix, hashes = naming_series.rsplit('.', 1)
|
||||||
@ -107,32 +171,6 @@ class TransactionDeletionRecord(Document):
|
|||||||
|
|
||||||
frappe.delete_doc('Communication', communication_names, ignore_permissions=True)
|
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()
|
@frappe.whitelist()
|
||||||
def get_doctypes_to_be_ignored():
|
def get_doctypes_to_be_ignored():
|
||||||
doctypes_to_be_ignored_list = ['Account', 'Cost Center', 'Warehouse', 'Budget',
|
doctypes_to_be_ignored_list = ['Account', 'Cost Center', 'Warehouse', 'Budget',
|
||||||
|
Loading…
x
Reference in New Issue
Block a user