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