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.

83 lines
3.1 KiB

  1. # Copyright 2016 Tecnativa - Pedro M. Baeza
  2. # Copyright 2018 Tecnativa - Carlos Dauden
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
  4. from odoo import _, api, fields, models, exceptions
  5. from odoo.tools import float_is_zero
  6. from odoo.tools.safe_eval import safe_eval
  7. class AccountAnalyticAccount(models.Model):
  8. _inherit = "account.analytic.account"
  9. skip_zero_qty = fields.Boolean(
  10. string='Skip Zero Qty Lines',
  11. help="If checked, contract lines with 0 qty don't create invoice line",
  12. )
  13. @api.model
  14. def _prepare_invoice_line(self, line, invoice_id):
  15. vals = super(AccountAnalyticAccount, self)._prepare_invoice_line(
  16. line, invoice_id)
  17. if line.qty_type == 'variable':
  18. eval_context = {
  19. 'env': self.env,
  20. 'context': self.env.context,
  21. 'user': self.env.user,
  22. 'line': line,
  23. 'contract': line.analytic_account_id,
  24. 'invoice': self.env['account.invoice'].browse(invoice_id),
  25. }
  26. safe_eval(line.qty_formula_id.code.strip(), eval_context,
  27. mode="exec", nocopy=True) # nocopy for returning result
  28. qty = eval_context.get('result', 0)
  29. if self.skip_zero_qty and float_is_zero(
  30. qty, self.env['decimal.precision'].precision_get(
  31. 'Product Unit of Measure')):
  32. # Return empty dict to skip line create
  33. vals = {}
  34. else:
  35. vals['quantity'] = qty
  36. # Re-evaluate price with this new quantity
  37. vals['price_unit'] = line.with_context(
  38. contract_line_qty=qty,
  39. ).price_unit
  40. return vals
  41. class AccountAnalyticContractLine(models.Model):
  42. _inherit = 'account.analytic.contract.line'
  43. qty_type = fields.Selection(
  44. selection=[
  45. ('fixed', 'Fixed quantity'),
  46. ('variable', 'Variable quantity'),
  47. ], required=True, default='fixed', string="Qty. type")
  48. qty_formula_id = fields.Many2one(
  49. comodel_name="contract.line.qty.formula", string="Qty. formula")
  50. class ContractLineFormula(models.Model):
  51. _name = 'contract.line.qty.formula'
  52. name = fields.Char(required=True, translate=True)
  53. code = fields.Text(required=True, default="result = 0")
  54. @api.constrains('code')
  55. def _check_code(self):
  56. eval_context = {
  57. 'env': self.env,
  58. 'context': self.env.context,
  59. 'user': self.env.user,
  60. 'line': self.env['account.analytic.invoice.line'],
  61. 'contract': self.env['account.analytic.account'],
  62. 'invoice': self.env['account.invoice'],
  63. }
  64. try:
  65. safe_eval(
  66. self.code.strip(), eval_context, mode="exec", nocopy=True)
  67. except Exception as e:
  68. raise exceptions.ValidationError(
  69. _('Error evaluating code.\nDetails: %s') % e)
  70. if 'result' not in eval_context:
  71. raise exceptions.ValidationError(_('No valid result returned.'))