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