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.

303 lines
14 KiB

  1. # -*- coding: utf-8 -*-
  2. # © 2016 Serpent Consulting Services Pvt. Ltd. (support@serpentcs.com)
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. from lxml import etree
  5. import odoo.tools as tools
  6. from odoo import api, models
  7. class MassEditingWizard(models.TransientModel):
  8. _name = 'mass.editing.wizard'
  9. @api.model
  10. def fields_view_get(self, view_id=None, view_type='form', toolbar=False,
  11. submenu=False):
  12. result =\
  13. super(MassEditingWizard, self).fields_view_get(view_id=view_id,
  14. view_type=view_type,
  15. toolbar=toolbar,
  16. submenu=submenu)
  17. context = self._context
  18. if context.get('mass_editing_object'):
  19. mass_obj = self.env['mass.object']
  20. editing_data = mass_obj.browse(context.get('mass_editing_object'))
  21. all_fields = {}
  22. xml_form = etree.Element('form', {
  23. 'string': tools.ustr(editing_data.name)
  24. })
  25. xml_group = etree.SubElement(xml_form, 'group', {
  26. 'colspan': '6',
  27. 'col': '6',
  28. })
  29. etree.SubElement(xml_group, 'label', {
  30. 'string': '',
  31. 'colspan': '2',
  32. })
  33. xml_group = etree.SubElement(xml_form, 'group', {
  34. 'colspan': '6',
  35. 'col': '6',
  36. })
  37. model_obj = self.env[context.get('active_model')]
  38. field_info = model_obj.fields_get()
  39. for field in editing_data.field_ids:
  40. if field.ttype == "many2many":
  41. all_fields[field.name] = field_info[field.name]
  42. all_fields["selection__" + field.name] = {
  43. 'type': 'selection',
  44. 'string': field_info[field.name]['string'],
  45. 'selection': [('set', 'Set'),
  46. ('remove_m2m', 'Remove'),
  47. ('add', 'Add')]
  48. }
  49. xml_group = etree.SubElement(xml_group, 'group', {
  50. 'colspan': '6',
  51. 'col': '6',
  52. })
  53. etree.SubElement(xml_group, 'separator', {
  54. 'string': field_info[field.name]['string'],
  55. 'colspan': '6',
  56. })
  57. etree.SubElement(xml_group, 'field', {
  58. 'name': "selection__" + field.name,
  59. 'colspan': '6',
  60. 'nolabel': '1'
  61. })
  62. etree.SubElement(xml_group, 'field', {
  63. 'name': field.name,
  64. 'colspan': '6',
  65. 'nolabel': '1',
  66. 'attrs': ("{'invisible': [('selection__" +
  67. field.name + "', '=', 'remove_m2m')]}"),
  68. })
  69. elif field.ttype == "one2many":
  70. all_fields["selection__" + field.name] = {
  71. 'type': 'selection',
  72. 'string': field_info[field.name]['string'],
  73. 'selection': [('set', 'Set'), ('remove', 'Remove')],
  74. }
  75. all_fields[field.name] = {
  76. 'type': field.ttype,
  77. 'string': field.field_description,
  78. 'relation': field.relation,
  79. }
  80. etree.SubElement(xml_group, 'field', {
  81. 'name': "selection__" + field.name,
  82. 'colspan': '4',
  83. })
  84. etree.SubElement(xml_group, 'field', {
  85. 'name': field.name,
  86. 'colspan': '6',
  87. 'nolabel': '1',
  88. 'attrs': ("{'invisible':[('selection__" +
  89. field.name + "', '=', 'remove_o2m')]}"),
  90. })
  91. elif field.ttype == "many2one":
  92. all_fields["selection__" + field.name] = {
  93. 'type': 'selection',
  94. 'string': field_info[field.name]['string'],
  95. 'selection': [('set', 'Set'), ('remove', 'Remove')],
  96. }
  97. all_fields[field.name] = {
  98. 'type': field.ttype,
  99. 'string': field.field_description,
  100. 'relation': field.relation,
  101. }
  102. etree.SubElement(xml_group, 'field', {
  103. 'name': "selection__" + field.name,
  104. 'colspan': '2',
  105. })
  106. etree.SubElement(xml_group, 'field', {
  107. 'name': field.name,
  108. 'nolabel': '1',
  109. 'colspan': '4',
  110. 'attrs': ("{'invisible':[('selection__" +
  111. field.name + "', '=', 'remove')]}"),
  112. })
  113. elif field.ttype == "char":
  114. all_fields["selection__" + field.name] = {
  115. 'type': 'selection',
  116. 'string': field_info[field.name]['string'],
  117. 'selection': [('set', 'Set'), ('remove', 'Remove')],
  118. }
  119. all_fields[field.name] = {
  120. 'type': field.ttype,
  121. 'string': field.field_description,
  122. 'size': field.size or 256,
  123. }
  124. etree.SubElement(xml_group, 'field', {
  125. 'name': "selection__" + field.name,
  126. 'colspan': '2',
  127. })
  128. etree.SubElement(xml_group, 'field', {
  129. 'name': field.name,
  130. 'nolabel': '1',
  131. 'attrs': ("{'invisible':[('selection__" +
  132. field.name + "','=','remove')]}"),
  133. 'colspan': '4',
  134. })
  135. elif field.ttype == 'selection':
  136. all_fields["selection__" + field.name] = {
  137. 'type': 'selection',
  138. 'string': field_info[field.name]['string'],
  139. 'selection': [('set', 'Set'), ('remove', 'Remove')]
  140. }
  141. etree.SubElement(xml_group, 'field', {
  142. 'name': "selection__" + field.name,
  143. 'colspan': '2',
  144. })
  145. etree.SubElement(xml_group, 'field', {
  146. 'name': field.name,
  147. 'nolabel': '1',
  148. 'colspan': '4',
  149. 'attrs': ("{'invisible':[('selection__" +
  150. field.name + "', '=', 'remove')]}"),
  151. })
  152. all_fields[field.name] = {
  153. 'type': field.ttype,
  154. 'string': field.field_description,
  155. 'selection': field_info[field.name]['selection'],
  156. }
  157. else:
  158. all_fields[field.name] = {
  159. 'type': field.ttype,
  160. 'string': field.field_description,
  161. }
  162. all_fields["selection__" + field.name] = {
  163. 'type': 'selection',
  164. 'string': field_info[field.name]['string'],
  165. 'selection': [('set', 'Set'), ('remove', 'Remove')]
  166. }
  167. if field.ttype == 'text':
  168. xml_group = etree.SubElement(xml_group, 'group', {
  169. 'colspan': '6',
  170. 'col': '6',
  171. })
  172. etree.SubElement(xml_group, 'separator', {
  173. 'string': all_fields[field.name]['string'],
  174. 'colspan': '6',
  175. })
  176. etree.SubElement(xml_group, 'field', {
  177. 'name': "selection__" + field.name,
  178. 'colspan': '6',
  179. 'nolabel': '1',
  180. })
  181. etree.SubElement(xml_group, 'field', {
  182. 'name': field.name,
  183. 'colspan': '6',
  184. 'nolabel': '1',
  185. 'attrs': ("{'invisible':[('selection__" +
  186. field.name + "','=','remove')]}"),
  187. })
  188. else:
  189. all_fields["selection__" + field.name] = {
  190. 'type': 'selection',
  191. 'string': field_info[field.name]['string'],
  192. 'selection': [('set', 'Set'), ('remove', 'Remove')]
  193. }
  194. etree.SubElement(xml_group, 'field', {
  195. 'name': "selection__" + field.name,
  196. 'colspan': '2',
  197. })
  198. etree.SubElement(xml_group, 'field', {
  199. 'name': field.name,
  200. 'nolabel': '1',
  201. 'attrs': ("{'invisible':[('selection__" +
  202. field.name + "','=','remove')]}"),
  203. 'colspan': '4',
  204. })
  205. # Patch fields with required extra data
  206. for field in all_fields.values():
  207. field.setdefault("views", {})
  208. etree.SubElement(xml_form, 'separator', {
  209. 'string': '',
  210. 'colspan': '6',
  211. 'col': '6',
  212. })
  213. xml_group3 = etree.SubElement(xml_form, 'footer', {})
  214. etree.SubElement(xml_group3, 'button', {
  215. 'string': 'Apply',
  216. 'class': 'btn-primary',
  217. 'type': 'object',
  218. 'name': 'action_apply',
  219. })
  220. etree.SubElement(xml_group3, 'button', {
  221. 'string': 'Close',
  222. 'class': 'btn-default',
  223. 'special': 'cancel',
  224. })
  225. root = xml_form.getroottree()
  226. result['arch'] = etree.tostring(root)
  227. result['fields'] = all_fields
  228. return result
  229. @api.model
  230. def create(self, vals):
  231. if (self._context.get('active_model') and
  232. self._context.get('active_ids')):
  233. model_obj = self.env[self._context.get('active_model')]
  234. model_field_obj = self.env['ir.model.fields']
  235. translation_obj = self.env['ir.translation']
  236. values = {}
  237. for key, val in vals.items():
  238. if key.startswith('selection_'):
  239. split_key = key.split('__', 1)[1]
  240. if val == 'set':
  241. values.update({split_key: vals.get(split_key, False)})
  242. elif val == 'remove':
  243. values.update({split_key: False})
  244. # If field to remove is translatable,
  245. # its translations have to be removed
  246. model_field = model_field_obj.search([
  247. ('model', '=', self._context.get('active_model')),
  248. ('name', '=', split_key)])
  249. if model_field and model_field.translate:
  250. translation_ids = translation_obj.search([
  251. ('res_id', 'in', self._context.get(
  252. 'active_ids')),
  253. ('type', '=', 'model'),
  254. ('name', '=', u"{0},{1}".format(
  255. self._context.get('active_model'),
  256. split_key))])
  257. translation_ids.unlink()
  258. elif val == 'remove_m2m':
  259. m2m_list = []
  260. if vals.get(split_key):
  261. for m2m_id in vals.get(split_key)[0][2]:
  262. m2m_list.append((3, m2m_id))
  263. if m2m_list:
  264. values.update({split_key: m2m_list})
  265. else:
  266. values.update({split_key: [(5, 0, [])]})
  267. elif val == 'add':
  268. m2m_list = []
  269. for m2m_id in vals.get(split_key, False)[0][2]:
  270. m2m_list.append((4, m2m_id))
  271. values.update({split_key: m2m_list})
  272. if values:
  273. model_obj.browse(self._context.get('active_ids')).write(values)
  274. return super(MassEditingWizard, self).create({})
  275. @api.multi
  276. def action_apply(self):
  277. return {'type': 'ir.actions.act_window_close'}
  278. def read(self, fields, load='_classic_read'):
  279. """ Without this call, dynamic fields build by fields_view_get()
  280. generate a log warning, i.e.:
  281. odoo.models:mass.editing.wizard.read() with unknown field 'myfield'
  282. odoo.models:mass.editing.wizard.read()
  283. with unknown field 'selection__myfield'
  284. """
  285. real_fields = fields
  286. if fields:
  287. # We remove fields which are not in _fields
  288. real_fields = [x for x in fields if x in self._fields]
  289. result = super(MassEditingWizard, self).read(real_fields, load=load)
  290. # adding fields to result
  291. [result[0].update({x: False}) for x in fields if x not in real_fields]
  292. return result