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.

256 lines
9.3 KiB

  1. # -*- coding: utf-8 -*-
  2. # Copyright 2018 Eficent Business and IT Consulting Services S.L.
  3. # License AGPL-3 - See http://www.gnu.org/licenses/agpl-3.0.html
  4. from openerp import api, fields, models, _
  5. from openerp.osv import fields as old_fields
  6. from openerp.exceptions import UserError
  7. class GDPRPartnerReport(models.TransientModel):
  8. _name = "gdpr.partner.report"
  9. _description = "GDPR Partner Report"
  10. company_id = fields.Many2one(
  11. comodel_name='res.company',
  12. string='Company',
  13. required=True,
  14. default=lambda self: self.env.user.company_id,
  15. )
  16. partner_id = fields.Many2one(
  17. comodel_name='res.partner',
  18. string='Partner',
  19. required=True,
  20. )
  21. table_ids = fields.Many2many(
  22. comodel_name='gdpr.partner.data',
  23. string='Models with related partner data',
  24. )
  25. @api.multi
  26. @api.onchange('partner_id')
  27. def _onchange_table_ids(self):
  28. self.ensure_one()
  29. for report in self:
  30. if report.partner_id:
  31. data = self._get_tables_from_partner(self.partner_id)
  32. names = self._get_table_names(data)
  33. tables = self.env['gdpr.partner.data']
  34. for name in sorted(names):
  35. vals = report._get_default_table(
  36. name=name,
  37. data=[t for t in data if t[0] == name and not t[5]],
  38. )
  39. if vals:
  40. tables |= self.env['gdpr.partner.data'].create(vals)
  41. report.table_ids = tables
  42. else:
  43. report.table_ids = self.env['gdpr.partner.data']
  44. return {
  45. 'domain': {
  46. 'table_ids': [
  47. ('id', 'in', report.table_ids.ids)],
  48. },
  49. }
  50. @api.onchange('company_id')
  51. def _onchange_company_id(self):
  52. if self.company_id:
  53. return {
  54. 'domain': {
  55. 'partner_id': [
  56. ('company_id', 'in', [self.company_id.id, False])],
  57. },
  58. }
  59. else:
  60. return {
  61. 'domain': {
  62. 'partner_id': [('company_id', '=', False)],
  63. },
  64. }
  65. @api.multi
  66. def button_export_pdf(self):
  67. self.ensure_one()
  68. return self.check_report()
  69. @api.multi
  70. def button_export_xlsx(self):
  71. self.ensure_one()
  72. return self.check_report(xlsx_report=True)
  73. def _build_contexts(self, data):
  74. result = {}
  75. result['partner_id'] = data['form']['partner_id'][0] or False
  76. result['company_id'] = data['form']['company_id'][0] or False
  77. result['table_ids'] = 'table_ids' in data['form'] and \
  78. data['form']['table_ids'] or False
  79. return result
  80. def _clean_data(self, model, rows):
  81. cleaned_rows = []
  82. for i, row in enumerate(rows):
  83. cleaned_rows.append({})
  84. for key, value in row.items():
  85. label = self.env[model]._fields[key].string or key
  86. if 'many2' in self.env[model]._fields[key].type:
  87. comodel = self.env[model]._fields[key].comodel_name
  88. if value:
  89. record = self.env[comodel].browse(value)
  90. cleaned_rows[i][label] = str(record.display_name)
  91. else:
  92. cleaned_rows[i][label] = rows[i][key]
  93. else:
  94. cleaned_rows[i][label] = rows[i][key]
  95. return cleaned_rows
  96. @api.multi
  97. def check_report(self, xlsx_report=False):
  98. self.ensure_one()
  99. data = {}
  100. data['ids'] = self.env.context.get('active_ids', [])
  101. data['model'] = self.env.context.get('active_model', 'ir.ui.menu')
  102. data['form'] = self.read(['partner_id', 'company_id', 'table_ids'])[0]
  103. used_context = self._build_contexts(data)
  104. data['form']['used_context'] = dict(
  105. used_context, lang=self.env.context.get('lang', 'en_US'))
  106. return self._print_report(data=data, xlsx_report=xlsx_report)
  107. @api.multi
  108. def compute_data_for_report(self, data):
  109. if not data.get('form'):
  110. raise UserError(
  111. _("Form content is missing, this report cannot be printed."))
  112. partner = data['form'].get('partner_id', False)
  113. if not partner:
  114. raise UserError(
  115. _("No provided partner."))
  116. partner = self.env['res.partner'].browse(partner[0])
  117. tables = data['form'].get('table_ids', False)
  118. if tables:
  119. tables = self.env['gdpr.partner.data'].browse(tables)
  120. tables = self._get_rows_from_tables(tables, partner)
  121. data.update({'tables': tables, })
  122. return data
  123. def _exclude_column(self, model, column):
  124. # To remove in v10:
  125. # (non-stored function fields should have _fnct_search)
  126. column_info = self.env[model]._columns.get(column)
  127. next_model = self.env[model]
  128. while not column_info and column in next_model._inherit_fields:
  129. next_model = self.env[next_model._inherit_fields[column][0]]
  130. column_info = next_model._columns.get(column)
  131. if isinstance(column_info, old_fields.function) \
  132. and not column_info.store and not column_info._fnct_search:
  133. return True
  134. # https://github.com/odoo/odoo/issues/24927
  135. if model in ('mail.compose.message', 'survey.mail.compose.message'):
  136. if column in ('needaction_partner_ids', 'starred_partner_ids'):
  137. return True
  138. return False
  139. def _get_default_table(self, name, data):
  140. if data:
  141. data_type = data[0][4]
  142. res = self.env[data[0][1]]
  143. for t in data:
  144. res |= self.env[t[1]].browse(t[3])
  145. if res:
  146. values = {
  147. 'name': name,
  148. 'model_id': self.env['ir.model'].search(
  149. [('model', '=', res._name)]).id,
  150. 'count_rows': len(res.ids),
  151. 'type': data_type,
  152. }
  153. return values
  154. return {}
  155. def _get_model_from_table(self, table, partner):
  156. new_tables = {}
  157. for model in table.model_id:
  158. rows = self._get_rows_from_model(model, partner)
  159. new_tables[str(model.display_name)] = rows
  160. return new_tables
  161. def _get_rows_from_model(self, model, partner):
  162. cr = self.env.cr
  163. lines = self.env[model.model]
  164. columns = [k for k, v in self.env[model.model]._fields.items()
  165. if v.comodel_name == 'res.partner' and
  166. not self._exclude_column(model.model, k)]
  167. for column in columns:
  168. lines |= self.env[model.model].search([(column, '=', partner.id)])
  169. line_ids = ', '.join([str(i) for i in lines.ids])
  170. query = "SELECT * FROM %s WHERE id IN (%s)" % (
  171. model.model.replace('.', '_'), line_ids)
  172. cr.execute(query)
  173. rows = cr.dictfetchall()
  174. rows = self._clean_data(model.model, rows)
  175. return rows
  176. def _get_rows_from_tables(self, tables, partner):
  177. new_tables = {}
  178. for table in tables:
  179. data_table = self._get_model_from_table(table, partner)
  180. new_tables[str(table.name)] = data_table
  181. return new_tables
  182. def _get_table_names(self, data):
  183. names = []
  184. for t in data:
  185. if t[3] and not t[5] and t[0] not in names:
  186. names.append(t[0])
  187. return names
  188. def _get_tables_from_partner(self, partner):
  189. tables = [t[0] for t in [
  190. [[self.env[m]._table, m, k, self.env[m].sudo().search(
  191. [(k, '=', partner.id)]).ids, v.type, self.env[m]._transient]
  192. for k, v in self.env[m]._fields.items()
  193. if v.comodel_name == 'res.partner' and self.env[m]._auto and
  194. not self._exclude_column(m, k)]
  195. for m in [x for x in self.env.registry.keys()]] if t]
  196. for i, t in enumerate(tables):
  197. if t[4] == 'many2many':
  198. if t[3]:
  199. relation = self.env[t[1]]._fields[t[2]].relation
  200. if relation:
  201. tables[i][0] = relation
  202. return tables
  203. def _print_report(self, data, xlsx_report=False):
  204. records = self.env[data['model']].browse(data.get('ids', []))
  205. processed_data = self.compute_data_for_report(data)
  206. if xlsx_report:
  207. kkk = self.env['report'].with_context(landscape=True).get_action(
  208. records=records, report_name='gdpr.report_partner_xlsx',
  209. data=processed_data)
  210. return kkk
  211. else:
  212. return self.env['report'].with_context(landscape=True).get_action(
  213. records=records, report_name='gdpr.report_partner',
  214. data=processed_data)
  215. class GDPRPartnerData(models.TransientModel):
  216. _name = "gdpr.partner.data"
  217. _description = "GDPR Partner Data"
  218. name = fields.Char(
  219. string='Database Table',
  220. )
  221. model_id = fields.Many2one(
  222. comodel_name='ir.model',
  223. ondelete='cascade',
  224. string='Models',
  225. )
  226. type = fields.Char(
  227. string="Type",
  228. )
  229. count_rows = fields.Integer(
  230. default=0,
  231. string='Number of lines',
  232. )