You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

194 regels
6.5 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals
  4. import frappe, json
  5. from frappe import _
  6. from frappe.utils import cstr
  7. from frappe.model import default_fields
  8. @frappe.whitelist()
  9. def make_mapped_doc(method, source_name, selected_children=None):
  10. '''Returns the mapped document calling the given mapper method.
  11. Sets selected_children as flags for the `get_mapped_doc` method.
  12. Called from `open_mapped_doc` from create_new.js'''
  13. method = frappe.get_attr(method)
  14. if method not in frappe.whitelisted:
  15. raise frappe.PermissionError
  16. if selected_children:
  17. selected_children = json.loads(selected_children)
  18. frappe.flags.selected_children = selected_children or None
  19. return method(source_name)
  20. def get_mapped_doc(from_doctype, from_docname, table_maps, target_doc=None,
  21. postprocess=None, ignore_permissions=False, ignore_child_tables=False):
  22. source_doc = frappe.get_doc(from_doctype, from_docname)
  23. if not ignore_permissions:
  24. if not source_doc.has_permission("read"):
  25. source_doc.raise_no_permission_to("read")
  26. # main
  27. if not target_doc:
  28. target_doc = frappe.new_doc(table_maps[from_doctype]["doctype"])
  29. elif isinstance(target_doc, basestring):
  30. target_doc = frappe.get_doc(json.loads(target_doc))
  31. if not ignore_permissions and not target_doc.has_permission("create"):
  32. target_doc.raise_no_permission_to("create")
  33. map_doc(source_doc, target_doc, table_maps[source_doc.doctype])
  34. row_exists_for_parentfield = {}
  35. # children
  36. if not ignore_child_tables:
  37. for df in source_doc.meta.get_table_fields():
  38. source_child_doctype = df.options
  39. table_map = table_maps.get(source_child_doctype)
  40. # if table_map isn't explicitly specified check if both source and target have the same fieldname and same table options and both of them don't have no_copy
  41. if not table_map:
  42. target_df = target_doc.meta.get_field(df.fieldname)
  43. if target_df:
  44. target_child_doctype = target_df.options
  45. if target_df and target_child_doctype==source_child_doctype and not df.no_copy and not target_df.no_copy:
  46. table_map = {
  47. "doctype": target_child_doctype
  48. }
  49. if table_map:
  50. for source_d in source_doc.get(df.fieldname):
  51. if "condition" in table_map:
  52. if not table_map["condition"](source_d):
  53. continue
  54. # if children are selected (checked from UI) for this table type,
  55. # and this record is not in the selected children, then continue
  56. if (frappe.flags.selected_children
  57. and (df.fieldname in frappe.flags.selected_children)
  58. and source_d.name not in frappe.flags.selected_children[df.fieldname]):
  59. continue
  60. target_child_doctype = table_map["doctype"]
  61. target_parentfield = target_doc.get_parentfield_of_doctype(target_child_doctype)
  62. # does row exist for a parentfield?
  63. if target_parentfield not in row_exists_for_parentfield:
  64. row_exists_for_parentfield[target_parentfield] = (True
  65. if target_doc.get(target_parentfield) else False)
  66. if table_map.get("add_if_empty") and \
  67. row_exists_for_parentfield.get(target_parentfield):
  68. continue
  69. if table_map.get("filter") and table_map.get("filter")(source_d):
  70. continue
  71. map_child_doc(source_d, target_doc, table_map, source_doc)
  72. if postprocess:
  73. postprocess(source_doc, target_doc)
  74. target_doc.set_onload("load_after_mapping", True)
  75. return target_doc
  76. def map_doc(source_doc, target_doc, table_map, source_parent=None):
  77. if table_map.get("validation"):
  78. for key, condition in table_map["validation"].items():
  79. if condition[0]=="=":
  80. if source_doc.get(key) != condition[1]:
  81. frappe.throw(_("Cannot map because following condition fails: ")
  82. + key + "=" + cstr(condition[1]))
  83. map_fields(source_doc, target_doc, table_map, source_parent)
  84. if "postprocess" in table_map:
  85. table_map["postprocess"](source_doc, target_doc, source_parent)
  86. def map_fields(source_doc, target_doc, table_map, source_parent):
  87. no_copy_fields = set([d.fieldname for d in source_doc.meta.get("fields") if (d.no_copy==1 or d.fieldtype=="Table")]
  88. + [d.fieldname for d in target_doc.meta.get("fields") if (d.no_copy==1 or d.fieldtype=="Table")]
  89. + list(default_fields)
  90. + list(table_map.get("field_no_map", [])))
  91. for df in target_doc.meta.get("fields"):
  92. if df.fieldname not in no_copy_fields:
  93. # map same fields
  94. val = source_doc.get(df.fieldname)
  95. if val not in (None, ""):
  96. target_doc.set(df.fieldname, val)
  97. elif df.fieldtype == "Link":
  98. if not target_doc.get(df.fieldname):
  99. # map link fields having options == source doctype
  100. if df.options == source_doc.doctype:
  101. target_doc.set(df.fieldname, source_doc.name)
  102. elif source_parent and df.options == source_parent.doctype:
  103. target_doc.set(df.fieldname, source_parent.name)
  104. # map other fields
  105. field_map = table_map.get("field_map")
  106. if field_map:
  107. if isinstance(field_map, dict):
  108. for source_key, target_key in field_map.items():
  109. val = source_doc.get(source_key)
  110. if val not in (None, ""):
  111. target_doc.set(target_key, val)
  112. else:
  113. for fmap in field_map:
  114. val = source_doc.get(fmap[0])
  115. if val not in (None, ""):
  116. target_doc.set(fmap[1], val)
  117. # map idx
  118. if source_doc.idx:
  119. target_doc.idx = source_doc.idx
  120. # add fetch
  121. for df in target_doc.meta.get("fields", {"fieldtype": "Link"}):
  122. if target_doc.get(df.fieldname):
  123. map_fetch_fields(target_doc, df, no_copy_fields)
  124. def map_fetch_fields(target_doc, df, no_copy_fields):
  125. linked_doc = None
  126. # options should be like "link_fieldname.fieldname_in_liked_doc"
  127. for fetch_df in target_doc.meta.get("fields", {"options": "^{0}.".format(df.fieldname)}):
  128. if not (fetch_df.fieldtype == "Read Only" or fetch_df.read_only):
  129. continue
  130. if not target_doc.get(fetch_df.fieldname) and fetch_df.fieldname not in no_copy_fields:
  131. source_fieldname = fetch_df.options.split(".")[1]
  132. if not linked_doc:
  133. try:
  134. linked_doc = frappe.get_doc(df.options, target_doc.get(df.fieldname))
  135. except:
  136. return
  137. val = linked_doc.get(source_fieldname)
  138. if val not in (None, ""):
  139. target_doc.set(fetch_df.fieldname, val)
  140. def map_child_doc(source_d, target_parent, table_map, source_parent=None):
  141. target_child_doctype = table_map["doctype"]
  142. target_parentfield = target_parent.get_parentfield_of_doctype(target_child_doctype)
  143. target_d = frappe.new_doc(target_child_doctype, target_parent, target_parentfield)
  144. map_doc(source_d, target_d, table_map, source_parent)
  145. target_d.idx = None
  146. target_parent.append(target_parentfield, target_d)
  147. return target_d