2018-01-16 06:58:15 +01:00
|
|
|
# -*- coding: utf-8 -*-
|
2018-01-16 11:34:37 +01:00
|
|
|
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
|
2018-01-16 06:58:15 +01:00
|
|
|
|
2018-01-16 11:34:37 +01:00
|
|
|
from flectra import api, fields, models
|
|
|
|
from flectra.tools.translate import html_translate
|
|
|
|
from flectra.addons import decimal_precision as dp
|
2018-01-16 06:58:15 +01:00
|
|
|
|
|
|
|
|
|
|
|
class SaleQuoteTemplate(models.Model):
|
|
|
|
_name = "sale.quote.template"
|
|
|
|
_description = "Sale Quotation Template"
|
|
|
|
|
|
|
|
name = fields.Char('Quotation Template', required=True)
|
|
|
|
website_description = fields.Html('Description', translate=html_translate, sanitize_attributes=False)
|
|
|
|
quote_line = fields.One2many('sale.quote.line', 'quote_id', 'Quotation Template Lines', copy=True)
|
|
|
|
note = fields.Text('Terms and conditions')
|
|
|
|
options = fields.One2many('sale.quote.option', 'template_id', 'Optional Products Lines', copy=True)
|
|
|
|
number_of_days = fields.Integer('Quotation Duration',
|
|
|
|
help='Number of days for the validity date computation of the quotation')
|
|
|
|
require_payment = fields.Selection([
|
|
|
|
(0, 'Online Signature'),
|
|
|
|
(1, 'Online Payment')], default=0, string='Confirmation Mode',
|
|
|
|
help="Choose how you want to confirm an order to launch the delivery process. You can either "
|
|
|
|
"request a digital signature or an upfront payment. With a digital signature, you can "
|
|
|
|
"request the payment when issuing the invoice.")
|
|
|
|
mail_template_id = fields.Many2one(
|
|
|
|
'mail.template', 'Confirmation Mail',
|
|
|
|
domain=[('model', '=', 'sale.order')],
|
|
|
|
help="This e-mail template will be sent on confirmation. Leave empty to send nothing.")
|
|
|
|
active = fields.Boolean(default=True, help="If unchecked, it will allow you to hide the quotation template without removing it.")
|
|
|
|
|
|
|
|
@api.multi
|
|
|
|
def open_template(self):
|
|
|
|
self.ensure_one()
|
|
|
|
return {
|
|
|
|
'type': 'ir.actions.act_url',
|
|
|
|
'target': 'self',
|
|
|
|
'url': '/quote/template/%d' % self.id
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
class SaleQuoteLine(models.Model):
|
|
|
|
_name = "sale.quote.line"
|
|
|
|
_description = "Quotation Template Lines"
|
|
|
|
_order = 'sequence, id'
|
|
|
|
|
|
|
|
sequence = fields.Integer('Sequence', help="Gives the sequence order when displaying a list of sale quote lines.",
|
|
|
|
default=10)
|
|
|
|
quote_id = fields.Many2one('sale.quote.template', 'Quotation Template Reference', required=True,
|
|
|
|
ondelete='cascade', index=True)
|
|
|
|
name = fields.Text('Description', required=True, translate=True)
|
|
|
|
product_id = fields.Many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], required=True)
|
|
|
|
layout_category_id = fields.Many2one('sale.layout_category', string='Section')
|
|
|
|
website_description = fields.Html('Line Description', related='product_id.product_tmpl_id.quote_description',
|
|
|
|
translate=html_translate)
|
|
|
|
price_unit = fields.Float('Unit Price', required=True, digits=dp.get_precision('Product Price'))
|
|
|
|
discount = fields.Float('Discount (%)', digits=dp.get_precision('Discount'), default=0.0)
|
|
|
|
product_uom_qty = fields.Float('Quantity', required=True, digits=dp.get_precision('Product UoS'), default=1)
|
|
|
|
product_uom_id = fields.Many2one('product.uom', 'Unit of Measure ', required=True)
|
|
|
|
|
|
|
|
@api.onchange('product_id')
|
|
|
|
def _onchange_product_id(self):
|
|
|
|
self.ensure_one()
|
|
|
|
if self.product_id:
|
|
|
|
name = self.product_id.name_get()[0][1]
|
|
|
|
if self.product_id.description_sale:
|
|
|
|
name += '\n' + self.product_id.description_sale
|
|
|
|
self.name = name
|
|
|
|
self.price_unit = self.product_id.lst_price
|
|
|
|
self.product_uom_id = self.product_id.uom_id.id
|
|
|
|
self.website_description = self.product_id.quote_description or self.product_id.website_description or ''
|
|
|
|
domain = {'product_uom_id': [('category_id', '=', self.product_id.uom_id.category_id.id)]}
|
|
|
|
return {'domain': domain}
|
|
|
|
|
|
|
|
@api.onchange('product_uom_id')
|
|
|
|
def _onchange_product_uom(self):
|
|
|
|
if self.product_id and self.product_uom_id:
|
|
|
|
self.price_unit = self.product_id.uom_id._compute_price(self.product_id.lst_price, self.product_uom_id)
|
|
|
|
|
|
|
|
@api.model
|
|
|
|
def create(self, values):
|
|
|
|
values = self._inject_quote_description(values)
|
|
|
|
return super(SaleQuoteLine, self).create(values)
|
|
|
|
|
|
|
|
@api.multi
|
|
|
|
def write(self, values):
|
|
|
|
values = self._inject_quote_description(values)
|
|
|
|
return super(SaleQuoteLine, self).write(values)
|
|
|
|
|
|
|
|
def _inject_quote_description(self, values):
|
|
|
|
values = dict(values or {})
|
|
|
|
if not values.get('website_description') and values.get('product_id'):
|
|
|
|
product = self.env['product.product'].browse(values['product_id'])
|
|
|
|
values['website_description'] = product.quote_description or product.website_description or ''
|
|
|
|
return values
|
|
|
|
|
|
|
|
|
|
|
|
class SaleQuoteOption(models.Model):
|
|
|
|
_name = "sale.quote.option"
|
|
|
|
_description = "Quotation Option"
|
|
|
|
|
|
|
|
template_id = fields.Many2one('sale.quote.template', 'Quotation Template Reference', ondelete='cascade',
|
|
|
|
index=True, required=True)
|
|
|
|
name = fields.Text('Description', required=True, translate=True)
|
|
|
|
product_id = fields.Many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], required=True)
|
|
|
|
layout_category_id = fields.Many2one('sale.layout_category', string='Section')
|
|
|
|
website_description = fields.Html('Option Description', translate=html_translate, sanitize_attributes=False)
|
|
|
|
price_unit = fields.Float('Unit Price', required=True, digits=dp.get_precision('Product Price'))
|
|
|
|
discount = fields.Float('Discount (%)', digits=dp.get_precision('Discount'))
|
|
|
|
uom_id = fields.Many2one('product.uom', 'Unit of Measure ', required=True)
|
|
|
|
quantity = fields.Float('Quantity', required=True, digits=dp.get_precision('Product UoS'), default=1)
|
|
|
|
|
|
|
|
@api.onchange('product_id')
|
|
|
|
def _onchange_product_id(self):
|
|
|
|
if not self.product_id:
|
|
|
|
return
|
|
|
|
product = self.product_id
|
|
|
|
self.price_unit = product.list_price
|
|
|
|
self.website_description = product.product_tmpl_id.quote_description
|
|
|
|
self.name = product.name
|
|
|
|
self.uom_id = product.uom_id
|
|
|
|
domain = {'uom_id': [('category_id', '=', self.product_id.uom_id.category_id.id)]}
|
|
|
|
return {'domain': domain}
|
|
|
|
|
|
|
|
@api.onchange('uom_id')
|
|
|
|
def _onchange_product_uom(self):
|
|
|
|
if not self.product_id:
|
|
|
|
return
|
|
|
|
if not self.uom_id:
|
|
|
|
self.price_unit = 0.0
|
|
|
|
return
|
|
|
|
if self.uom_id.id != self.product_id.uom_id.id:
|
|
|
|
self.price_unit = self.product_id.uom_id._compute_price(self.price_unit, self.uom_id)
|