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.

188 lines
6.3 KiB

  1. # -*- coding: utf-8 -*-
  2. # © 2011 Raphaël Valyi, Renato Lima, Guewen Baconnier, Sodexis
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  4. import time
  5. from openerp import api, models, fields
  6. from openerp.exceptions import Warning
  7. from openerp.tools.safe_eval import safe_eval
  8. from openerp.tools.translate import _
  9. class SaleException(models.Model):
  10. _name = 'sale.exception'
  11. _description = "Sale Exceptions"
  12. _order = 'active desc, sequence asc'
  13. name = fields.Char('Exception Name', required=True, translate=True)
  14. description = fields.Text('Description', translate=True)
  15. sequence = fields.Integer(
  16. string='Sequence',
  17. help="Gives the sequence order when applying the test")
  18. model = fields.Selection(
  19. [('sale.order', 'Sale Order'),
  20. ('sale.order.line', 'Sale Order Line')],
  21. string='Apply on', required=True)
  22. active = fields.Boolean('Active')
  23. code = fields.Text(
  24. 'Python Code',
  25. help="Python code executed to check if the exception apply or "
  26. "not. The code must apply block = True to apply the "
  27. "exception.",
  28. default="""
  29. # Python code. Use failed = True to block the sale order.
  30. # You can use the following variables :
  31. # - self: ORM model of the record which is checked
  32. # - order or line: browse_record of the sale order or sale order line
  33. # - object: same as order or line, browse_record of the sale order or
  34. # sale order line
  35. # - pool: ORM model pool (i.e. self.pool)
  36. # - time: Python time module
  37. # - cr: database cursor
  38. # - uid: current user id
  39. # - context: current context
  40. """)
  41. sale_order_ids = fields.Many2many(
  42. 'sale.order',
  43. 'sale_order_exception_rel', 'exception_id', 'sale_order_id',
  44. string='Sale Orders',
  45. readonly=True)
  46. class SaleOrder(models.Model):
  47. _inherit = 'sale.order'
  48. _order = 'main_exception_id asc, date_order desc, name desc'
  49. main_exception_id = fields.Many2one(
  50. 'sale.exception',
  51. compute='_get_main_error',
  52. string='Main Exception',
  53. store=True)
  54. exception_ids = fields.Many2many(
  55. 'sale.exception',
  56. 'sale_order_exception_rel', 'sale_order_id', 'exception_id',
  57. string='Exceptions')
  58. ignore_exceptions = fields.Boolean('Ignore Exceptions', copy=False)
  59. @api.one
  60. @api.depends('state', 'exception_ids')
  61. def _get_main_error(self):
  62. if self.state == 'draft' and self.exception_ids:
  63. self.main_exception_id = self.exception_ids[0]
  64. else:
  65. self.main_exception_id = False
  66. @api.model
  67. def test_all_draft_orders(self):
  68. order_set = self.search([('state', '=', 'draft')])
  69. order_set.test_exceptions()
  70. return True
  71. @api.multi
  72. def _popup_exceptions(self):
  73. action = self.env.ref('sale_exception.action_sale_exception_confirm')
  74. action = action.read()[0]
  75. action.update({
  76. 'context': {
  77. 'active_id': self.ids[0],
  78. 'active_ids': self.ids
  79. }
  80. })
  81. return action
  82. @api.multi
  83. def action_confirm(self):
  84. if self.detect_exceptions():
  85. return self._popup_exceptions()
  86. else:
  87. return super(SaleOrder, self).action_confirm()
  88. @api.multi
  89. def action_cancel(self):
  90. for order in self:
  91. if order.ignore_exceptions:
  92. order.ignore_exceptions = False
  93. return super(SaleOrder, self).action_cancel()
  94. @api.multi
  95. def test_exceptions(self):
  96. """
  97. Condition method for the workflow from draft to confirm
  98. """
  99. if self.detect_exceptions():
  100. return False
  101. return True
  102. @api.multi
  103. def detect_exceptions(self):
  104. """returns the list of exception_ids for all the considered sale orders
  105. as a side effect, the sale order's exception_ids column is updated with
  106. the list of exceptions related to the SO
  107. """
  108. exception_obj = self.env['sale.exception']
  109. order_exceptions = exception_obj.search(
  110. [('model', '=', 'sale.order')])
  111. line_exceptions = exception_obj.search(
  112. [('model', '=', 'sale.order.line')])
  113. all_exception_ids = []
  114. for order in self:
  115. if order.ignore_exceptions:
  116. continue
  117. exception_ids = order._detect_exceptions(order_exceptions,
  118. line_exceptions)
  119. order.exception_ids = [(6, 0, exception_ids)]
  120. all_exception_ids += exception_ids
  121. return all_exception_ids
  122. @api.model
  123. def _exception_rule_eval_context(self, obj_name, rec):
  124. user = self.env['res.users'].browse(self._uid)
  125. return {obj_name: rec,
  126. 'self': self.pool.get(rec._name),
  127. 'object': rec,
  128. 'obj': rec,
  129. 'pool': self.pool,
  130. 'cr': self._cr,
  131. 'uid': self._uid,
  132. 'user': user,
  133. 'time': time,
  134. # copy context to prevent side-effects of eval
  135. 'context': self._context.copy()}
  136. @api.model
  137. def _rule_eval(self, rule, obj_name, rec):
  138. expr = rule.code
  139. space = self._exception_rule_eval_context(obj_name, rec)
  140. try:
  141. safe_eval(expr,
  142. space,
  143. mode='exec',
  144. nocopy=True) # nocopy allows to return 'result'
  145. except Exception, e:
  146. raise Warning(
  147. _('Error when evaluating the sale exception '
  148. 'rule:\n %s \n(%s)') % (rule.name, e))
  149. return space.get('failed', False)
  150. @api.multi
  151. def _detect_exceptions(self, order_exceptions,
  152. line_exceptions):
  153. self.ensure_one()
  154. exception_ids = []
  155. for rule in order_exceptions:
  156. if self._rule_eval(rule, 'order', self):
  157. exception_ids.append(rule.id)
  158. for order_line in self.order_line:
  159. for rule in line_exceptions:
  160. if rule.id in exception_ids:
  161. # we do not matter if the exception as already been
  162. # found for an order line of this order
  163. continue
  164. if self._rule_eval(rule, 'line', order_line):
  165. exception_ids.append(rule.id)
  166. return exception_ids