flectra/addons/portal/controllers/portal.py
2018-01-16 02:34:37 -08:00

225 lines
8.3 KiB
Python

# -*- coding: utf-8 -*-
# Part of Odoo, Flectra. See LICENSE file for full copyright and licensing details.
import math
from werkzeug import urls
from flectra import fields as flectra_fields, tools, _
from flectra.exceptions import ValidationError
from flectra.http import Controller, request, route
# --------------------------------------------------
# Misc tools
# --------------------------------------------------
def pager(url, total, page=1, step=30, scope=5, url_args=None):
""" Generate a dict with required value to render `website.pager` template. This method compute
url, page range to display, ... in the pager.
:param url : base url of the page link
:param total : number total of item to be splitted into pages
:param page : current page
:param step : item per page
:param scope : number of page to display on pager
:param url_args : additionnal parameters to add as query params to page url
:type url_args : dict
:returns dict
"""
# Compute Pager
page_count = int(math.ceil(float(total) / step))
page = max(1, min(int(page if str(page).isdigit() else 1), page_count))
scope -= 1
pmin = max(page - int(math.floor(scope/2)), 1)
pmax = min(pmin + scope, page_count)
if pmax - pmin < scope:
pmin = pmax - scope if pmax - scope > 0 else 1
def get_url(page):
_url = "%s/page/%s" % (url, page) if page > 1 else url
if url_args:
_url = "%s?%s" % (_url, urls.url_encode(url_args))
return _url
return {
"page_count": page_count,
"offset": (page - 1) * step,
"page": {
'url': get_url(page),
'num': page
},
"page_start": {
'url': get_url(pmin),
'num': pmin
},
"page_previous": {
'url': get_url(max(pmin, page - 1)),
'num': max(pmin, page - 1)
},
"page_next": {
'url': get_url(min(pmax, page + 1)),
'num': min(pmax, page + 1)
},
"page_end": {
'url': get_url(pmax),
'num': pmax
},
"pages": [
{'url': get_url(page_num), 'num': page_num} for page_num in range(pmin, pmax+1)
]
}
def get_records_pager(ids, current):
if current.id in ids and (hasattr(current, 'website_url') or hasattr(current, 'portal_url')):
attr_name = 'portal_url' if hasattr(current, 'portal_url') else 'website_url'
idx = ids.index(current.id)
return {
'prev_record': idx != 0 and getattr(current.browse(ids[idx - 1]), attr_name),
'next_record': idx < len(ids) - 1 and getattr(current.browse(ids[idx + 1]), attr_name),
}
return {}
def _build_url_w_params(url_string, query_params, remove_duplicates=True):
""" Rebuild a string url based on url_string and correctly compute query parameters
using those present in the url and those given by query_params. Having duplicates in
the final url is optional. For example:
* url_string = '/my?foo=bar&error=pay'
* query_params = {'foo': 'bar2', 'alice': 'bob'}
* if remove duplicates: result = '/my?foo=bar2&error=pay&alice=bob'
* else: result = '/my?foo=bar&foo=bar2&error=pay&alice=bob'
"""
url = urls.url_parse(url_string)
url_params = url.decode_query()
if remove_duplicates: # convert to standard dict instead of werkzeug multidict to remove duplicates automatically
url_params = url_params.to_dict()
url_params.update(query_params)
return url.replace(query=urls.url_encode(url_params)).to_url()
class CustomerPortal(Controller):
MANDATORY_BILLING_FIELDS = ["name", "phone", "email", "street", "city", "country_id"]
OPTIONAL_BILLING_FIELDS = ["zipcode", "state_id", "vat", "company_name"]
_items_per_page = 20
def _get_archive_groups(self, model, domain=None, fields=None, groupby="create_date", order="create_date desc"):
if not model:
return []
if domain is None:
domain = []
if fields is None:
fields = ['name', 'create_date']
groups = []
for group in request.env[model]._read_group_raw(domain, fields=fields, groupby=groupby, orderby=order):
dates, label = group[groupby]
date_begin, date_end = dates.split('/')
groups.append({
'date_begin': flectra_fields.Date.to_string(flectra_fields.Date.from_string(date_begin)),
'date_end': flectra_fields.Date.to_string(flectra_fields.Date.from_string(date_end)),
'name': label,
'item_count': group[groupby + '_count']
})
return groups
def _prepare_portal_layout_values(self):
# get customer sales rep
sales_user = False
partner = request.env.user.partner_id
if partner.user_id and not partner.user_id._is_public():
sales_user = partner.user_id
return {
'sales_user': sales_user,
'page_name': 'home',
'archive_groups': [],
}
@route(['/my', '/my/home'], type='http', auth="user", website=True)
def home(self, **kw):
values = self._prepare_portal_layout_values()
return request.render("portal.portal_my_home", values)
@route(['/my/account'], type='http', auth='user', website=True)
def account(self, redirect=None, **post):
values = self._prepare_portal_layout_values()
partner = request.env.user.partner_id
values.update({
'error': {},
'error_message': [],
})
if post:
error, error_message = self.details_form_validate(post)
values.update({'error': error, 'error_message': error_message})
values.update(post)
if not error:
values = {key: post[key] for key in self.MANDATORY_BILLING_FIELDS}
values.update({key: post[key] for key in self.OPTIONAL_BILLING_FIELDS if key in post})
values.update({'zip': values.pop('zipcode', '')})
partner.sudo().write(values)
if redirect:
return request.redirect(redirect)
return request.redirect('/my/home')
countries = request.env['res.country'].sudo().search([])
states = request.env['res.country.state'].sudo().search([])
values.update({
'partner': partner,
'countries': countries,
'states': states,
'has_check_vat': hasattr(request.env['res.partner'], 'check_vat'),
'redirect': redirect,
'page_name': 'my_details',
})
response = request.render("portal.portal_my_details", values)
response.headers['X-Frame-Options'] = 'DENY'
return response
def details_form_validate(self, data):
error = dict()
error_message = []
# Validation
for field_name in self.MANDATORY_BILLING_FIELDS:
if not data.get(field_name):
error[field_name] = 'missing'
# email validation
if data.get('email') and not tools.single_email_re.match(data.get('email')):
error["email"] = 'error'
error_message.append(_('Invalid Email! Please enter a valid email address.'))
# vat validation
partner = request.env["res.partner"]
if data.get("vat") and hasattr(partner, "check_vat"):
if data.get("country_id"):
data["vat"] = request.env["res.partner"].fix_eu_vat_number(int(data.get("country_id")), data.get("vat"))
partner_dummy = partner.new({
'vat': data['vat'],
'country_id': (int(data['country_id'])
if data.get('country_id') else False),
})
try:
partner_dummy.check_vat()
except ValidationError:
error["vat"] = 'error'
# error message for empty required fields
if [err for err in error.values() if err == 'missing']:
error_message.append(_('Some required fields are empty.'))
unknown = [k for k in data if k not in self.MANDATORY_BILLING_FIELDS + self.OPTIONAL_BILLING_FIELDS]
if unknown:
error['common'] = 'Unknown field'
error_message.append("Unknown field '%s'" % ','.join(unknown))
return error, error_message