GoodERP
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 lines
7.7KB

  1. # -*- coding: utf-8 -*-
  2. from odoo import _
  3. from odoo.http import request
  4. import itertools
  5. import operator
  6. import time
  7. import pickle
  8. from odoo import models, api
  9. from odoo.exceptions import UserError
  10. from functools import reduce
  11. class ReportBase(models.Model):
  12. _name = 'report.base'
  13. _description = '使用search_read来直接生成数据的基本类,其他类可以直接异名继承当前类来重用搜索、过滤、分组等函数'
  14. _expired_time = 60
  15. _cache_record = False
  16. _cache_env = False
  17. _cache_time = False
  18. def select_sql(self, sql_type='out'):
  19. return ''
  20. def from_sql(self, sql_type='out'):
  21. return ''
  22. def where_sql(self, sql_type='out'):
  23. return ''
  24. def group_sql(self, sql_type='out'):
  25. return ''
  26. def order_sql(self, sql_type='out'):
  27. return ''
  28. def get_context(self, sql_type='out', context=None):
  29. return {}
  30. def execute_sql(self, sql_type='out'):
  31. context = self.get_context(sql_type, context=self.env.context)
  32. for key, value in list(context.items()):
  33. if key == "date_end":
  34. continue
  35. if key == "date_start":
  36. continue
  37. if isinstance(context[key], str):
  38. context[key] = value.encode('utf-8')
  39. search_sql = (self.select_sql(sql_type) + self.from_sql(sql_type) + self.where_sql(
  40. sql_type) + self.group_sql(sql_type) + self.order_sql(
  41. sql_type)).format(**context)
  42. self.env.cr.execute(search_sql)
  43. return self.env.cr.dictfetchall()
  44. def collect_data_by_sql(self, sql_type='out'):
  45. return []
  46. def check_valid_domain(self, domain):
  47. if not isinstance(domain, (list, tuple)):
  48. raise UserError(_('不可识别的domain条件,请检查domain"%s"是否正确') % str(domain))
  49. def _get_next_domain(self, domains, index):
  50. domain = domains[index]
  51. if domain == '|':
  52. _, index = self.get_next_or_domain(domains, index + 1)
  53. else:
  54. index += 1
  55. if domain != '&':
  56. self.check_valid_domain(domain)
  57. return index
  58. def get_next_or_domain(self, domains, index):
  59. index = self._get_next_domain(domains, index)
  60. return index, self._get_next_domain(domains, index)
  61. def _process_domain(self, result, domain):
  62. if domain and len(domain) == 3:
  63. field, opto, value = domain
  64. compute_operator = {
  65. 'ilike': lambda field, value: value.lower() in field.lower(),
  66. 'like': lambda field, value: value in field,
  67. 'not ilike': lambda field, value: value.lower() not in field.lower(),
  68. 'not like': lambda field, value: value not in field,
  69. 'in': lambda field, value: field in value,
  70. 'not in': lambda field, value: field not in value,
  71. '=': operator.eq,
  72. '!=': operator.ne,
  73. '>': operator.gt,
  74. '<': operator.lt,
  75. '>=': operator.ge,
  76. '<=': operator.le,
  77. }
  78. opto = opto.lower()
  79. if field in result:
  80. if opto in compute_operator.keys():
  81. return compute_operator.get(opto)(result.get(field), value)
  82. raise UserError(_('暂时无法解析的domain条件%s,请联系管理员') % str(domain))
  83. raise UserError(_('不可识别的domain条件,请检查domain"%s"是否正确') % str(domain))
  84. def _compute_domain_util(self, result, domains):
  85. index = 0
  86. while index < len(domains):
  87. domain = domains[index]
  88. index += 1
  89. if domain == '|':
  90. left_index, right_index = self.get_next_or_domain(
  91. domains, index)
  92. if not self._compute_domain_util(result, domains[index:left_index]) and not self._compute_domain_util(
  93. result, domains[left_index:right_index]):
  94. return False
  95. index = right_index
  96. else:
  97. if domain == '&':
  98. continue
  99. self.check_valid_domain(domain)
  100. if not self._process_domain(result, domain):
  101. return False
  102. return True
  103. def _compute_domain(self, result, domain):
  104. return list(filter(lambda res: self._compute_domain_util(res, domain), result))
  105. @api.model
  106. def read_group(self, domain, fields, groupby, offset=0, limit=65535, orderby=False, lazy=True):
  107. def dict_plus(collect, values):
  108. for key, value in values.items():
  109. if isinstance(value, (int, float)):
  110. if key not in collect:
  111. collect[key] = 0
  112. collect[key] += value
  113. collect[groupby[0] + '_count'] += 1
  114. return collect
  115. res = []
  116. values = self.search_read(
  117. domain=domain, fields=fields, offset=offset, limit=limit or 65535, order=orderby)
  118. if groupby:
  119. key = operator.itemgetter(groupby[0])
  120. for group, itervalue in itertools.groupby(sorted(values, key=key), key):
  121. collect = {'__domain': [
  122. (groupby[0], '=', group)], groupby[0]: group, groupby[0] + '_count': 0}
  123. collect = reduce(lambda collect, value: dict_plus(
  124. collect, value), itervalue, collect)
  125. if len(groupby) > 1:
  126. collect.update({
  127. '__context': {'group_by': groupby[1:]}
  128. })
  129. if domain:
  130. collect['__domain'].extend(domain)
  131. res.append(collect)
  132. return res
  133. def _compute_order(self, result, order):
  134. """暂时不支持多重排序"""
  135. if order:
  136. order = order.partition(',')[0].partition(' ')
  137. for line in result:
  138. if line.get(order[0]) is False:
  139. line.update({order[0]: ''})
  140. result.sort(key=lambda item: item.get(
  141. order[0]), reverse=order[2] == 'ASC')
  142. return result
  143. def _compute_limit_and_offset(self, result, limit, offset):
  144. return list(result)[offset:limit + offset]
  145. def update_result_none_to_false(self, result):
  146. for val in result:
  147. for key, value in val.items():
  148. if value is None:
  149. val[key] = False
  150. return result
  151. def get_data_from_cache(self, sql_type='out'):
  152. # These rows depend on mutable ledger data. A class-level cache can
  153. # outlive its transaction and be mutated by a caller's sorting/edits.
  154. # Cursor caches also ignore savepoints, so query the current transaction
  155. # afresh rather than sharing financial report rows across requests.
  156. return self.update_result_none_to_false(self.collect_data_by_sql(sql_type))
  157. @api.model
  158. def search_read(self, domain=None, fields=None, offset=0, limit=65535, order=None):
  159. result = self.get_data_from_cache(sql_type='out')
  160. result = self._compute_domain(result, domain)
  161. result = self._compute_order(result, order)
  162. result = self._compute_limit_and_offset(result, limit, offset)
  163. return result
  164. @api.model
  165. def search_count(self, domain):
  166. result = self.get_data_from_cache(sql_type='out')
  167. result = self._compute_domain(result, domain)
  168. return len(list(result))
  169. def read(self, fields=None, context=None, load='_classic_read'):
  170. res = []
  171. fields = fields or []
  172. fields.append('id')
  173. for record in self.get_data_from_cache():
  174. if record.get('id') in self.ids:
  175. res.append({field: record.get(field) for field in fields})
  176. return res
上海开阖软件有限公司 沪ICP备12045867号-1