Nie możesz wybrać więcej, niż 25 tematów Tematy muszą się zaczynać od litery lub cyfry, mogą zawierać myślniki ('-') i mogą mieć do 35 znaków.
 
 
 
 
 
 

229 wiersze
7.3 KiB

  1. # Copyright (c) 2015, Frappe Technologies Pvt. Ltd. and Contributors
  2. # MIT License. See license.txt
  3. from __future__ import unicode_literals, print_function
  4. """
  5. Utilities for using modules
  6. """
  7. import frappe, os, json
  8. import frappe.utils
  9. from frappe import _
  10. lower_case_files_for = ['DocType', 'Page', 'Report',
  11. "Workflow", 'Module Def', 'Desktop Item', 'Workflow State', 'Workflow Action', 'Print Format',
  12. "Website Theme", 'Web Form', 'Email Alert']
  13. def export_module_json(doc, is_standard, module):
  14. """Make a folder for the given doc and add its json file (make it a standard
  15. object that will be synced)"""
  16. if (not frappe.flags.in_import and getattr(frappe.get_conf(),'developer_mode', 0)
  17. and is_standard):
  18. from frappe.modules.export_file import export_to_files
  19. # json
  20. export_to_files(record_list=[[doc.doctype, doc.name]], record_module=module)
  21. path = os.path.join(frappe.get_module_path(module), scrub(doc.doctype),
  22. scrub(doc.name), scrub(doc.name))
  23. return path
  24. def get_doc_module(module, doctype, name):
  25. """Get custom module for given document"""
  26. module_name = "{app}.{module}.{doctype}.{name}.{name}".format(
  27. app = frappe.local.module_app[scrub(module)],
  28. doctype = scrub(doctype),
  29. module = scrub(module),
  30. name = scrub(name)
  31. )
  32. return frappe.get_module(module_name)
  33. @frappe.whitelist()
  34. def export_customizations(module, doctype, sync_on_migrate=0, with_permissions=0):
  35. """Export Custom Field and Property Setter for the current document to the app folder.
  36. This will be synced with bench migrate"""
  37. if not frappe.get_conf().developer_mode:
  38. raise Exception('Not developer mode')
  39. custom = {'custom_fields': [], 'property_setters': [], 'custom_perms': [],
  40. 'doctype': doctype, 'sync_on_migrate': 1}
  41. def add(_doctype):
  42. custom['custom_fields'] += frappe.get_all('Custom Field',
  43. fields='*', filters={'dt': _doctype})
  44. custom['property_setters'] += frappe.get_all('Property Setter',
  45. fields='*', filters={'doc_type': _doctype})
  46. add(doctype)
  47. if with_permissions:
  48. custom['custom_perms'] = frappe.get_all('Custom DocPerm',
  49. fields='*', filters={'parent': doctype})
  50. # add custom fields and property setters for all child tables
  51. for d in frappe.get_meta(doctype).get_table_fields():
  52. add(d.options)
  53. folder_path = os.path.join(get_module_path(module), 'custom')
  54. if not os.path.exists(folder_path):
  55. os.makedirs(folder_path)
  56. path = os.path.join(folder_path, scrub(doctype)+ '.json')
  57. with open(path, 'w') as f:
  58. f.write(frappe.as_json(custom))
  59. frappe.msgprint(_('Customizations exported to {0}').format(path))
  60. def sync_customizations(app=None):
  61. '''Sync custom fields and property setters from custom folder in each app module'''
  62. if app:
  63. apps = [app]
  64. else:
  65. apps = frappe.get_installed_apps()
  66. for app_name in apps:
  67. for module_name in frappe.local.app_modules.get(app_name) or []:
  68. folder = frappe.get_app_path(app_name, module_name, 'custom')
  69. if os.path.exists(folder):
  70. for fname in os.listdir(folder):
  71. with open(os.path.join(folder, fname), 'r') as f:
  72. data = json.loads(f.read())
  73. if data.get('sync_on_migrate'):
  74. sync_customizations_for_doctype(data)
  75. def sync_customizations_for_doctype(data):
  76. '''Sync doctype customzations for a particular data set'''
  77. from frappe.core.doctype.doctype.doctype import validate_fields_for_doctype
  78. doctype = data['doctype']
  79. update_schema = False
  80. def sync(key, custom_doctype, doctype_fieldname):
  81. frappe.db.sql('delete from `tab{0}` where `{1}`=%s'.format(custom_doctype, doctype_fieldname),
  82. doctype)
  83. for d in data[key]:
  84. d['doctype'] = custom_doctype
  85. doc = frappe.get_doc(d)
  86. doc.db_insert()
  87. if data['custom_fields']:
  88. sync('custom_fields', 'Custom Field', 'dt')
  89. update_schema = True
  90. if data['property_setters']:
  91. sync('property_setters', 'Property Setter', 'doc_type')
  92. if data.get('custom_perms'):
  93. sync('custom_perms', 'Custom DocPerm', 'parent')
  94. print('Updating customizations for {0}'.format(doctype))
  95. validate_fields_for_doctype(doctype)
  96. if update_schema and not frappe.db.get_value('DocType', doctype, 'issingle'):
  97. from frappe.model.db_schema import updatedb
  98. updatedb(doctype)
  99. def scrub(txt):
  100. return frappe.scrub(txt)
  101. def scrub_dt_dn(dt, dn):
  102. """Returns in lowercase and code friendly names of doctype and name for certain types"""
  103. ndt, ndn = dt, dn
  104. if dt in lower_case_files_for:
  105. ndt, ndn = scrub(dt), scrub(dn)
  106. return ndt, ndn
  107. def get_module_path(module):
  108. """Returns path of the given module"""
  109. return frappe.get_module_path(module)
  110. def get_doc_path(module, doctype, name):
  111. dt, dn = scrub_dt_dn(doctype, name)
  112. return os.path.join(get_module_path(module), dt, dn)
  113. def reload_doc(module, dt=None, dn=None, force=False, reset_permissions=False):
  114. from frappe.modules.import_file import import_files
  115. return import_files(module, dt, dn, force=force, reset_permissions=reset_permissions)
  116. def export_doc(doctype, name, module=None):
  117. """Write a doc to standard path."""
  118. from frappe.modules.export_file import write_document_file
  119. print(doctype, name)
  120. if not module: module = frappe.db.get_value('DocType', name, 'module')
  121. write_document_file(frappe.get_doc(doctype, name), module)
  122. def get_doctype_module(doctype):
  123. """Returns **Module Def** name of given doctype."""
  124. def make_modules_dict():
  125. return dict(frappe.db.sql("select name, module from tabDocType"))
  126. return frappe.cache().get_value("doctype_modules", make_modules_dict)[doctype]
  127. doctype_python_modules = {}
  128. def load_doctype_module(doctype, module=None, prefix="", suffix=""):
  129. """Returns the module object for given doctype."""
  130. if not module:
  131. module = get_doctype_module(doctype)
  132. app = get_module_app(module)
  133. key = (app, doctype, prefix, suffix)
  134. module_name = get_module_name(doctype, module, prefix, suffix)
  135. try:
  136. if key not in doctype_python_modules:
  137. doctype_python_modules[key] = frappe.get_module(module_name)
  138. except ImportError, e:
  139. raise ImportError('Module import failed for {0} ({1})'.format(doctype, module_name + ' Error: ' + str(e)))
  140. return doctype_python_modules[key]
  141. def get_module_name(doctype, module, prefix="", suffix="", app=None):
  142. return '{app}.{module}.doctype.{doctype}.{prefix}{doctype}{suffix}'.format(\
  143. app = scrub(app or get_module_app(module)),
  144. module = scrub(module),
  145. doctype = scrub(doctype),
  146. prefix=prefix,
  147. suffix=suffix)
  148. def get_module_app(module):
  149. return frappe.local.module_app[scrub(module)]
  150. def get_app_publisher(module):
  151. app = frappe.local.module_app[scrub(module)]
  152. if not app:
  153. frappe.throw(_("App not found"))
  154. app_publisher = frappe.get_hooks(hook="app_publisher", app_name=app)[0]
  155. return app_publisher
  156. def make_boilerplate(template, doc, opts=None):
  157. target_path = get_doc_path(doc.module, doc.doctype, doc.name)
  158. template_name = template.replace("controller", scrub(doc.name))
  159. target_file_path = os.path.join(target_path, template_name)
  160. if not doc: doc = {}
  161. app_publisher = get_app_publisher(doc.module)
  162. if not os.path.exists(target_file_path):
  163. if not opts:
  164. opts = {}
  165. with open(target_file_path, 'w') as target:
  166. with open(os.path.join(get_module_path("core"), "doctype", scrub(doc.doctype),
  167. "boilerplate", template), 'r') as source:
  168. target.write(frappe.utils.encode(
  169. frappe.utils.cstr(source.read()).format(
  170. app_publisher=app_publisher,
  171. year=frappe.utils.nowdate()[:4],
  172. classname=doc.name.replace(" ", ""),
  173. doctype=doc.name, **opts)
  174. ))