8430ef077911dd9ebd77f7375a1aa69318614fab
[odoo/odoo.git] / addons / website_quote / models / order.py
1 # -*- coding: utf-8 -*-
2 ##############################################################################
3 #
4 #    OpenERP, Open Source Management Solution
5 #    Copyright (C) 2013-Today OpenERP SA (<http://www.openerp.com>).
6 #
7 #    This program is free software: you can redistribute it and/or modify
8 #    it under the terms of the GNU Affero General Public License as
9 #    published by the Free Software Foundation, either version 3 of the
10 #    License, or (at your option) any later version.
11 #
12 #    This program is distributed in the hope that it will be useful,
13 #    but WITHOUT ANY WARRANTY; without even the implied warranty of
14 #    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15 #    GNU Affero General Public License for more details.
16 #
17 #    You should have received a copy of the GNU Affero General Public License
18 #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
19 #
20 ##############################################################################
21
22 from openerp.osv import osv, fields
23 import uuid
24 import time
25 import datetime
26
27 import openerp.addons.decimal_precision as dp
28
29 class sale_quote_template(osv.osv):
30     _name = "sale.quote.template"
31     _description = "Sale Quotation Template"
32     _columns = {
33         'name': fields.char('Quotation Template', required=True),
34         'website_description': fields.html('Description', translate=True),
35         'quote_line': fields.one2many('sale.quote.line', 'quote_id', 'Quote Template Lines', copy=True),
36         'note': fields.text('Terms and conditions'),
37         'options': fields.one2many('sale.quote.option', 'template_id', 'Optional Products Lines', copy=True),
38         'number_of_days': fields.integer('Quote Duration', help='Number of days for the validaty date computation of the quotation'),
39     }
40     def open_template(self, cr, uid, quote_id, context=None):
41         return {
42             'type': 'ir.actions.act_url',
43             'target': 'self',
44             'url': '/quote/template/%d' % quote_id[0]
45         }
46
47 class sale_quote_line(osv.osv):
48     _name = "sale.quote.line"
49     _description = "Quotation Template Lines"
50     _columns = {
51         'quote_id': fields.many2one('sale.quote.template', 'Quotation Template Reference', required=True, ondelete='cascade', select=True),
52         'name': fields.text('Description', required=True, translate=True),
53         'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], required=True),
54         'website_description': fields.html('Line Description', translate=True),
55         'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')),
56         'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount')),
57         'product_uom_qty': fields.float('Quantity', required=True, digits_compute= dp.get_precision('Product UoS')),
58         'product_uom_id': fields.many2one('product.uom', 'Unit of Measure ', required=True),
59     }
60     _defaults = {
61         'product_uom_qty': 1,
62         'discount': 0.0,
63     }
64     def on_change_product_id(self, cr, uid, ids, product, context=None):
65         vals = {}
66         product_obj = self.pool.get('product.product').browse(cr, uid, product, context=context)
67         vals.update({
68             'price_unit': product_obj.list_price,
69             'product_uom_id': product_obj.uom_id.id,
70             'website_description': product_obj.website_description,
71             'name': product_obj.name,
72         })
73         return {'value': vals}
74
75
76 class sale_order_line(osv.osv):
77     _inherit = "sale.order.line"
78     _description = "Sales Order Line"
79     _columns = {
80         'website_description': fields.html('Line Description'),
81         'option_line_id': fields.one2many('sale.order.option', 'line_id', 'Optional Products Lines'),
82     }
83
84     def _inject_website_description(self, cr, uid, values, context=None):
85         values = dict(values or {})
86         if not values.get('website_description') and values.get('product_id'):
87             product = self.pool['product.product'].browse(cr, uid, values['product_id'], context=context)
88             values['website_description'] = product.website_description
89         return values
90
91     def create(self, cr, uid, values, context=None):
92         values = self._inject_website_description(cr, uid, values, context)
93         return super(sale_order_line, self).create(cr, uid, values, context=context)
94
95     def write(self, cr, uid, ids, values, context=None):
96         values = self._inject_website_description(cr, uid, values, context)
97         return super(sale_order_line, self).write(cr, uid, ids, values, context=context)
98
99
100 class sale_order(osv.osv):
101     _inherit = 'sale.order'
102
103     def _get_total(self, cr, uid, ids, name, arg, context=None):
104         res = {}
105         for order in self.browse(cr, uid, ids, context=context):
106             total = 0.0
107             for line in order.order_line:
108                 total += (line.product_uom_qty * line.price_unit)
109             res[order.id] = total
110         return res
111
112     _columns = {
113         'access_token': fields.char('Security Token', required=True, copy=False),
114         'template_id': fields.many2one('sale.quote.template', 'Quote Template'),
115         'website_description': fields.html('Description'),
116         'options' : fields.one2many('sale.order.option', 'order_id', 'Optional Products Lines'),
117         'validity_date': fields.date('Expiry Date'),
118         'amount_undiscounted': fields.function(_get_total, string='Amount Before Discount', type="float",
119             digits_compute=dp.get_precision('Account'))
120     }
121     _defaults = {
122         'access_token': lambda self, cr, uid, ctx={}: str(uuid.uuid4())
123     }
124
125     def open_quotation(self, cr, uid, quote_id, context=None):
126         quote = self.browse(cr, uid, quote_id[0], context=context)
127         return {
128             'type': 'ir.actions.act_url',
129             'target': 'self',
130             'url': '/quote/%s' % (quote.id)
131         }
132
133     def onchange_template_id(self, cr, uid, ids, template_id, partner=False, fiscal_position=False, context=None):
134         if not template_id:
135             return True
136
137         if context is None:
138             context = {}
139         context = dict(context, lang=self.pool.get('res.partner').browse(cr, uid, partner, context).lang)
140         
141         lines = [(5,)]
142         quote_template = self.pool.get('sale.quote.template').browse(cr, uid, template_id, context=context)
143         for line in quote_template.quote_line:
144             res = self.pool.get('sale.order.line').product_id_change(cr, uid, False,
145                 False, line.product_id.id, line.product_uom_qty, line.product_uom_id.id, line.product_uom_qty,
146                 line.product_uom_id.id, line.name, partner, False, True, time.strftime('%Y-%m-%d'),
147                 False, fiscal_position, True, context)
148             data = res.get('value', {})
149             if 'tax_id' in data:
150                 data['tax_id'] = [(6, 0, data['tax_id'])]
151             data.update({
152                 'name': line.name,
153                 'price_unit': line.price_unit,
154                 'discount': line.discount,
155                 'product_uom_qty': line.product_uom_qty,
156                 'product_id': line.product_id.id,
157                 'product_uom': line.product_uom_id.id,
158                 'website_description': line.website_description,
159                 'state': 'draft',
160             })
161             lines.append((0, 0, data))
162         options = []
163         for option in quote_template.options:
164             options.append((0, 0, {
165                 'product_id': option.product_id.id,
166                 'name': option.name,
167                 'quantity': option.quantity,
168                 'uom_id': option.uom_id.id,
169                 'price_unit': option.price_unit,
170                 'discount': option.discount,
171                 'website_description': option.website_description,
172             }))
173         date = False
174         if quote_template.number_of_days > 0:
175             date = (datetime.datetime.now() + datetime.timedelta(quote_template.number_of_days)).strftime("%Y-%m-%d")
176         data = {'order_line': lines, 'website_description': quote_template.website_description, 'note': quote_template.note, 'options': options, 'validity_date': date}
177         return {'value': data}
178
179     def recommended_products(self, cr, uid, ids, context=None):
180         order_line = self.browse(cr, uid, ids[0], context=context).order_line
181         product_pool = self.pool.get('product.product')
182         products = []
183         for line in order_line:
184             products += line.product_id.product_tmpl_id.recommended_products(context=context)
185         return products
186         
187
188
189 class sale_quote_option(osv.osv):
190     _name = "sale.quote.option"
191     _description = "Quote Option"
192     _columns = {
193         'template_id': fields.many2one('sale.quote.template', 'Quotation Template Reference', ondelete='cascade', select=True, required=True),
194         'name': fields.text('Description', required=True, translate=True),
195         'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)], required=True),
196         'website_description': fields.html('Option Description', translate=True),
197         'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')),
198         'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount')),
199         'uom_id': fields.many2one('product.uom', 'Unit of Measure ', required=True),
200         'quantity': fields.float('Quantity', required=True, digits_compute= dp.get_precision('Product UoS')),
201     }
202     _defaults = {
203         'quantity': 1,
204     }
205     def on_change_product_id(self, cr, uid, ids, product, context=None):
206         vals = {}
207         product_obj = self.pool.get('product.product').browse(cr, uid, product, context=context)
208         vals.update({
209             'price_unit': product_obj.list_price,
210             'website_description': product_obj.product_tmpl_id.website_description,
211             'name': product_obj.name,
212             'uom_id': product_obj.product_tmpl_id.uom_id.id,
213         })
214         return {'value': vals}
215
216 class sale_order_option(osv.osv):
217     _name = "sale.order.option"
218     _description = "Sale Options"
219     _columns = {
220         'order_id': fields.many2one('sale.order', 'Sale Order Reference', ondelete='cascade', select=True),
221         'line_id': fields.many2one('sale.order.line', on_delete="set null"),
222         'name': fields.text('Description', required=True),
223         'product_id': fields.many2one('product.product', 'Product', domain=[('sale_ok', '=', True)]),
224         'website_description': fields.html('Line Description'),
225         'price_unit': fields.float('Unit Price', required=True, digits_compute= dp.get_precision('Product Price')),
226         'discount': fields.float('Discount (%)', digits_compute= dp.get_precision('Discount')),
227         'uom_id': fields.many2one('product.uom', 'Unit of Measure ', required=True),
228         'quantity': fields.float('Quantity', required=True,
229             digits_compute= dp.get_precision('Product UoS')),
230     }
231
232     _defaults = {
233         'quantity': 1,
234     }
235     def on_change_product_id(self, cr, uid, ids, product, context=None):
236         vals = {}
237         product_obj = self.pool.get('product.product').browse(cr, uid, product, context=context)
238         vals.update({
239             'price_unit': product_obj.list_price,
240             'website_description': product_obj.product_tmpl_id.website_description,
241             'name': product_obj.name,
242             'uom_id': product_obj.product_tmpl_id.uom_id.id,
243         })
244         return {'value': vals}
245
246 class product_template(osv.Model):
247     _inherit = "product.template"
248     _columns = {
249         'website_description': fields.html('Description for the website'),
250     }