feat: dependency syncing in mapped doctypes

This commit is contained in:
Rucha Mahabal 2020-03-18 00:52:14 +05:30
parent 1706f46b17
commit 85d6da6e2e
4 changed files with 74 additions and 38 deletions

View file

@ -7,15 +7,13 @@
"field_order": [
"local_fieldname",
"remote_fieldname",
"has_default_value",
"default_value",
"column_break_5",
"is_child_table",
"child_table_mapping"
"mapping_type",
"mapping"
],
"fields": [
{
"depends_on": "eval:!doc.has_default_value;",
"fieldname": "remote_fieldname",
"fieldtype": "Data",
"in_list_view": 1,
@ -28,40 +26,32 @@
"label": "Local Fieldname",
"reqd": 1
},
{
"default": "0",
"fieldname": "is_child_table",
"fieldtype": "Check",
"label": "Is Child Table"
},
{
"depends_on": "eval: doc.is_child_table == 1",
"fieldname": "child_table_mapping",
"fieldtype": "Link",
"label": "Child Table Mapping",
"options": "Document Type Mapping"
},
{
"fieldname": "column_break_5",
"fieldtype": "Column Break"
},
{
"default": "0",
"description": "Check this If the value of the field is a default value and not to be fetched from the remote DocType's field",
"fieldname": "has_default_value",
"fieldtype": "Check",
"label": "Has Default Value"
},
{
"depends_on": "eval:doc.has_default_value;",
"fieldname": "default_value",
"fieldtype": "Data",
"label": "Default Value"
},
{
"fieldname": "mapping_type",
"fieldtype": "Select",
"label": "Mapping Type",
"options": "\nChild Table\nDocument"
},
{
"depends_on": "eval:doc.mapping_type;",
"fieldname": "mapping",
"fieldtype": "Link",
"label": "Mapping",
"options": "Document Type Mapping"
}
],
"istable": 1,
"links": [],
"modified": "2020-03-16 13:42:41.104161",
"modified": "2020-03-16 14:54:33.546135",
"modified_by": "Administrator",
"module": "Event Streaming",
"name": "Document Type Field Mapping",

View file

@ -9,27 +9,52 @@ from frappe.model.document import Document
class DocumentTypeMapping(Document):
def get_mapped_doc(self, update):
doc = frappe._dict(json.loads(update))
def get_mapped_update(self, doc, producer_site):
remote_fields = []
# list of tuples (local_fieldname, dependent_doc)
dependencies = []
for mapping in self.field_mapping:
if doc.get(mapping.remote_fieldname):
if mapping.is_child_table:
doc[mapping.local_fieldname] = self.get_mapped_child_table_docs(mapping.child_table_mapping, doc[mapping.remote_fieldname])
if mapping.mapping_type == 'Document':
dependency = self.get_mapped_dependency(mapping, producer_site, doc.get(mapping.remote_fieldname), mapping.remote_fieldname)
dependencies.append((mapping.local_fieldname, dependency))
if mapping.mapping_type == 'Child Table':
doc[mapping.local_fieldname] = self.get_mapped_child_table_docs(mapping.child_table_mapping, doc[mapping.remote_fieldname])
else:
# copy value into local fieldname key and remove remote fieldname key
doc[mapping.local_fieldname] = doc[mapping.remote_fieldname]
remote_fields.append(mapping.remote_fieldname)
elif mapping.has_default_value:
if not doc.get(mapping.local_fieldname) and mapping.default_value:
doc[mapping.local_fieldname] = mapping.default_value
#remove the remote fieldnames
for field in remote_fields:
doc.pop(field, None)
doc['doctype'] = self.local_doctype
return frappe.as_json(doc)
mapped_update = {'doc': frappe.as_json(doc)}
if len(dependencies):
mapped_update['dependencies'] = dependencies
return mapped_update
def get_mapped_dependency(self, mapping, producer_site, dependent_field_val, dependent_field):
inner_mapping = frappe.get_doc('Document Type Mapping', mapping.mapping)
filters = {}
for pair in inner_mapping.field_mapping:
if pair.remote_fieldname == dependent_field:
filters[pair.remote_fieldname] = dependent_field_val
break
matching_docs = producer_site.get_doc(inner_mapping.remote_doctype, filters=filters)
if len(matching_docs):
remote_docname = matching_docs[0].get('name')
remote_doc = producer_site.get_doc(inner_mapping.remote_doctype, remote_docname)
doc = inner_mapping.get_mapped_update(remote_doc, producer_site).get('doc')
return doc
def get_mapped_child_table_docs(child_map, table_entries):

View file

@ -93,6 +93,7 @@ class EventProducer(Document):
if self.is_producer_online():
producer_site = get_producer_site(self.producer_url)
event_consumer = producer_site.get_doc('Event Consumer', get_url())
event_consumer = frappe._dict(event_consumer)
if event_consumer:
config = event_consumer.consumer_doctypes
event_consumer.consumer_doctypes = []
@ -172,7 +173,7 @@ def pull_from_node(event_producer):
mapping = mapping_config.get(update.ref_doctype)
if mapping:
update.mapping = mapping
update = get_mapped_update(update)
update = get_mapped_update(update, producer_site)
if not update.update_type == 'Delete':
update.data = json.loads(update.data)
@ -225,8 +226,13 @@ def set_insert(update, producer_site, event_producer):
return
doc = frappe.get_doc(update.data)
if not update.mapping:
if update.mapping:
dependencies_created = sync_mapped_dependencies(update.dependencies, producer_site)
for fieldname, value in iteritems(dependencies_created):
doc.update({ fieldname : value })
else:
sync_dependencies(doc, producer_site)
if update.use_same_name:
doc.insert(set_name=update.docname, set_child_names=False)
else:
@ -346,6 +352,7 @@ def sync_dependencies(document, producer_site):
child_table = doc.get(df.fieldname)
for entry in child_table:
child_doc = producer_site.get_doc(entry.doctype, entry.name)
child_doc = frappe._dict(child_doc)
set_dependencies(child_doc, frappe.get_meta(entry.doctype).get_link_fields(), producer_site)
def sync_link_dependencies(doc, link_fields, producer_site):
@ -397,6 +404,15 @@ def sync_dependencies(document, producer_site):
dependencies[document] = False
def sync_mapped_dependencies(dependencies, producer_site):
dependencies_created = {}
for entry in dependencies:
doc = frappe._dict(json.loads(entry[1]))
doc = frappe.get_doc(doc).insert(set_child_names=False)
dependencies_created[entry[0]] = doc.name
return dependencies_created
def log_event_sync(update, event_producer, sync_status, error=None):
"""Log event update received with the sync_status as Synced or Failed"""
doc = frappe.new_doc('Event Sync Log')
@ -417,11 +433,15 @@ def log_event_sync(update, event_producer, sync_status, error=None):
doc.insert()
def get_mapped_update(update):
def get_mapped_update(update, producer_site):
"""get the new update document with mapped fields"""
mapping = frappe.get_doc('Document Type Mapping', update.mapping)
if update.update_type != 'Delete':
update.data = mapping.get_mapped_doc(update.data)
doc = frappe._dict(json.loads(update.data))
mapped_update = mapping.get_mapped_update(doc, producer_site)
update.data = mapped_update.get('doc')
update.dependencies = mapped_update.get('dependencies', None)
update.ref_doctype = mapping.local_doctype
return update

View file

@ -199,8 +199,9 @@ class FrappeClient(object):
res = self.session.get(self.url + "/api/resource/" + doctype + "/" + name,
params=params, verify=self.verify, headers=self.headers)
print('==================res', res.text, filters)
return frappe._dict(self.post_process(res))
return self.post_process(res)
def rename_doc(self, doctype, old_name, new_name):
'''Rename remote document