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.

161 lines
6.0 KiB

  1. # Copyright 2017 LasLabs Inc.
  2. # Copyright 2017 ACSONE SA/NV.
  3. # License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
  4. from odoo import api, fields, models, _
  5. from odoo.exceptions import ValidationError
  6. class SaleOrderLine(models.Model):
  7. _inherit = 'sale.order.line'
  8. is_contract = fields.Boolean(
  9. string='Is a contract', related="product_id.is_contract"
  10. )
  11. contract_id = fields.Many2one(
  12. comodel_name='account.analytic.account', string='Contract', copy=False
  13. )
  14. contract_template_id = fields.Many2one(
  15. comodel_name='account.analytic.contract',
  16. string='Contract Template',
  17. related='product_id.product_tmpl_id.contract_template_id',
  18. readonly=True,
  19. )
  20. recurring_rule_type = fields.Selection(
  21. [
  22. ('daily', 'Day(s)'),
  23. ('weekly', 'Week(s)'),
  24. ('monthly', 'Month(s)'),
  25. ('monthlylastday', 'Month(s) last day'),
  26. ('yearly', 'Year(s)'),
  27. ],
  28. default='monthly',
  29. string='Recurrence',
  30. help="Specify Interval for automatic invoice generation.",
  31. copy=False,
  32. )
  33. recurring_invoicing_type = fields.Selection(
  34. [('pre-paid', 'Pre-paid'), ('post-paid', 'Post-paid')],
  35. default='pre-paid',
  36. string='Invoicing type',
  37. help="Specify if process date is 'from' or 'to' invoicing date",
  38. copy=False,
  39. )
  40. recurring_interval = fields.Integer(
  41. default=1,
  42. string='Repeat Every',
  43. help="Repeat every (Days/Week/Month/Year)",
  44. copy=False,
  45. )
  46. date_start = fields.Date(string='Date Start',)
  47. date_end = fields.Date(string='Date End',)
  48. contract_line_id = fields.Many2one(
  49. comodel_name="account.analytic.invoice.line",
  50. string="Contract Line to replace",
  51. required=False,
  52. copy=False,
  53. )
  54. is_auto_renew = fields.Boolean(
  55. string="Auto Renew",
  56. related="product_id.is_auto_renew",
  57. readonly=True,
  58. )
  59. @api.onchange('product_id')
  60. def onchange_product(self):
  61. if self.product_id.is_contract:
  62. self.recurring_rule_type = self.product_id.recurring_rule_type
  63. self.recurring_invoicing_type = (
  64. self.product_id.recurring_invoicing_type
  65. )
  66. self.recurring_interval = self.product_id.recurring_interval
  67. self.date_start = self.date_start or fields.Date.today()
  68. if self.product_id.is_auto_renew:
  69. self.date_end = self.date_start + self.env[
  70. 'account.analytic.invoice.line'
  71. ].get_relative_delta(
  72. self.product_id.auto_renew_rule_type,
  73. self.product_id.auto_renew_interval,
  74. )
  75. @api.multi
  76. def _prepare_contract_line_values(self, contract):
  77. self.ensure_one()
  78. contract_line_env = self.env['account.analytic.invoice.line']
  79. return {
  80. 'sequence': self.sequence,
  81. 'product_id': self.product_id.id,
  82. 'name': self.name,
  83. 'quantity': self.product_uom_qty,
  84. 'uom_id': self.product_uom.id,
  85. 'price_unit': self.price_unit,
  86. 'discount': self.discount,
  87. 'date_end': self.date_end,
  88. 'date_start': self.date_start or fields.Date.today(),
  89. 'recurring_next_date':
  90. contract_line_env._compute_first_recurring_next_date(
  91. self.date_start or fields.Date.today(),
  92. self.recurring_invoicing_type,
  93. self.recurring_rule_type,
  94. self.recurring_interval,
  95. ),
  96. 'recurring_interval': self.recurring_interval,
  97. 'recurring_invoicing_type': self.recurring_invoicing_type,
  98. 'recurring_rule_type': self.recurring_rule_type,
  99. 'is_auto_renew': self.product_id.is_auto_renew,
  100. 'auto_renew_interval': self.product_id.auto_renew_interval,
  101. 'auto_renew_rule_type': self.product_id.auto_renew_rule_type,
  102. 'termination_notice_interval':
  103. self.product_id.termination_notice_interval,
  104. 'termination_notice_rule_type':
  105. self.product_id.termination_notice_rule_type,
  106. 'contract_id': contract.id,
  107. 'sale_order_line_id': self.id,
  108. }
  109. @api.multi
  110. def create_contract_line(self, contract):
  111. contract_line_env = self.env['account.analytic.invoice.line']
  112. contract_line = self.env['account.analytic.invoice.line']
  113. for rec in self:
  114. contract_line |= contract_line_env.create(
  115. rec._prepare_contract_line_values(contract)
  116. )
  117. rec.contract_line_id.stop(rec.date_start)
  118. return contract_line
  119. @api.constrains('contract_id')
  120. def _check_contract_sale_partner(self):
  121. for rec in self:
  122. if rec.contract_id:
  123. if rec.order_id.partner_id != rec.contract_id.partner_id:
  124. raise ValidationError(
  125. _(
  126. "Sale Order and contract should be "
  127. "linked to the same partner"
  128. )
  129. )
  130. @api.constrains('product_id', 'contract_id')
  131. def _check_contract_sale_contract_template(self):
  132. for rec in self:
  133. if rec.contract_id:
  134. if (
  135. rec.contract_template_id
  136. != rec.contract_id.contract_template_id
  137. ):
  138. raise ValidationError(
  139. _("Contract product has different contract template")
  140. )
  141. def _compute_invoice_status(self):
  142. super(SaleOrderLine, self)._compute_invoice_status()
  143. for line in self.filtered('contract_id'):
  144. line.invoice_status = 'no'
  145. @api.multi
  146. def invoice_line_create(self, invoice_id, qty):
  147. return super(
  148. SaleOrderLine, self.filtered(lambda l: not l.contract_id)
  149. ).invoice_line_create(invoice_id, qty)