OCA reporting engine fork for dev and update.
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.

171 lines
5.6 KiB

  1. # Copyright 2017-2018 Onestein (<http://www.onestein.eu>)
  2. # License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl).
  3. import logging
  4. from odoo import SUPERUSER_ID
  5. from odoo import _, api, models, modules, tools
  6. from odoo.exceptions import UserError
  7. from odoo.tools import (existing_tables, topological_sort)
  8. _logger = logging.getLogger(__name__)
  9. @api.model
  10. def _bi_view(_name):
  11. return _name[0:6] == 'x_bve.'
  12. def check_tables_exist(self, cr):
  13. """
  14. Verify that all tables are present and try to initialize
  15. those that are missing.
  16. """
  17. # This monkey patch is meant to avoid that the _logger writes
  18. # warning and error messages, while running an update all,
  19. # in case the model is a bi-view-generated model.
  20. env = api.Environment(cr, SUPERUSER_ID, {})
  21. table2model = {
  22. model._table: name for name, model in env.items()
  23. if not model._abstract and not _bi_view(name) # here is the patch
  24. }
  25. missing_tables = set(table2model).difference(
  26. existing_tables(cr, table2model))
  27. if missing_tables:
  28. missing = {table2model[table] for table in missing_tables}
  29. _logger.warning("Models have no table: %s.", ", ".join(missing))
  30. # recreate missing tables following model dependencies
  31. deps = {name: model._depends for name, model in env.items()}
  32. for name in topological_sort(deps):
  33. if name in missing:
  34. _logger.info("Recreate table of model %s.", name)
  35. env[name].init()
  36. # check again, and log errors if tables are still missing
  37. missing_tables = set(table2model).difference(
  38. existing_tables(cr, table2model))
  39. for table in missing_tables:
  40. _logger.error("Model %s has no table.", table2model[table])
  41. modules.registry.Registry.check_tables_exist = check_tables_exist
  42. @api.model_cr_context
  43. def _auto_init(self):
  44. """ Initialize the database schema of ``self``:
  45. - create the corresponding table,
  46. - create/update the necessary columns/tables for fields,
  47. - initialize new columns on existing rows,
  48. - add the SQL constraints given on the model,
  49. - add the indexes on indexed fields,
  50. Also prepare post-init stuff to:
  51. - add foreign key constraints,
  52. - reflect models, fields, relations and constraints,
  53. - mark fields to recompute on existing records.
  54. Note: you should not override this method. Instead, you can modify
  55. the model's database schema by overriding method :meth:`~.init`,
  56. which is called right after this one.
  57. """
  58. # This monkey patch is meant to fix an error (probably
  59. # introduced by https://github.com/odoo/odoo/pull/15412), while
  60. # running an update all. The _auto_init() method invoked during
  61. # an update all is the one of BaseModel, and not the one of Base.
  62. # START OF patch
  63. if _bi_view(self._name):
  64. return
  65. # END of patch
  66. models.raise_on_invalid_object_name(self._name)
  67. # This prevents anything called by this method (in particular default
  68. # values) from prefetching a field for which the corresponding column
  69. # has not been added in database yet!
  70. self = self.with_context(prefetch_fields=False)
  71. self.pool.post_init(self._reflect)
  72. cr = self._cr
  73. parent_store_compute = False
  74. update_custom_fields = self._context.get('update_custom_fields', False)
  75. must_create_table = not tools.table_exists(cr, self._table)
  76. if self._auto:
  77. if must_create_table:
  78. tools.create_model_table(cr, self._table, self._description)
  79. if self._parent_store:
  80. if not tools.column_exists(cr, self._table, 'parent_left'):
  81. self._create_parent_columns()
  82. parent_store_compute = True
  83. self._check_removed_columns(log=False)
  84. # update the database schema for fields
  85. columns = tools.table_columns(cr, self._table)
  86. def recompute(field):
  87. _logger.info("Storing computed values of %s", field)
  88. recs = self.with_context(active_test=False).search([])
  89. recs._recompute_todo(field)
  90. for field in self._fields.values():
  91. if not field.store:
  92. continue
  93. if field.manual and not update_custom_fields:
  94. continue # don't update custom fields
  95. new = field.update_db(self, columns)
  96. if new and field.compute:
  97. self.pool.post_init(recompute, field)
  98. if self._auto:
  99. self._add_sql_constraints()
  100. if must_create_table:
  101. self._execute_sql()
  102. if parent_store_compute:
  103. self._parent_store_compute()
  104. models.BaseModel._auto_init = _auto_init
  105. class Base(models.AbstractModel):
  106. _inherit = 'base'
  107. @api.model
  108. def _auto_init(self):
  109. if not _bi_view(self._name):
  110. super(Base, self)._auto_init()
  111. @api.model
  112. def _setup_complete(self):
  113. if not _bi_view(self._name):
  114. super(Base, self)._setup_complete()
  115. else:
  116. self.pool.models[self._name]._log_access = False
  117. @api.model
  118. def _read_group_process_groupby(self, gb, query):
  119. if not _bi_view(self._name):
  120. return super(Base, self)._read_group_process_groupby(gb, query)
  121. split = gb.split(':')
  122. if split[0] not in self._fields:
  123. raise UserError(
  124. _('No data to be displayed.'))
  125. return super(Base, self)._read_group_process_groupby(gb, query)
  126. @api.model
  127. def _add_magic_fields(self):
  128. if _bi_view(self._name):
  129. self._log_access = False
  130. return super(Base, self)._add_magic_fields()