[MERGE] Merged lp:~openerp-dev/openobject-addons/trunk-website-bootstrap-3.0-bth
[odoo/odoo.git] / addons / website_sale / controllers / main.py
1 # -*- coding: utf-8 -*-
2
3 from openerp import SUPERUSER_ID
4 from openerp.osv import osv
5 from openerp.addons.web import http
6 from openerp.addons.web.http import request
7 import random
8 import werkzeug
9
10 def get_order(order_id=None):
11     order_obj = request.registry.get('sale.order')
12     # check if order allready exists
13     context = {}
14     if order_id:
15         try:
16             order = order_obj.browse(request.cr, SUPERUSER_ID, order_id)
17             order.pricelist_id
18         except:
19             order_id = None
20     if not order_id:
21         fields = [k for k, v in order_obj._columns.items()]
22         order_value = order_obj.default_get(request.cr, SUPERUSER_ID, fields)
23         if request.httprequest.session.get('ecommerce_pricelist'):
24             order_value['pricelist_id'] = request.httprequest.session['ecommerce_pricelist']
25         order_value['partner_id'] = request.registry.get('res.users').browse(request.cr, SUPERUSER_ID, request.uid).partner_id.id
26         order_value.update(order_obj.onchange_partner_id(request.cr, SUPERUSER_ID, [], request.uid, context={})['value'])
27         order_id = order_obj.create(request.cr, SUPERUSER_ID, order_value)
28         order = order_obj.browse(request.cr, SUPERUSER_ID, order_id)
29
30     context = {
31         'pricelist': order.pricelist_id.id,
32     }
33     return order_obj.browse(request.cr, SUPERUSER_ID, order_id, context=context)
34
35 def get_current_order():
36     if request.httprequest.session.get('ecommerce_order_id'):
37         return get_order(request.httprequest.session.get('ecommerce_order_id'))
38     else:
39         return False
40
41 class website(osv.osv):
42     _inherit = "website"
43     def get_rendering_context(self, additional_values=None):
44         values = {
45             'order': get_current_order(),
46             # 'website_sale_get_current_order': get_current_order, # TODO: replace 'order' key in templates
47         }
48         if additional_values:
49             values.update(additional_values)
50         return super(website, self).get_rendering_context(values)
51
52 class Ecommerce(http.Controller):
53
54     def get_categories(self):
55         category_obj = request.registry.get('pos.category')
56         category_ids = category_obj.search(request.cr, SUPERUSER_ID, [('parent_id', '=', False)])
57         categories = category_obj.browse(request.cr, SUPERUSER_ID, category_ids)
58         return categories
59
60     @http.route(['/shop/', '/shop/category/<cat_id>/', '/shop/category/<cat_id>/page/<int:page>/', '/shop/page/<int:page>/'], type='http', auth="public")
61     def category(self, cat_id=0, page=0, **post):
62
63         if 'promo' in post:
64             self.change_pricelist(post.get('promo'))
65             
66         website = request.registry['website']
67         product_obj = request.registry.get('product.template')
68
69         domain = [("sale_ok", "=", True)]
70         if SUPERUSER_ID != request.uid:
71             domain += [('website_published', '=', True)]
72
73         if post.get("search"):
74             domain += ['|', '|', '|',
75                 ('name', 'ilike', "%%%s%%" % post.get("search")), 
76                 ('description', 'ilike', "%%%s%%" % post.get("search")),
77                 ('website_description', 'ilike', "%%%s%%" % post.get("search")),
78                 ('product_variant_ids.pos_categ_id.name', 'ilike', "%%%s%%" % post.get("search"))]
79         if cat_id:
80             cat_id = int(cat_id)
81             domain += [('product_variant_ids.pos_categ_id.id', 'child_of', cat_id)] + domain
82
83         step = 20
84         product_count = len(product_obj.search(request.cr, request.uid, domain))
85         pager = website.pager(url="/shop/category/%s/" % cat_id, total=product_count, page=page, step=step, scope=7, url_args=post)
86
87         product_ids = product_obj.search(request.cr, request.uid, domain, limit=step, offset=pager['offset'])
88
89         context = {'pricelist': self.get_pricelist()}
90
91         values = website.get_rendering_context({
92             'categories': self.get_categories(),
93             'category_id': cat_id,
94             'products': product_obj.browse(request.cr, request.uid, product_ids, context=context),
95             'search': post.get("search"),
96             'pager': pager,
97         })
98         return website.render("website_sale.products", values)
99
100     @http.route(['/shop/product/<product_id>/'], type='http', auth="public")
101     def product(self, cat_id=0, product_id=0, **post):
102
103         if 'promo' in post:
104             self.change_pricelist(post.get('promo'))
105
106         website = request.registry['website']
107
108         product_id = product_id and int(product_id) or 0
109         product_obj = request.registry.get('product.template')
110
111         context = {'pricelist': self.get_pricelist()}
112
113         product = product_obj.browse(request.cr, request.uid, product_id, context=context)
114         values = website.get_rendering_context({
115             'category_id': post.get('category_id') and int(post.get('category_id')) or None,
116             'search': post.get("search"),
117             'categories': self.get_categories(),
118             'product': product,
119         })
120         return website.render("website_sale.product", values)
121
122     def get_pricelist(self):
123         if not request.httprequest.session.get('ecommerce_pricelist'):
124             self.change_pricelist(None)
125         return request.httprequest.session.get('ecommerce_pricelist')
126
127     def change_pricelist(self, code):
128         request.httprequest.session.setdefault('ecommerce_pricelist', False)
129
130         pricelist_id = False
131         if code:
132             pricelist_obj = request.registry.get('product.pricelist')
133             pricelist_ids = pricelist_obj.search(request.cr, SUPERUSER_ID, [('code', '=', code)])
134             if pricelist_ids:
135                 pricelist_id = pricelist_ids[0]
136
137         if not pricelist_id:
138             pricelist_id = request.registry['sale.order'].onchange_partner_id(request.cr, SUPERUSER_ID, [], request.uid, context={})['value']['pricelist_id']
139         
140         request.httprequest.session['ecommerce_pricelist'] = pricelist_id
141
142         order = get_current_order()
143         if order:
144             values = {'pricelist_id': pricelist_id}
145             values.update(order.onchange_pricelist_id(pricelist_id, None)['value'])
146             order.write(values)
147             for line in order.order_line:
148                 self.add_product_to_cart(line.product_id.id, 0)
149
150     def add_product_to_cart(self, product_id=0, number=1, set_number=-1):
151         order_line_obj = request.registry.get('sale.order.line')
152         user_obj = request.registry.get('res.users')
153
154         product_id = product_id and int(product_id) or 0
155         order = get_current_order()
156         if not order:
157             order = get_order()
158             request.httprequest.session['ecommerce_order_id'] = order.id
159
160         context = {'pricelist': self.get_pricelist()}
161
162         quantity = 0
163
164         # values initialisation
165         values = {}
166         order_line_ids = order_line_obj.search(request.cr, SUPERUSER_ID, [('order_id', '=', order.id), ('product_id', '=', product_id)], context=context)
167         if order_line_ids:
168             order_line = order_line_obj.read(request.cr, SUPERUSER_ID, order_line_ids, [], context=context)[0]
169             if set_number >= 0:
170                 quantity = set_number
171             else:
172                 quantity = order_line['product_uom_qty'] + number
173             if quantity < 0:
174                 quantity = 0
175         else:
176             fields = [k for k, v in order_line_obj._columns.items()]
177             values = order_line_obj.default_get(request.cr, SUPERUSER_ID, fields, context=context)
178             quantity = 1
179
180         values['product_uom_qty'] = quantity
181         values['product_id'] = product_id
182         values['order_id'] = order.id
183
184         # change and record value
185         pricelist_id = order.pricelist_id and order.pricelist_id.id or False
186
187         vals = order_line_obj.product_id_change(request.cr, SUPERUSER_ID, [], pricelist_id, product_id,
188             partner_id=user_obj.browse(request.cr, SUPERUSER_ID, request.uid).partner_id.id,
189             context=context)['value']
190
191         values.update(vals)
192         if order_line_ids:
193             order_line_obj.write(request.cr, SUPERUSER_ID, order_line_ids, values, context=context)
194             if not quantity:
195                 order_line_obj.unlink(request.cr, SUPERUSER_ID, order_line_ids, context=context)
196         else:
197             order_line_id = order_line_obj.create(request.cr, SUPERUSER_ID, values, context=context)
198             order.write({'order_line': [(4, order_line_id)]}, context=context)
199
200         return quantity
201
202     @http.route(['/shop/mycart/'], type='http', auth="public")
203     def mycart(self, **post):
204         order = get_current_order()
205         website = request.registry['website']
206         prod_obj = request.registry.get('product.product')
207
208         if 'promo' in post:
209             self.change_pricelist(post.get('promo'))
210
211         suggested_ids = []
212         if order:
213             for line in order.order_line:
214                 suggested_ids += [p.id for p in line.product_id.suggested_product_ids for line in order.order_line]
215         suggested_ids = prod_obj.search(request.cr, request.uid, [('id', 'in', suggested_ids)])
216         # select 3 random products
217         suggested_products = []
218         while len(suggested_products) < 3 and suggested_ids:
219             index = random.randrange(0, len(suggested_ids))
220             suggested_products.append(suggested_ids.pop(index))
221
222         values = website.get_rendering_context({
223             'categories': self.get_categories(),
224             'suggested_products': prod_obj.browse(request.cr, request.uid, suggested_products),
225         })
226         return website.render("website_sale.mycart", values)
227
228     @http.route(['/shop/<path:path>/add_cart/', '/shop/add_cart/', '/shop/add_cart/<product_id>/', '/shop/<path:path>/add_cart/<product_id>/'], type='http', auth="public")
229     def add_cart(self, path=None, product_id=0, remove=None):
230         self.add_product_to_cart(product_id, number=(remove and -1 or 1))
231         if path:
232             return werkzeug.utils.redirect("/shop/%s/" % path)
233         else:
234             return werkzeug.utils.redirect("/shop/")
235
236     @http.route(['/shop/remove_cart/<product_id>/', '/shop/<path:path>/remove_cart/<product_id>/'], type='http', auth="public")
237     def remove_cart(self, path=None, product_id=0):
238         return self.add_cart(product_id=product_id, path=path, remove=True)
239
240     @http.route(['/shop/set_cart/<product_id>/<set_number>/', '/shop/<path:path>/set_cart/<product_id>/<set_number>/'], type='http', auth="public")
241     def set_cart(self, path=None, product_id=0, set_number=0):
242         self.add_product_to_cart(product_id, set_number=set_number)
243         if path:
244             return werkzeug.utils.redirect("/shop/%s/" % path)
245         else:
246             return werkzeug.utils.redirect("/shop/")
247
248     @http.route(['/shop/checkout/'], type='http', auth="public")
249     def checkout(self, **post):
250         website = request.registry['website']
251
252         order = get_current_order()
253
254         if order.state != 'draft' or not order.order_line:
255             return self.mycart(**post)
256
257         partner_obj = request.registry.get('res.partner')
258         user_obj = request.registry.get('res.users')
259         country_obj = request.registry.get('res.country')
260         country_state_obj = request.registry.get('res.country.state')
261
262         values = website.get_rendering_context({
263             'shipping': post.get("shipping"),
264             'error': post.get("error") and dict.fromkeys(post.get("error").split(","), 'error') or {}
265         })
266
267         checkout = {}
268         if request.uid != website.get_public_user().id:
269             partner = user_obj.browse(request.cr, request.uid, request.uid).partner_id
270             partner_id = partner.id
271             checkout = user_obj.read(request.cr, SUPERUSER_ID, [partner_id], [])[0]
272             checkout['company'] = partner.parent_id and partner.parent_id.name or ''
273
274             shipping_ids = partner_obj.search(request.cr, request.uid, [("parent_id", "=", partner_id), ('type', "=", 'delivery')])
275             if shipping_ids:
276                 for k,v in partner_obj.read(request.cr, request.uid, shipping_ids[0]).items():
277                     checkout['shipping_'+k] = v or ''
278
279         checkout.update(request.session.setdefault('checkout', {}))
280         for k,v in checkout.items():
281             checkout[k] = v or ''
282         values['checkout'] = checkout
283
284         values['countries'] = country_obj.browse(request.cr, SUPERUSER_ID, country_obj.search(request.cr, SUPERUSER_ID, [(1, "=", 1)]))
285         values['states'] = country_state_obj.browse(request.cr, SUPERUSER_ID, country_state_obj.search(request.cr, SUPERUSER_ID, [(1, "=", 1)]))
286
287         return website.render("website_sale.checkout", values)
288
289     @http.route(['/shop/confirm_order/'], type='http', auth="public")
290     def confirm_order(self, **post):
291         website = request.registry['website']
292         order = get_current_order()
293
294         error = []
295         partner_obj = request.registry.get('res.partner')
296         user_obj = request.registry.get('res.users')
297
298         if order.state != 'draft':
299             return werkzeug.utils.redirect("/shop/checkout/")
300         if not order.order_line:
301             error.append("empty_cart")
302             return werkzeug.utils.redirect("/shop/checkout/")
303
304         # check values
305         request.session['checkout'] = post
306         required_field = ['phone', 'zip', 'email', 'street', 'city', 'name', 'country_id']
307         for key in required_field:
308             if not post.get(key):
309                 error.append(key)
310             if post.get('shipping_different') and key != 'email' and not post.get("shipping_%s" % key):
311                 error.append("shipping_%s" % key)
312         if error:
313             return werkzeug.utils.redirect("/shop/checkout/?error=%s&shipping=%s" % (",".join(error), post.get('shipping_different') and 'on' or ''))
314
315         # search or create company
316         company_id = None
317         if post['company']:
318             company_ids = partner_obj.search(request.cr, SUPERUSER_ID, [("name", "ilike", post['company']), ('is_company', '=', True)])
319             company_id = company_ids and company_ids[0] or None
320             if not company_id:
321                 company_id = partner_obj.create(request.cr, SUPERUSER_ID, {'name': post['company'], 'is_company': True})
322
323         partner_value = {
324             'fax': post['fax'],
325             'phone': post['phone'],
326             'zip': post['zip'],
327             'email': post['email'],
328             'street': post['street'],
329             'city': post['city'],
330             'name': post['name'],
331             'parent_id': company_id,
332             'country_id': post['country_id'],
333             'state_id': post['state_id'],
334         }
335         if request.uid != website.get_public_user().id:
336             partner_id = user_obj.browse(request.cr, request.uid, request.uid).partner_id.id
337             partner_obj.write(request.cr, request.uid, [partner_id], partner_value)
338         else:
339             partner_id = partner_obj.create(request.cr, SUPERUSER_ID, partner_value)
340
341         shipping_id = None
342         if 'shipping_name' in post:
343             shipping_value = {
344                 'fax': post['shipping_fax'],
345                 'phone': post['shipping_phone'],
346                 'zip': post['shipping_zip'],
347                 'street': post['shipping_street'],
348                 'city': post['shipping_city'],
349                 'name': post['shipping_name'],
350                 'type': 'delivery',
351                 'parent_id': partner_id,
352                 'country_id': post['shipping_country_id'],
353                 'state_id': post['shipping_state_id'],
354             }
355             domain = [(key, '_id' in key and '=' or 'ilike', '_id' in key and int(value) or value)
356                 for key, value in shipping_value.items() if key in required_field + ["type", "parent_id"]]
357             shipping_ids = partner_obj.search(request.cr, SUPERUSER_ID, domain)
358             if shipping_ids:
359                 shipping_id = shipping_ids[0]
360                 partner_obj.write(request.cr, SUPERUSER_ID, [shipping_id], shipping_value)
361             else:
362                 shipping_id = partner_obj.create(request.cr, SUPERUSER_ID, shipping_value)
363
364         order_value = {
365             'partner_id': partner_id,
366             'partner_invoice_id': partner_id,
367             'partner_shipping_id': shipping_id or partner_id
368         }
369         order_value.update(request.registry.get('sale.order').onchange_partner_id(request.cr, SUPERUSER_ID, [], request.uid, context={})['value'])
370         order.write(order_value)
371
372         return werkzeug.utils.redirect("/shop/payment/")
373
374     @http.route(['/shop/payment/'], type='http', auth="public")
375     def payment(self, **post):
376         website = request.registry['website']
377         order = get_current_order()
378
379         if not order or not order.order_line:
380             return self.mycart(**post)
381
382         values = website.get_rendering_context({
383             'partner': False,
384             'order': order
385         })
386
387         payment_obj = request.registry.get('portal.payment.acquirer')
388         payment_ids = payment_obj.search(request.cr, SUPERUSER_ID, [('visible', '=', True)])
389         values['payments'] = payment_obj.browse(request.cr, SUPERUSER_ID, payment_ids)
390         for payment in values['payments']:
391             content = payment_obj.render(request.cr, SUPERUSER_ID, payment.id, order, order.name, order.pricelist_id.currency_id, order.amount_total)
392             payment._content = content
393
394         return website.render("website_sale.payment", values)
395
396     @http.route(['/shop/payment_validate/'], type='http', auth="public")
397     def payment_validate(self, **post):
398         request.httprequest.session['ecommerce_order_id'] = False
399         request.httprequest.session['ecommerce_pricelist'] = False
400         return werkzeug.utils.redirect("/shop/")
401
402 # vim:expandtab:tabstop=4:softtabstop=4:shiftwidth=4: