[MERGE] forward port of branch 8.0 up to ed1c173
authorChristophe Simonis <chs@odoo.com>
Fri, 5 Sep 2014 13:28:22 +0000 (15:28 +0200)
committerChristophe Simonis <chs@odoo.com>
Fri, 5 Sep 2014 13:28:22 +0000 (15:28 +0200)
112 files changed:
1  2 
addons/account/__openerp__.py
addons/account/account.py
addons/account/account_invoice.py
addons/account/account_view.xml
addons/account/report/account_analytic_entries_report.py
addons/account/report/account_analytic_entries_report_view.xml
addons/account/res_config.py
addons/account/res_config_view.xml
addons/account_voucher/account_voucher.py
addons/analytic/__openerp__.py
addons/analytic/models/analytic.py
addons/calendar/calendar.py
addons/calendar/calendar_view.xml
addons/crm/__openerp__.py
addons/crm/crm_lead.py
addons/crm/crm_lead_view.xml
addons/event/__openerp__.py
addons/fleet/fleet_view.xml
addons/hr/hr.py
addons/hr_attendance/hr_attendance_view.xml
addons/hr_contract/hr_contract.py
addons/hr_holidays/hr_holidays.py
addons/hr_holidays/hr_holidays_view.xml
addons/hr_recruitment/hr_recruitment.py
addons/hw_scale/__openerp__.py
addons/l10n_be_coda/__openerp__.py
addons/l10n_be_coda/wizard/account_coda_import.py
addons/mail/__openerp__.py
addons/mail/mail_group.py
addons/mail/mail_mail.py
addons/mail/static/src/css/mail.css
addons/mail/tests/test_mail_features.py
addons/mass_mailing/views/website_mass_mailing.xml
addons/mrp/mrp.py
addons/mrp/mrp_view.xml
addons/point_of_sale/controllers/main.py
addons/point_of_sale/point_of_sale.py
addons/point_of_sale/point_of_sale_view.xml
addons/point_of_sale/report/pos_order_report.py
addons/point_of_sale/res_partner_view.xml
addons/point_of_sale/static/src/css/pos.css
addons/point_of_sale/static/src/js/models.js
addons/point_of_sale/static/src/js/screens.js
addons/point_of_sale/static/src/js/widget_base.js
addons/point_of_sale/static/src/js/widgets.js
addons/point_of_sale/static/src/xml/pos.xml
addons/portal_sale/portal_sale_data.xml
addons/product/product_view.xml
addons/project/project.py
addons/project_issue/project_issue.py
addons/purchase/edi/purchase_order_action_data.xml
addons/purchase/purchase.py
addons/purchase/purchase_view.xml
addons/restaurant/__openerp__.py
addons/sale/edi/sale_order_action_data.xml
addons/sale/res_partner_view.xml
addons/sale/sale.py
addons/sale/sale_view.xml
addons/stock/static/src/js/widgets.js
addons/stock/stock.py
addons/theme_bootswatch/views/theme.xml
addons/web/controllers/main.py
addons/web/static/src/css/base.css
addons/web/static/src/css/base.sass
addons/web/static/src/js/chrome.js
addons/web/static/src/js/core.js
addons/web/static/src/js/data_export.js
addons/web/static/src/js/tour.js
addons/web/static/src/js/view_form.js
addons/web/static/src/js/view_list.js
addons/web/static/src/js/views.js
addons/web/static/src/xml/base.xml
addons/web_kanban/static/src/js/kanban.js
addons/website/controllers/main.py
addons/website/models/ir_http.py
addons/website/models/ir_ui_view.py
addons/website/static/src/css/website.css
addons/website/static/src/css/website.sass
addons/website/static/src/js/website.editor.js
addons/website/static/src/js/website.snippets.editor.js
addons/website/views/themes.xml
addons/website/views/website_templates.xml
addons/website_blog/views/website_blog_templates.xml
addons/website_customer/views/website_customer.xml
addons/website_event/views/website_event.xml
addons/website_event_track/views/website_event.xml
addons/website_forum/models/forum.py
addons/website_forum/views/website_forum.xml
addons/website_hr_recruitment/views/templates.xml
addons/website_membership/views/website_membership.xml
addons/website_partner/models/res_partner.py
addons/website_quote/__openerp__.py
addons/website_quote/models/order.py
addons/website_quote/views/website_quotation.xml
addons/website_quote/views/website_quotation_backend.xml
addons/website_sale/__openerp__.py
addons/website_sale/data/demo.xml
addons/website_sale/views/templates.xml
openerp/addons/base/ir/ir_qweb.py
openerp/addons/base/ir/ir_ui_view.py
openerp/addons/base/res/res_partner.py
openerp/addons/base/res/res_partner_view.xml
openerp/addons/base/tests/test_mail_examples.py
openerp/addons/base/tests/test_views.py
openerp/models.py
openerp/modules/module.py
openerp/release.py
openerp/tools/config.py
openerp/tools/convert.py
openerp/tools/func.py
openerp/tools/mail.py
openerp/tools/misc.py

Simple merge
Simple merge
Simple merge
Simple merge
                  <field name="product_id" />
                  <field name="user_id"/>
                  <group expand="0" string="Group By">
-                     <filter string="User" name="User" icon="terp-personal" context="{'group_by':'user_id'}"/>
-                     <filter string="Partner" icon="terp-partner" context="{'group_by':'partner_id'}"/>
-                     <filter string="Analytic Account" name="Account" icon="terp-folder-green" context="{'group_by':'account_id'}" groups="analytic.group_analytic_accounting"/>
-                     <filter string="Financial Account" icon="terp-folder-orange" context="{'group_by':'general_account_id'}"/>
-                     <filter string="Journal" icon="terp-folder-orange" context="{'group_by':'journal_id'}"/>
-                     <filter string="Product" icon="terp-accessories-archiver" context="{'group_by':'product_id'}"/>
-                     <filter string="Product Unit of Measure" icon="terp-mrp" context="{'group_by':'product_uom_id'}"/>
-                     <filter string="Company" icon="terp-go-home" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
-                     <filter string="Date" name="Month" icon="terp-go-month" context="{'group_by':'date:month'}"/>
+                     <filter string="Partner" context="{'group_by':'partner_id'}"/>
 -                    <filter string="Account" name="Account" context="{'group_by':'account_id'}" groups="analytic.group_analytic_accounting"/>
 -                    <filter string="General Account" context="{'group_by':'general_account_id'}"/>
++                    <filter string="Analytic Account" name="Account" context="{'group_by':'account_id'}" groups="analytic.group_analytic_accounting"/>
++                    <filter string="Financial Account" context="{'group_by':'general_account_id'}"/>
+                     <filter string="Journal" context="{'group_by':'journal_id'}"/>
+                     <filter string="Company" context="{'group_by':'company_id'}" groups="base.group_multi_company"/>
+                     <separator/>
+                     <filter string="Month" name="Month" context="{'group_by':'date:month'}"/>
                  </group>
              </search>
          </field>
Simple merge
Simple merge
Simple merge
index 340a37f,0000000..4661a3f
mode 100644,000000..100644
--- /dev/null
@@@ -1,377 -1,0 +1,377 @@@
 +# -*- coding: utf-8 -*-
 +##############################################################################
 +#
 +#    OpenERP, Open Source Management Solution
 +#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
 +#
 +#    This program is free software: you can redistribute it and/or modify
 +#    it under the terms of the GNU Affero General Public License as
 +#    published by the Free Software Foundation, either version 3 of the
 +#    License, or (at your option) any later version.
 +#
 +#    This program is distributed in the hope that it will be useful,
 +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +#    GNU Affero General Public License for more details.
 +#
 +#    You should have received a copy of the GNU Affero General Public License
 +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +#
 +##############################################################################
 +
 +import time
 +from datetime import datetime
 +
 +from openerp.osv import fields, osv
 +from openerp import tools
 +from openerp.tools.translate import _
 +import openerp.addons.decimal_precision as dp
 +
 +class account_analytic_account(osv.osv):
 +    _name = 'account.analytic.account'
 +    _inherit = ['mail.thread']
 +    _description = 'Analytic Account'
 +    _track = {
 +        'state': {
 +            'analytic.mt_account_pending': lambda self, cr, uid, obj, ctx=None: obj.state == 'pending',
 +            'analytic.mt_account_closed': lambda self, cr, uid, obj, ctx=None: obj.state == 'close',
 +            'analytic.mt_account_opened': lambda self, cr, uid, obj, ctx=None: obj.state == 'open',
 +        },
 +    }
 +
 +    def _compute_level_tree(self, cr, uid, ids, child_ids, res, field_names, context=None):
 +        currency_obj = self.pool.get('res.currency')
 +        recres = {}
 +        def recursive_computation(account):
 +            result2 = res[account.id].copy()
 +            for son in account.child_ids:
 +                result = recursive_computation(son)
 +                for field in field_names:
 +                    if (account.currency_id.id != son.currency_id.id) and (field!='quantity'):
 +                        result[field] = currency_obj.compute(cr, uid, son.currency_id.id, account.currency_id.id, result[field], context=context)
 +                    result2[field] += result[field]
 +            return result2
 +        for account in self.browse(cr, uid, ids, context=context):
 +            if account.id not in child_ids:
 +                continue
 +            recres[account.id] = recursive_computation(account)
 +        return recres
 +
 +    def _debit_credit_bal_qtty(self, cr, uid, ids, fields, arg, context=None):
 +        res = {}
 +        if context is None:
 +            context = {}
 +        child_ids = tuple(self.search(cr, uid, [('parent_id', 'child_of', ids)]))
 +        for i in child_ids:
 +            res[i] =  {}
 +            for n in fields:
 +                res[i][n] = 0.0
 +
 +        if not child_ids:
 +            return res
 +
 +        where_date = ''
 +        where_clause_args = [tuple(child_ids)]
 +        if context.get('from_date', False):
 +            where_date += " AND l.date >= %s"
 +            where_clause_args  += [context['from_date']]
 +        if context.get('to_date', False):
 +            where_date += " AND l.date <= %s"
 +            where_clause_args += [context['to_date']]
 +        cr.execute("""
 +              SELECT a.id,
 +                     sum(
 +                         CASE WHEN l.amount > 0
 +                         THEN l.amount
 +                         ELSE 0.0
 +                         END
 +                          ) as debit,
 +                     sum(
 +                         CASE WHEN l.amount < 0
 +                         THEN -l.amount
 +                         ELSE 0.0
 +                         END
 +                          ) as credit,
 +                     COALESCE(SUM(l.amount),0) AS balance,
 +                     COALESCE(SUM(l.unit_amount),0) AS quantity
 +              FROM account_analytic_account a
 +                  LEFT JOIN account_analytic_line l ON (a.id = l.account_id)
 +              WHERE a.id IN %s
 +              """ + where_date + """
 +              GROUP BY a.id""", where_clause_args)
 +        for row in cr.dictfetchall():
 +            res[row['id']] = {}
 +            for field in fields:
 +                res[row['id']][field] = row[field]
 +        return self._compute_level_tree(cr, uid, ids, child_ids, res, fields, context)
 +
 +    def name_get(self, cr, uid, ids, context=None):
 +        res = []
 +        if not ids:
 +            return res
 +        if isinstance(ids, (int, long)):
 +            ids = [ids]
 +        for id in ids:
 +            elmt = self.browse(cr, uid, id, context=context)
 +            res.append((id, self._get_one_full_name(elmt)))
 +        return res
 +
 +    def _get_full_name(self, cr, uid, ids, name=None, args=None, context=None):
 +        if context == None:
 +            context = {}
 +        res = {}
 +        for elmt in self.browse(cr, uid, ids, context=context):
 +            res[elmt.id] = self._get_one_full_name(elmt)
 +        return res
 +
 +    def _get_one_full_name(self, elmt, level=6):
 +        if level<=0:
 +            return '...'
 +        if elmt.parent_id and not elmt.type == 'template':
 +            parent_path = self._get_one_full_name(elmt.parent_id, level-1) + " / "
 +        else:
 +            parent_path = ''
 +        return parent_path + elmt.name
 +
 +    def _child_compute(self, cr, uid, ids, name, arg, context=None):
 +        result = {}
 +        if context is None:
 +            context = {}
 +
 +        for account in self.browse(cr, uid, ids, context=context):
 +            result[account.id] = map(lambda x: x.id, [child for child in account.child_ids if child.state != 'template'])
 +
 +        return result
 +
 +    def _get_analytic_account(self, cr, uid, ids, context=None):
 +        company_obj = self.pool.get('res.company')
 +        analytic_obj = self.pool.get('account.analytic.account')
 +        accounts = []
 +        for company in company_obj.browse(cr, uid, ids, context=context):
 +            accounts += analytic_obj.search(cr, uid, [('company_id', '=', company.id)])
 +        return accounts
 +
 +    def _set_company_currency(self, cr, uid, ids, name, value, arg, context=None):
 +        if isinstance(ids, (int, long)):
 +            ids=[ids]
 +        for account in self.browse(cr, uid, ids, context=context):
 +            if account.company_id:
 +                if account.company_id.currency_id.id != value:
 +                    raise osv.except_osv(_('Error!'), _("If you set a company, the currency selected has to be the same as it's currency. \nYou can remove the company belonging, and thus change the currency, only on analytic account of type 'view'. This can be really useful for consolidation purposes of several companies charts with different currencies, for example."))
 +        if value:
 +            cr.execute("""update account_analytic_account set currency_id=%s where id=%s""", (value, account.id))
 +            self.invalidate_cache(cr, uid, ['currency_id'], [account.id], context=context)
 +
 +    def _currency(self, cr, uid, ids, field_name, arg, context=None):
 +        result = {}
 +        for rec in self.browse(cr, uid, ids, context=context):
 +            if rec.company_id:
 +                result[rec.id] = rec.company_id.currency_id.id
 +            else:
 +                result[rec.id] = rec.currency_id.id
 +        return result
 +
 +    _columns = {
 +        'name': fields.char('Account/Contract Name', required=True, track_visibility='onchange'),
 +        'complete_name': fields.function(_get_full_name, type='char', string='Full Name'),
 +        'code': fields.char('Reference', select=True, track_visibility='onchange', copy=False),
 +        'type': fields.selection([('view','Analytic View'), ('normal','Analytic Account'),('contract','Contract or Project'),('template','Template of Contract')], 'Type of Account', required=True,
 +                                 help="If you select the View Type, it means you won\'t allow to create journal entries using that account.\n"\
 +                                  "The type 'Analytic account' stands for usual accounts that you only want to use in accounting.\n"\
 +                                  "If you select Contract or Project, it offers you the possibility to manage the validity and the invoicing options for this account.\n"\
 +                                  "The special type 'Template of Contract' allows you to define a template with default data that you can reuse easily."),
 +        'template_id': fields.many2one('account.analytic.account', 'Template of Contract'),
 +        'description': fields.text('Description'),
 +        'parent_id': fields.many2one('account.analytic.account', 'Parent Analytic Account', select=2),
 +        'child_ids': fields.one2many('account.analytic.account', 'parent_id', 'Child Accounts'),
 +        'child_complete_ids': fields.function(_child_compute, relation='account.analytic.account', string="Account Hierarchy", type='many2many'),
 +        'line_ids': fields.one2many('account.analytic.line', 'account_id', 'Analytic Entries'),
 +        'balance': fields.function(_debit_credit_bal_qtty, type='float', string='Balance', multi='debit_credit_bal_qtty', digits_compute=dp.get_precision('Account')),
 +        'debit': fields.function(_debit_credit_bal_qtty, type='float', string='Debit', multi='debit_credit_bal_qtty', digits_compute=dp.get_precision('Account')),
 +        'credit': fields.function(_debit_credit_bal_qtty, type='float', string='Credit', multi='debit_credit_bal_qtty', digits_compute=dp.get_precision('Account')),
 +        'quantity': fields.function(_debit_credit_bal_qtty, type='float', string='Quantity', multi='debit_credit_bal_qtty'),
 +        'quantity_max': fields.float('Prepaid Service Units', help='Sets the higher limit of time to work on the contract, based on the timesheet. (for instance, number of hours in a limited support contract.)'),
 +        'partner_id': fields.many2one('res.partner', 'Customer'),
 +        'user_id': fields.many2one('res.users', 'Project Manager', track_visibility='onchange'),
 +        'manager_id': fields.many2one('res.users', 'Account Manager', track_visibility='onchange'),
 +        'date_start': fields.date('Start Date'),
 +        'date': fields.date('Expiration Date', select=True, track_visibility='onchange'),
 +        'company_id': fields.many2one('res.company', 'Company', required=False), #not required because we want to allow different companies to use the same chart of account, except for leaf accounts.
 +        'state': fields.selection([('template', 'Template'),
 +                                   ('draft','New'),
 +                                   ('open','In Progress'),
 +                                   ('pending','To Renew'),
 +                                   ('close','Closed'),
 +                                   ('cancelled', 'Cancelled')],
 +                                  'Status', required=True,
 +                                  track_visibility='onchange', copy=False),
 +        'currency_id': fields.function(_currency, fnct_inv=_set_company_currency, #the currency_id field is readonly except if it's a view account and if there is no company
 +            store = {
 +                'res.company': (_get_analytic_account, ['currency_id'], 10),
 +            }, string='Currency', type='many2one', relation='res.currency'),
 +    }
 +
 +    def on_change_template(self, cr, uid, ids, template_id, date_start=False, context=None):
 +        if not template_id:
 +            return {}
 +        res = {'value':{}}
 +        template = self.browse(cr, uid, template_id, context=context)
 +        if template.date_start and template.date:
 +            from_dt = datetime.strptime(template.date_start, tools.DEFAULT_SERVER_DATE_FORMAT)
 +            to_dt = datetime.strptime(template.date, tools.DEFAULT_SERVER_DATE_FORMAT)
 +            timedelta = to_dt - from_dt
 +            res['value']['date'] = datetime.strftime(datetime.now() + timedelta, tools.DEFAULT_SERVER_DATE_FORMAT)
 +        if not date_start:
 +            res['value']['date_start'] = fields.date.today()
 +        res['value']['quantity_max'] = template.quantity_max
 +        res['value']['parent_id'] = template.parent_id and template.parent_id.id or False
 +        res['value']['description'] = template.description
 +        return res
 +
 +    def on_change_partner_id(self, cr, uid, ids,partner_id, name, context=None):
 +        res={}
 +        if partner_id:
 +            partner = self.pool.get('res.partner').browse(cr, uid, partner_id, context=context)
 +            if partner.user_id:
 +                res['manager_id'] = partner.user_id.id
 +            if not name:
 +                res['name'] = _('Contract: ') + partner.name
 +        return {'value': res}
 +
 +    def _default_company(self, cr, uid, context=None):
 +        user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
 +        if user.company_id:
 +            return user.company_id.id
 +        return self.pool.get('res.company').search(cr, uid, [('parent_id', '=', False)])[0]
 +
 +    def _get_default_currency(self, cr, uid, context=None):
 +        user = self.pool.get('res.users').browse(cr, uid, uid, context=context)
 +        return user.company_id.currency_id.id
 +
 +    _defaults = {
 +        'type': 'normal',
 +        'company_id': _default_company,
 +        'code' : lambda obj, cr, uid, context: obj.pool.get('ir.sequence').get(cr, uid, 'account.analytic.account'),
 +        'state': 'open',
 +        'user_id': lambda self, cr, uid, ctx: uid,
 +        'partner_id': lambda self, cr, uid, ctx: ctx.get('partner_id', False),
 +        'date_start': lambda *a: time.strftime('%Y-%m-%d'),
 +        'currency_id': _get_default_currency,
 +    }
 +
 +    def check_recursion(self, cr, uid, ids, context=None, parent=None):
 +        return super(account_analytic_account, self)._check_recursion(cr, uid, ids, context=context, parent=parent)
 +
 +    _order = 'code, name asc'
 +    _constraints = [
 +        (check_recursion, 'Error! You cannot create recursive analytic accounts.', ['parent_id']),
 +    ]
 +
 +    def name_create(self, cr, uid, name, context=None):
 +        raise osv.except_osv(_('Warning'), _("Quick account creation disallowed."))
 +
 +    def copy(self, cr, uid, id, default=None, context=None):
 +        if not default:
 +            default = {}
 +        analytic = self.browse(cr, uid, id, context=context)
 +        default['name'] = _("%s (copy)") % analytic['name']
 +        return super(account_analytic_account, self).copy(cr, uid, id, default, context=context)
 +
 +    def on_change_company(self, cr, uid, id, company_id):
 +        if not company_id:
 +            return {}
 +        currency = self.pool.get('res.company').read(cr, uid, [company_id], ['currency_id'])[0]['currency_id']
 +        return {'value': {'currency_id': currency}}
 +
 +    def on_change_parent(self, cr, uid, id, parent_id):
 +        if not parent_id:
 +            return {}
 +        parent = self.read(cr, uid, [parent_id], ['partner_id','code'])[0]
 +        if parent['partner_id']:
 +            partner = parent['partner_id'][0]
 +        else:
 +            partner = False
 +        res = {'value': {}}
 +        if partner:
 +            res['value']['partner_id'] = partner
 +        return res
 +
 +    def name_search(self, cr, uid, name, args=None, operator='ilike', context=None, limit=100):
 +        if not args:
 +            args=[]
 +        if context is None:
 +            context={}
 +        if name:
 +            account_ids = self.search(cr, uid, [('code', '=', name)] + args, limit=limit, context=context)
 +            if not account_ids:
 +                dom = []
 +                for name2 in name.split('/'):
 +                    name = name2.strip()
-                     account_ids = self.search(cr, uid, dom + [('name', 'ilike', name)] + args, limit=limit, context=context)
++                    account_ids = self.search(cr, uid, dom + [('name', operator, name)] + args, limit=limit, context=context)
 +                    if not account_ids: break
 +                    dom = [('parent_id','in',account_ids)]
 +        else:
 +            account_ids = self.search(cr, uid, args, limit=limit, context=context)
 +        return self.name_get(cr, uid, account_ids, context=context)
 +
 +class account_analytic_line(osv.osv):
 +    _name = 'account.analytic.line'
 +    _description = 'Analytic Line'
 +
 +    _columns = {
 +        'name': fields.char('Description', required=True),
 +        'date': fields.date('Date', required=True, select=True),
 +        'amount': fields.float('Amount', required=True, help='Calculated by multiplying the quantity and the price given in the Product\'s cost price. Always expressed in the company main currency.', digits_compute=dp.get_precision('Account')),
 +        'unit_amount': fields.float('Quantity', help='Specifies the amount of quantity to count.'),
 +        'account_id': fields.many2one('account.analytic.account', 'Analytic Account', required=True, ondelete='restrict', select=True, domain=[('type','<>','view')]),
 +        'user_id': fields.many2one('res.users', 'User'),
 +        'company_id': fields.related('account_id', 'company_id', type='many2one', relation='res.company', string='Company', store=True, readonly=True),
 +        'journal_id': fields.many2one('account.analytic.journal', 'Analytic Journal', required=True, ondelete='restrict', select=True),
 +
 +    }
 +
 +    def _get_default_date(self, cr, uid, context=None):
 +        return fields.date.context_today(self, cr, uid, context=context)
 +
 +    def __get_default_date(self, cr, uid, context=None):
 +        return self._get_default_date(cr, uid, context=context)
 +
 +    _defaults = {
 +        'date': __get_default_date,
 +        'company_id': lambda self,cr,uid,c: self.pool.get('res.company')._company_default_get(cr, uid, 'account.analytic.line', context=c),
 +        'amount': 0.00
 +    }
 +
 +    _order = 'date desc'
 +
 +    def _check_no_view(self, cr, uid, ids, context=None):
 +        analytic_lines = self.browse(cr, uid, ids, context=context)
 +        for line in analytic_lines:
 +            if line.account_id.type == 'view':
 +                return False
 +        return True
 +
 +    _constraints = [
 +        (_check_no_view, 'You cannot create analytic line on view account.', ['account_id']),
 +    ]
 +
 +
 +class account_analytic_journal(osv.osv):
 +    _name = 'account.analytic.journal'
 +    _description = 'Analytic Journal'
 +    _columns = {
 +        'name': fields.char('Journal Name', required=True),
 +        'code': fields.char('Journal Code', size=8),
 +        'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the analytic journal without removing it."),
 +        'type': fields.selection(
 +            [('sale', 'Sale'), ('purchase', 'Purchase'), ('cash', 'Cash'),
 +             ('general', 'General'), ('situation', 'Situation')],
 +            'Type', required=True, help="Gives the type of the analytic journal. When it needs for a document (eg: an invoice) to create analytic entries, Odoo will look for a matching journal of the same type."),
 +        'line_ids': fields.one2many('account.analytic.line', 'journal_id', 'Lines'),
 +        'company_id': fields.many2one('res.company', 'Company', required=True),
 +    }
 +    _defaults = {
 +        'active': True,
 +        'type': 'general',
 +        'company_id': lambda self, cr, uid, c=None: self.pool.get('res.users').browse(cr, uid, uid, c).company_id.id,
 +    }
Simple merge
Simple merge
Simple merge
Simple merge
                  </header>
                  <sheet>
                      <div class="oe_right oe_button_box" name="buttons">
-                         <button class="oe_inline oe_stat_button" type="action" 
+                         <button class="oe_inline oe_stat_button" type="action"
                              context="{'default_opportunity_id': active_id, 'search_default_opportunity_id': active_id, 'default_partner_id': partner_id, 'default_duration': 1.0}"
                              name="%(crm.crm_case_categ_phone_incoming0)d" icon="fa-phone">
 -                            <div>Schedule/Log<br/>Calls</div>
 +                            <div>Calls</div>
                          </button>
                      </div>
                      <div class="oe_title">
                              domain="['&amp;', ('section_ids', '=', section_id), '|', ('type', '=', type), ('type', '=', 'both')]"/>
                      </header>
                      <sheet>
 -                        <div class="oe_right oe_button_box">
 +                        <div name="buttons" class="oe_right oe_button_box">
-                             <button class="oe_inline oe_stat_button" type="action" 
+                             <button class="oe_inline oe_stat_button" type="action"
                                  name="%(crm.crm_case_categ_phone_incoming0)d" icon="fa-phone"
                                  context="{'default_opportunity_id': active_id, 'search_default_opportunity_id': active_id, 'default_partner_id': partner_id, 'default_duration': 1.0}">
 -                                <div>Schedule/Log<br/>Calls</div>
 +                                <div>Calls</div>
                              </button>
-                             <button class="oe_inline oe_stat_button" type="object" 
+                             <button class="oe_inline oe_stat_button" type="object"
                                  context="{'partner_id': partner_id}"
                                  name="action_schedule_meeting" icon="fa-calendar">
                                  <field string="Meetings" name="meeting_count" widget="statinfo"/>
Simple merge
Simple merge
diff --cc addons/hr/hr.py
Simple merge
  #    along with this program.  If not, see <http://www.gnu.org/licenses/>.
  #
  ##############################################################################
 +
  import time
  
+ from openerp import SUPERUSER_ID
  from openerp.osv import fields, osv
  
  class hr_employee(osv.osv):
Simple merge
                      <filter domain="[('state','in',('confirm','validate1'))]" string="To Approve" name="approve"/>
                      <filter domain="[('state','=','validate')]" string="Validated" name="validated"/>
                      <separator/>
 +                    <filter string="New Mail" name="message_unread" domain="[('message_unread','=',True)]"/>
 +                    <separator/>
 +                    <filter string="Approved Leaves" name="validated" domain="[('state','=','validate')]"/>
 +                    <separator/>
 +                    <filter string="To Report in Payslip" name="gray" domain="[('payslip_status', '=', False)]" groups="base.group_hr_manager"/>
 +                    <separator/>
-                     <filter icon="terp-go-year" name="year" string="Year" domain="[('holiday_status_id.active','=',True)]" help="Filters only on allocations and requests that belong to an holiday type that is 'active' (active field is True)"/>
+                     <filter name="year" string="Year" domain="[('holiday_status_id.active','=',True)]" help="Filters only on allocations and requests that belong to an holiday type that is 'active' (active field is True)"/>
                      <separator/>
-                     <filter string="My Requests" icon="terp-personal" name="my_leaves" domain="[('employee_id.user_id','=', uid)]" help="My Leave Requests"/>
+                     <filter string="My Requests" name="my_leaves" domain="[('employee_id.user_id','=', uid)]" help="My Leave Requests"/>
                      <separator/>
-                     <filter string="My Department Leaves" icon="terp-personal+" help="My Department Leaves" domain="[('department_id.manager_id','=',uid)]"/>
+                     <filter string="My Department Leaves" help="My Department Leaves" domain="[('department_id.manager_id','=',uid)]"/>
                      <field name="employee_id"/>
                      <field name="department_id"/>
                      <field name="holiday_status_id"/>
                      </group>
                  </xpath>
                  <xpath expr="//div[@name='button_box']" position="inside">
 +                    <button name="%(act_hr_employee_holiday_request_approved)d"
 +                            icon="fa-calendar"
 +                            class="oe_stat_button"
 +                            type="action"
 +                            groups="base.group_hr_user">
 +                        <field name="approved_leaves_count" widget="statinfo"/>
 +                    </button>
-                     <button name="%(act_hr_employee_holiday_request)d" 
+                     <button name="%(act_hr_employee_holiday_request)d"
 -                        type="action"
 -                        class="oe_stat_button"
 -                        icon="fa-calendar"
 -                        groups="base.group_hr_user">
 -                        <field name="leaves_count" widget="statinfo" string="Leaves"/>
 +                            type="action"
 +                            class="oe_stat_button"
-                             icon="fa-calendar" 
++                            icon="fa-calendar"
 +                            groups="base.group_hr_user">
 +                        <field name="leaves_count" widget="statinfo"/>
                      </button>
                  </xpath>
              </field>
@@@ -26,8 -26,9 +26,9 @@@
      'category': 'Hardware Drivers',
      'sequence': 6,
      'summary': 'Hardware Driver for Weighting Scales',
+     'website': 'https://www.odoo.com/page/point-of-sale',
      'description': """
 -Barcode Scanner Hardware Driver
 +Weighting Scale Hardware Driver
  ================================
  
  This module allows the point of sale to connect to a scale using a USB HSM Serial Scale Interface,
Simple merge
@@@ -30,18 -30,36 +30,19 @@@ import loggin
  
  _logger = logging.getLogger(__name__)
  
 -class account_coda_import(osv.osv_memory):
 -    _name = 'account.coda.import'
 -    _description = 'Import CODA File'
 -    _columns = {
 -        'coda_data': fields.binary('CODA File', required=True),
 -        'coda_fname': fields.char('CODA Filename', required=True),
 -        'note': fields.text('Log'),
 -    }
 +from openerp.addons.account_bank_statement_import import account_bank_statement_import as coda_ibs
  
 -    _defaults = {
 -        'coda_fname': 'coda.txt',
 -    }
 +coda_ibs.add_file_type(('coda', 'CODA'))
  
 -    def coda_parsing(self, cr, uid, ids, context=None, batch=False, codafile=None, codafilename=None):
 +class account_bank_statement_import(osv.TransientModel):
 +    _inherit = "account.bank.statement.import"
 +
 +    def process_coda(self, cr, uid, codafile=None, journal_id=False, context=None):
          if context is None:
              context = {}
 -        if batch:
 -            codafile = str(codafile)
 -            codafilename = codafilename
 -        else:
 -            data = self.browse(cr, uid, ids)[0]
 -            try:
 -                codafile = data.coda_data
 -                codafilename = data.coda_fname
 -            except:
 -                raise osv.except_osv(_('Error'), _('Wizard in incorrect state. Please hit the Cancel button'))
 -                return {}
          recordlist = unicode(base64.decodestring(codafile), 'windows-1252', 'strict').split('\n')
          statements = []
+         globalisation_comm = {}
          for line in recordlist:
              if not line:
                  pass
  
                      if 'counterpartyAddress' in line and line['counterpartyAddress'] != '':
                          note.append(_('Counter Party Address') + ': ' + line['counterpartyAddress'])
-                     line['name'] = "\n".join(filter(None, [line['counterpartyName'], line['communication']]))
-                     structured_com = ""
 -                    partner_id = None
+                     structured_com = False
 -                    bank_account_id = False
                      if line['communication_struct'] and 'communication_type' in line and line['communication_type'] == '101':
                          structured_com = line['communication']
 +                    bank_account_id = False
 +                    partner_id = False
                      if 'counterpartyNumber' in line and line['counterpartyNumber']:
 -                        ids = self.pool.get('res.partner.bank').search(cr, uid, [('acc_number', '=', str(line['counterpartyNumber']))])
 -                        if ids:
 -                            bank_account_id = ids[0]
 -                            partner_id = self.pool.get('res.partner.bank').browse(cr, uid, bank_account_id, context=context).partner_id.id
 -                        else:
 -                            #create the bank account, not linked to any partner. The reconciliation will link the partner manually
 -                            #chosen at the bank statement final confirmation time.
 -                            try:
 -                                type_model, type_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'base', 'bank_normal')
 -                                type_id = self.pool.get('res.partner.bank.type').browse(cr, uid, type_id, context=context)
 -                                bank_code = type_id.code
 -                            except ValueError:
 -                                bank_code = 'bank'
 -                            bank_account_id = self.pool.get('res.partner.bank').create(cr, uid, {'acc_number': str(line['counterpartyNumber']), 'state': bank_code}, context=context)
 +                        bank_account_id, partner_id = self._detect_partner(cr, uid, str(line['counterpartyNumber']), identifying_field='acc_number', context=context)
-                     if 'communication' in line and line['communication'] != '':
+                     if line.get('communication', ''):
                          note.append(_('Communication') + ': ' + line['communication'])
 -                    data = {
 +                    line_data = {
-                         'name': line['name'],
+                         'name': structured_com or (line.get('communication', '') != '' and line['communication'] or '/'),
                          'note': "\n".join(note),
                          'date': line['entryDate'],
                          'amount': line['amount'],
                          'partner_id': partner_id,
-                         'ref': structured_com,
+                         'partner_name': line['counterpartyName'],
 -                        'statement_id': statement['id'],
+                         'ref': line['ref'],
                          'sequence': line['sequence'],
                          'bank_account_id': bank_account_id,
                      }
 -                    self.pool.get('account.bank.statement.line').create(cr, uid, data, context=context)
 +                    statement_line.append((0, 0, line_data))
              if statement['coda_note'] != '':
 -                self.pool.get('account.bank.statement').write(cr, uid, [statement['id']], {'coda_note': statement['coda_note']}, context=context)
 -        model, action_id = self.pool.get('ir.model.data').get_object_reference(cr, uid, 'account', 'action_bank_reconcile_bank_statements')
 -        action = self.pool[model].browse(cr, uid, action_id, context=context)
 -        statements_ids = [statement['id'] for statement in statements]
 -        return {
 -            'name': action.name,
 -            'tag': action.tag,
 -            'context': {'statement_ids': statements_ids},
 -            'type': 'ir.actions.client',
 -        }
 +                statement_data.update({'coda_note': statement['coda_note']})
 +            statement_data.update({'journal_id': journal_id, 'line_ids': statement_line})
 +        return [statement_data]
  
  def rmspaces(s):
      return " ".join(s.split())
  
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -1,18 -1,16 +1,21 @@@
  <?xml version="1.0" encoding="utf-8"?>
  <openerp>
- <data>
- <template id="head" inherit_id="website.layout" name="Mail customization">
-     <xpath expr="//head" position="inside">
-         <script type="text/javascript" src="/mass_mailing/static/src/js/website_mass_mailing.editor.js" groups="base.group_website_publisher"></script>
+     <data>
+         <template id="assets_frontend" inherit_id="website.assets_frontend" name="wesbite_mass_mailing assets">
+             <xpath expr="." position="inside">
 +    </xpath>
 +</template>
 +
 +<template id="assets_frontend" inherit_id="website.assets_frontend" name="Mail Frontend Assets">
 +    <xpath expr="." position="inside">
-         <script type="text/javascript" src="/mass_mailing/static/src/js/website_mass_mailing.js"></script>
-     </xpath>
- </template>
+                 <script type="text/javascript" src="/mass_mailing/static/src/js/website_mass_mailing.js"></script>
+             </xpath>
+         </template>
  
- </data>
+         <template id="assets_editor" inherit_id="website.assets_editor" name="wesbite_mass_mailing Editor assets">
+             <xpath expr="/t" position="inside">
+                 <script type="text/javascript" src="/mass_mailing/static/src/js/website_mass_mailing.editor.js" groups="base.group_website_publisher"></script>
+             </xpath>
+         </template>
+     </data>
  </openerp>
@@@ -195,12 -195,12 +195,12 @@@ class mrp_bom(osv.osv)
          'name': fields.char('Name'),
          'code': fields.char('Reference', size=16),
          'active': fields.boolean('Active', help="If the active field is set to False, it will allow you to hide the bills of material without removing it."),
 -        'type': fields.selection([('normal', 'Normal'), ('phantom', 'Set')], 'BoM Type', required=True,
 +        'type': fields.selection([('normal','Manufacture this product as a normal bill of material'),('phantom','Sell and ship this product as a set of components(phantom)')], 'BoM Type', required=True,
                  help= "Set: When processing a sales order for this product, the delivery order will contain the raw materials, instead of the finished product."),
          'position': fields.char('Internal Reference', help="Reference to a position in an external plan."),
-         'product_tmpl_id': fields.many2one('product.template', 'Product', required=True),
+         'product_tmpl_id': fields.many2one('product.template', 'Product', domain="[('type', '!=', 'service')]", required=True),
          'product_id': fields.many2one('product.product', 'Product Variant',
-             domain="[('product_tmpl_id','=',product_tmpl_id)]",
+             domain="['&', ('product_tmpl_id','=',product_tmpl_id), ('type','!=', 'service')]",
              help="If a product variant is defined the BOM is available only for this product."),
          'bom_line_ids': fields.one2many('mrp.bom.line', 'bom_id', 'BoM Lines', copy=True),
          'product_qty': fields.float('Product Quantity', required=True, digits_compute=dp.get_precision('Product Unit of Measure')),
Simple merge
@@@ -10,10 -15,30 +10,15 @@@ _logger = logging.getLogger(__name__
  
  class PosController(http.Controller):
  
-     @http.route('/pos/web', type='http', auth='none')
+     @http.route('/pos/web', type='http', auth='user')
      def a(self, debug=False, **k):
+         cr, uid, context, session = request.cr, request.uid, request.context, request.session
  
-         if not request.session.uid:
+         if not session.uid:
              return login_redirect()
  
+         PosSession = request.registry['pos.session']
+         pos_session_ids = PosSession.search(cr, uid, [('state','=','opened'),('user_id','=',session.uid)], context=context)
 -        PosSession.login(cr,uid,pos_session_ids,context=context)
++        PosSession.login(cr, uid, pos_session_ids, context=context)
+         
 -        modules =  simplejson.dumps(module_boot(request.db))
 -        init =  """
 -                 var wc = new s.web.WebClient();
 -                 wc.show_application = function(){
 -                     wc.action_manager.do_action("pos.ui");
 -                 };
 -                 wc.setElement($(document.body));
 -                 wc.start();
 -                 """
 -
 -        html = request.registry.get('ir.ui.view').render(cr, session.uid,'point_of_sale.index',{
 -            'modules': modules,
 -            'init': init,
 -        })
 -
 -        return html
 +        return request.render('point_of_sale.index')
Simple merge
@@@ -64,14 -66,15 +66,15 @@@ class pos_order_report(osv.osv)
                      s.location_id as location_id,
                      s.company_id as company_id,
                      s.sale_journal as journal_id,
-                     l.product_id as product_id
+                     l.product_id as product_id,
+                     pt.categ_id as product_categ_id
                  from pos_order_line as l
                      left join pos_order s on (s.id=l.order_id)
 -                    left join product_product p on (p.id=l.product_id)
 -                    left join product_template pt on (pt.id=p.product_tmpl_id)
 +                    left join product_product p on (l.product_id=p.id)
 +                    left join product_template pt on (p.product_tmpl_id=pt.id)
                      left join product_uom u on (u.id=pt.uom_id)
                  group by
-                     s.date_order, s.partner_id,s.state,
+                     s.date_order, s.partner_id,s.state, pt.categ_id,
                      s.user_id,s.location_id,s.company_id,s.sale_journal,l.product_id,s.create_date
                  having
                      sum(l.qty * u.factor) != 0)""")
@@@ -7,12 -7,14 +7,12 @@@
              <field name="model">res.partner</field>
              <field name="inherit_id" ref="base.view_partner_form"/>
              <field name="arch" type="xml">
 -                <notebook position="inside">
 -                    <page string="Point of Sale"> 
 -                        <group>
 -                            <field name="ean13" />
 -                            <button name="%(action_edit_ean)d" type="action" string="Set a Custom EAN" />
 -                        </group>
 -                    </page>
 -                </notebook>
 +                <group name="point_of_sale" position="replace">
 +                    <group string="Point of Sale">
 +                        <field name="ean13" />
-                         <button name="edit_ean" type="object" string="Edit" />
++                        <button name="%(action_edit_ean)d" type="action" string="Set a Custom EAN" />
 +                    </group>
 +                </group>
              </field>
          </record>
  
@@@ -1735,18 -1678,18 +1750,28 @@@ td 
  .pos .popup .comment{
      font-weight: normal;
      font-size: 18px;
 -    margin: 0px 16px;
 +    margin: 0px 16px 16px 16px;
 +}
 +.pos .popup .comment.traceback {
 +    height: 264px;
 +    overflow: auto;
 +    font-size: 14px;
 +    text-align: left;
 +    font-family: 'Inconsolata';
 +    -webkit-user-select: text;
 +       -moz-user-select: text;
 +            user-select: text;
  }
+ .pos .popup .comment.traceback {
+     height: 264px;
+     overflow: auto;
+     font-size: 14px;
+     text-align: left;
+     font-family: 'Inconsolata';
+     -webkit-user-select: text;
+        -moz-user-select: text;
+             user-select: text;
+ }
  .pos .popup .footer{
      position:absolute;
      bottom:0;
@@@ -269,6 -276,27 +276,25 @@@ function openerp_pos_models(instance, m
                  self.cashregisters = bankstatements;
              },
          },{
+             label: 'fonts',
+             loaded: function(self){
+                 var fonts_loaded = new $.Deferred();
 -
+                 // Waiting for fonts to be loaded to prevent receipt printing
+                 // from printing empty receipt while loading Inconsolata
+                 // ( The font used for the receipt ) 
+                 waitForWebfonts(['Lato','Inconsolata'], function(){
+                     fonts_loaded.resolve();
+                 });
 -
+                 // The JS used to detect font loading is not 100% robust, so
+                 // do not wait more than 5sec
+                 setTimeout(function(){
+                     fonts_loaded.resolve();
+                 },5000);
+                 return fonts_loaded;
+             },
+         },{
+             label: 'pictures',
              loaded: function(self){
                  self.company_logo = new Image();
                  self.company_logo.crossOrigin = 'anonymous';
          // wrapper around the _save_to_server that updates the synch status widget
          _flush_orders: function(orders, options) {
              var self = this;
--
              this.set('synch',{ state: 'connecting', pending: orders.length});
  
              return self._save_to_server(orders, options).done(function (server_ids) {
              this.screen_data = {};  // see ScreenSelector
              this.receipt_type = 'receipt';  // 'receipt' || 'invoice'
              this.temporary = attributes.temporary || false;
-             this.sequence_number = this.pos.pos_session.sequence_number++;
 +            this.to_invoice = false;
              return this;
          },
          is_empty: function(){
@@@ -641,17 -661,14 +651,17 @@@ function openerp_pos_screens(instance, 
          },
          render_list: function(partners){
              var contents = this.$el[0].querySelector('.client-list-contents');
-             contents.innerHtml = "";
-             for(var i = 0, len = partners.length; i < len; i++){
+             contents.innerHTML = "";
+             for(var i = 0, len = Math.min(partners.length,1000); i < len; i++){
                  var partner    = partners[i];
 -                var clientline_html = QWeb.render('ClientLine',{widget: this, partner:partners[i]});
 -                var clientline = document.createElement('tbody');
 -                clientline.innerHTML = clientline_html;
 -                clientline = clientline.childNodes[1];
 -
 +                var clientline = this.partner_cache.get_node(partner.id);
 +                if(!clientline){
-                     var clientline_html = QWeb.render('ClientLine',{partner:partners[i]});
++                    var clientline_html = QWeb.render('ClientLine',{widget: this, partner:partners[i]});
 +                    var clientline = document.createElement('tbody');
 +                    clientline.innerHTML = clientline_html;
 +                    clientline = clientline.childNodes[1];
 +                    this.partner_cache.cache_node(partner.id,clientline);
 +                }
                  if( partners === this.new_client ){
                      clientline.classList.add('highlight');
                  }else{
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index dbf735b,0000000..fbcfb30
mode 100644,000000..100644
--- /dev/null
@@@ -1,55 -1,0 +1,56 @@@
 +# -*- coding: utf-8 -*-
 +##############################################################################
 +#
 +#    OpenERP, Open Source Management Solution
 +#    Copyright (C) 2004-2010 Tiny SPRL (<http://tiny.be>).
 +#
 +#    This program is free software: you can redistribute it and/or modify
 +#    it under the terms of the GNU Affero General Public License as
 +#    published by the Free Software Foundation, either version 3 of the
 +#    License, or (at your option) any later version.
 +#
 +#    This program is distributed in the hope that it will be useful,
 +#    but WITHOUT ANY WARRANTY; without even the implied warranty of
 +#    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 +#    GNU Affero General Public License for more details.
 +#
 +#    You should have received a copy of the GNU Affero General Public License
 +#    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 +#
 +##############################################################################
 +
 +
 +{
 +    'name': 'Restaurant',
 +    'version': '1.0',
 +    'category': 'Point of Sale',
 +    'sequence': 6,
 +    'summary': 'Restaurant extensions for the Point of Sale ',
 +    'description': """
 +
 +=======================
 +
 +This module adds several restaurant features to the Point of Sale:
 +- Bill Printing: Allows you to print a receipt before the order is paid
 +- Bill Splitting: Allows you to split an order into different orders
 +- Kitchen Order Printing: allows you to print orders updates to kitchen or bar printers
 +
 +""",
 +    'author': 'OpenERP SA',
++    'website': 'https://www.odoo.com',
 +    'depends': ['point_of_sale'],
 +    'data': [
 +        'restaurant_view.xml',
 +        'security/ir.model.access.csv',
 +        'views/templates.xml',
 +    ],
 +    'qweb':[
 +        'static/src/xml/multiprint.xml',
 +        'static/src/xml/splitbill.xml',
 +        'static/src/xml/printbill.xml',
 +    ],
 +    'installable': True,
 +    'auto_install': False,
 +}
 +
 +# vim:expandtab:smartindent:tabstop=4:softtabstop=4:shiftwidth=4:
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
index 8c6fac9,0000000..db076e8
mode 100644,000000..100644
--- /dev/null
@@@ -1,206 -1,0 +1,206 @@@
 +<?xml version="1.0" encoding="utf-8"?>\r
 +<openerp>\r
 +<data>\r
 +\r
 +<template id="theme_customize" inherit_id="website.theme_customize" name="theme_customize Bootswatch">\r
 +    <xpath expr="div" position="replace">\r
 +\r
 +      <div id="theme_customize_modal" class="modal fade bs-example-modal-sm">\r
 +        <div class="modal-dialog">\r
 +          <div class="modal-content">\r
 +            <div class="loading_backdrop"></div>\r
 +            <div class="modal-header">\r
 +              <button type="button" class="close">×</button>\r
 +              <h4 class="modal-title">Customize your theme</h4>\r
 +            </div>\r
 +            <div class="modal-body">\r
 +              <table>\r
 +                <tr>\r
 +                  <td>\r
 +                    <label class="checked">\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/img/bootswatch_default_thumbnail.png" alt="Default Theme"/>\r
 +                      <input name="theme" type="radio" data-xmlid="" checked="checked"/>\r
 +                    </label>\r
 +                  </td>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/amelia/thumbnail.png" alt="Amelia"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_amelia"/>\r
 +                    </label>\r
 +                  </td>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/cerulean/thumbnail.png" alt="Cerulean"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_cerulean"/>\r
 +                    </label>\r
 +                  </td>\r
 +                </tr>\r
 +                <tr>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/cosmo/thumbnail.png" alt="Cosmo"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_cosmo" data-disable="ee"/>\r
 +                    </label>\r
 +                  </td>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/cyborg/thumbnail.png" alt="Cyborg"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_cyborg"/>\r
 +                    </label>\r
 +                  </td>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/flatly/thumbnail.png" alt="Flatly"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_flatly"/>\r
 +                    </label>\r
 +                  </td>\r
 +                </tr>\r
 +                <tr>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/journal/thumbnail.png" alt="Journal"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_journal"/>\r
 +                    </label>\r
 +                  </td>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/readable/thumbnail.png" alt="Readable"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_readable"/>\r
 +                    </label>\r
 +                  </td>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/simplex/thumbnail.png" alt="Simplex"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_simplex"/>\r
 +                    </label>\r
 +                  </td>\r
 +                </tr>\r
 +                <tr>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/slate/thumbnail.png" alt="Slate"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_slate"/>\r
 +                    </label>\r
 +                  </td>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/spacelab/thumbnail.png" alt="Spacelab"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_spacelab"/>\r
 +                    </label>\r
 +                  </td>\r
 +                  <td>\r
 +                    <label>\r
 +                      <img style="width: 120px; height: 70px;" src="/theme_bootswatch/static/src/less/united/thumbnail.png" alt="United"/>\r
 +                      <input name="theme" type="radio" data-xmlid="website.theme_united"/>\r
 +                    </label>\r
 +                  </td>\r
 +                </tr>\r
 +              </table>\r
 +            </div>\r
 +          </div>\r
 +        </div>\r
 +      </div>\r
 +\r
 +    </xpath>\r
 +</template>\r
 +\r
 +<!--\r
 +     Apply Bootstrap less files\r
 +-->\r
 +\r
 +    <record id="website.option_bootstrap_less" model="ir.ui.view">\r
 +        <field name="application">always</field>\r
 +    </record>\r
 +\r
 +<!--\r
 +     All Default Themes\r
 +-->\r
 +\r
-     <template id="website.theme_amelia" name="Amelia" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_amelia" name="Amelia" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/amelia/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/amelia/variables.less' t-ignore="true"/>\r
 +            <link rel='stylesheet' href='/theme_bootswatch/static/src/less/amelia/fix.css' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
-     <template id="website.theme_cerulean" name="Cerulean" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_cerulean" name="Cerulean" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/cerulean/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/cerulean/variables.less' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
-     <template id="website.theme_cosmo" name="Cosmo" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_cosmo" name="Cosmo" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/cosmo/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/cosmo/variables.less' t-ignore="true"/>\r
 +            <link rel='stylesheet' href='/theme_bootswatch/static/src/less/cosmo/fix.css' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
-     <template id="website.theme_cyborg" name="Cyborg" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_cyborg" name="Cyborg" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/cyborg/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/cyborg/variables.less' t-ignore="true"/>\r
 +            <link rel='stylesheet' href='/theme_bootswatch/static/src/less/cyborg/fix.css' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
-     <template id="website.theme_flatly" name="Flatly" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_flatly" name="Flatly" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/flatly/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/flatly/variables.less' t-ignore="true"/>\r
 +            <link rel='stylesheet' href='/theme_bootswatch/static/src/less/flatly/fix.css' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
-     <template id="website.theme_journal" name="Journal" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_journal" name="Journal" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/journal/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/journal/variables.less' t-ignore="true"/>\r
 +            <link rel='stylesheet' href='/theme_bootswatch/static/src/less/journal/fix.css' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
-     <template id="website.theme_readable" name="Readable" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_readable" name="Readable" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/readable/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/readable/variables.less' t-ignore="true"/>\r
 +            <link rel='stylesheet' href='/theme_bootswatch/static/src/less/readable/fix.css' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
-     <template id="website.theme_simplex" name="Simplex" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_simplex" name="Simplex" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/simplex/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/simplex/variables.less' t-ignore="true"/>\r
 +            <link rel='stylesheet' href='/theme_bootswatch/static/src/less/simplex/fix.css' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
-     <template id="website.theme_slate" name="Slate" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_slate" name="Slate" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/slate/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/slate/variables.less' t-ignore="true"/>\r
 +            <link rel='stylesheet' href='/theme_bootswatch/static/src/less/slate/fix.css' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
-     <template id="website.theme_spacelab" name="Spacelab" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_spacelab" name="Spacelab" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/spacelab/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/spacelab/variables.less' t-ignore="true"/>\r
 +            <link rel='stylesheet' href='/theme_bootswatch/static/src/less/spacelab/fix.css' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
-     <template id="website.theme_united" name="United" inherit_id="website.theme" optional="disabled">\r
++    <template id="website.theme_united" name="United" inherit_id="website.theme" active="False" customize_show="False">\r
 +        <xpath expr="//link[last()]" position="after">\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/united/bootswatch.less' t-ignore="true"/>\r
 +            <link rel="stylesheet" type="text/less" href='/theme_bootswatch/static/src/less/united/variables.less' t-ignore="true"/>\r
 +        </xpath>\r
 +    </template>\r
 +\r
 +</data>\r
 +</openerp>\r
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -197,7 -241,7 +218,7 @@@ class Website(openerp.addons.web.contro
          user_groups = set(user.groups_id)
  
          views = request.registry["ir.ui.view"]\
-             ._views_get(request.cr, request.uid, xml_id, bundles=bundles, context=request.context)
 -            ._views_get(request.cr, request.uid, xml_id, context=dict(request.context or {}, active_test=False))
++            ._views_get(request.cr, request.uid, xml_id, bundles=bundles, context=dict(request.context or {}, active_test=False))
          done = set()
          result = []
          for v in views:
          obj = _object.browse(request.cr, request.uid, _id)
          return bool(obj.website_published)
  
+     @http.route(['/website/seo_suggest/<keywords>'], type='http', auth="public", website=True)
+     def seo_suggest(self, keywords):
+         url = "http://google.com/complete/search"
+         try:
+             req = urllib2.Request("%s?%s" % (url, werkzeug.url_encode({
+                 'ie': 'utf8', 'oe': 'utf8', 'output': 'toolbar', 'q': keywords})))
+             request = urllib2.urlopen(req)
+         except (urllib2.HTTPError, urllib2.URLError):
+             return []
+         xmlroot = ET.fromstring(request.read())
+         return json.dumps([sugg[0].attrib['data'] for sugg in xmlroot if len(sugg) and sugg[0].attrib['data']])
      #------------------------------------------------------
 +    # Themes
 +    #------------------------------------------------------
 +
 +    def get_view_ids(self, xml_ids):
 +        ids = []
 +        imd = request.registry['ir.model.data']
 +        for xml_id in xml_ids:
 +            if "." in xml_id:
 +                xml = xml_id.split(".")
 +                view_model, id = imd.get_object_reference(request.cr, request.uid, xml[0], xml[1])
 +            else:
 +                id = int(xml_id)
 +            ids.append(id)
 +        return ids
 +
 +    @http.route(['/website/theme_customize_get'], type='json', auth="public", website=True)
 +    def theme_customize_get(self, xml_ids):
 +        view = request.registry["ir.ui.view"]
 +        enable = []
 +        disable = []
 +        ids = self.get_view_ids(xml_ids)
-         for v in view.browse(request.cr, request.uid, ids, context=request.context):
-             if v.application != "disabled":
++        context = dict(request.context or {}, active_test=True)
++        for v in view.browse(request.cr, request.uid, ids, context=context):
++            if v.active:
 +                enable.append(v.xml_id)
 +            else:
 +                disable.append(v.xml_id)
 +        return [enable, disable]
 +
 +    @http.route(['/website/theme_customize'], type='json', auth="public", website=True)
 +    def theme_customize(self, enable, disable):
 +        """ enable or Disable lists of ``xml_id`` of the inherit templates
 +        """
 +        cr, uid, context, pool = request.cr, request.uid, request.context, request.registry
 +        view = pool["ir.ui.view"]
 +
-         def set_application(ids, application):
-             write_ids = []
-             for v in view.browse(cr, uid, self.get_view_ids(ids), context=context):
-                 if v.application == 'always':
-                     continue
-                 if v.application != application:
-                     write_ids.append(v.id)
-             if write_ids:
-                 view.write(cr, uid, write_ids, {'application': application})
++        def set_active(ids, active):
++            if ids:
++                view.write(cr, uid, ids, {'active': active}, context=dict(request.context or {}, active_test=True))
 +
-         set_application(disable, 'disabled')
-         set_application(enable, 'enabled')
++        set_active(disable, False)
++        set_active(enable, True)
 +
 +        return True
 +
 +    @http.route(['/website/theme_customize_reload'], type='http', auth="public", website=True)
 +    def theme_customize_reload(self, href, enable, disable):
 +        self.theme_customize(enable and enable.split(",") or [],disable and disable.split(",") or [])
 +        return request.redirect(href + ("&theme=true" if "#" in href else "#theme=true"))
 +
 +    #------------------------------------------------------
      # Helpers
      #------------------------------------------------------
      @http.route(['/website/kanban'], type='http', auth="public", methods=['POST'], website=True)
  
      @http.route([
          '/website/image',
 +        '/website/image/<xmlid>',
 +        '/website/image/<xmlid>/<field>',
-         '/website/image/<model>/<id>/<field>'
+         '/website/image/<model>/<id>/<field>',
+         '/website/image/<model>/<id>/<field>/<int:max_width>x<int:max_height>'
          ], auth="public", website=True)
 -    def website_image(self, model, id, field, max_width=None, max_height=None):
 +    def website_image(self, model=None, id=None, field=None, xmlid=None, max_width=None, max_height=None):
          """ Fetches the requested field and ensures it does not go above
          (max_width, max_height), resizing it if necessary.
  
  
          The requested field is assumed to be base64-encoded image data in
          all cases.
 +
 +        xmlid can be used to load the image. But the field image must by base64-encoded
          """
 +        if xmlid and "." in xmlid:
 +            xmlid = xmlid.split(".", 1)
 +            try:
 +                model, id = request.registry['ir.model.data'].get_object_reference(request.cr, request.uid, xmlid[0], xmlid[1])
 +            except:
 +                raise werkzeug.exceptions.NotFound()
 +            if model == 'ir.attachment':
 +                field = "datas"
 +
 +        if not model or not id or not field:
 +            raise werkzeug.exceptions.NotFound()
 +
-         response = werkzeug.wrappers.Response()
-         return request.registry['website']._image(
-                     request.cr, request.uid, model, id, field, response, max_width, max_height)
+         try:
+             response = werkzeug.wrappers.Response()
+             return request.registry['website']._image(
+                 request.cr, request.uid, model, id, field, response, max_width, max_height)
+         except Exception:
+             logger.exception("Cannot render image field %r of record %s[%s] at size(%s,%s)",
+                              field, model, id, max_width, max_height)
+             response = werkzeug.wrappers.Response()
+             return self.placeholder(response)
  
      #------------------------------------------------------
      # Server actions
@@@ -82,16 -82,32 +82,34 @@@ class ir_http(orm.AbstractModel)
                  self._authenticate(func.routing['auth'])
              else:
                  self._auth_method_public()
-             request.redirect = lambda url: werkzeug.utils.redirect(url_for(url))
+             request.redirect = lambda url, code=302: werkzeug.utils.redirect(url_for(url), code)
              request.website = request.registry['website'].get_current_website(request.cr, request.uid, context=request.context)
+             langs = [lg[0] for lg in request.website.get_languages()]
+             path = request.httprequest.path.split('/')
              if first_pass:
-                 request.lang = request.website.default_lang_code
+                 if request.website_multilang:
+                     # If the url doesn't contains the lang and that it's the first connection, we to retreive the user preference if it exists.
+                     if not path[1] in langs and not request.httprequest.cookies.get('session_id'):
+                         if request.lang not in langs:
+                             # Try to find a similar lang. Eg: fr_BE and fr_FR
+                             short = request.lang.split('_')[0]
+                             langs_withshort = [lg[0] for lg in request.website.get_languages() if lg[0].startswith(short)]
+                             if len(langs_withshort):
+                                 request.lang = langs_withshort[0]
+                             else:
+                                 request.lang = request.website.default_lang_code
+                         # We redirect with the right language in url
+                         if request.lang != request.website.default_lang_code:
+                             path.insert(1, request.lang)
+                             path = '/'.join(path) or '/'
+                             return request.redirect(path + '?' + request.httprequest.query_string)
+                     else:
+                         request.lang = request.website.default_lang_code
              request.context['lang'] = request.lang
 +            if not request.context.get('tz'):
 +                request.context['tz'] = request.session['geoip'].get('time_zone')
              if not func:
-                 path = request.httprequest.path.split('/')
-                 langs = [lg[0] for lg in request.website.get_languages()]
                  if path[1] in langs:
                      request.lang = request.context['lang'] = path.pop(1)
                      path = '/'.join(path) or '/'
Simple merge
          bind_snippet_click_editor: function () {
              var self = this;
              var snipped_event_flag;
 -            $("#wrapwrap").on('click', function (event) {
 +            self.$wrapwrap.on('click', function (event) {
-                 if (snipped_event_flag || !event.srcElement) {
+                 var srcElement = event.srcElement || (event.originalEvent && (event.originalEvent.originalTarget || event.originalEvent.target));
+                 if (snipped_event_flag || !srcElement) {
                      return;
                  }
                  snipped_event_flag = true;
              this.BuildingBlock = BuildingBlock;
              this.editor = editor;
              this.$target = $target;
 +            var option = website.snippet.templateOptions[option_id];
              var styles = this.$target.data("snippet-option-ids") || {};
 -            styles[snippet_id] = this;
 +            styles[option_id] = this;
              this.$target.data("snippet-option-ids", styles);
-             this.$overlay = this.$target.data('overlay');
+             this.$overlay = this.$target.data('overlay') || $('<div>');
 -            this['snippet-option-id'] = snippet_id;
 -            var $option = website.snippet.templateOptions[snippet_id].$el;
 -            this.$el = $option.find(">li").clone();
 -            this.data = $option.data();
 -
 -            this.required = this.$el.data("required");
 +            this.option= option_id;
 +            this.$el = option.$el.find(">li").clone();
 +            this.data = option.$el.data();
  
              this.set_active();
 -            this.$el.find('li[data-value] a').on('mouseenter mouseleave click', _.bind(this._mouse, this));
 -            this.$el.not(':not([data-value])').find("a").on('mouseenter mouseleave click', _.bind(this._mouse, this));
 -            this.$target.on('snippet-style-reset', _.bind(this.set_active, this));
 +            this.$target.on('snippet-option-reset', _.bind(this.set_active, this));
 +            this._bind_li_menu();
  
              this.start();
          },
  <openerp>
  <data>
  
 +
  <!--
 -     Theme Selector
 +    Customize Themes
 +
 +    Use INPUT type 'checkbox' or 'radio' or use OPTION in select box
 +    'data-xmlid' (optional) xml id of the template to add if the input is checked.
-         You can set a list of xml id separate by comma (all template is enable or 
++        You can set a list of xml id separate by comma (all template is enable or
 +        disable in same time)
 +    'data-enable' (optional) to checked one or more HTML ids, or list separate by comma
 +    'data-disable' (optional) to unchecked one or more HTML ids, or list separate by comma
 +    'data-reload="/"' (optional) force the reloading of the page if the url match with
 +        the string ( = regexp).
 +        Otherwise, only the '/web/css/website.assets_frontend' is reloaded
 +
 +    For the sets (data-enable and/or data-disable without data-xmlid), the set is
 +    automatically checked if:
 +    - all related fields are enabled for data-enable
 +    - all related fields are disabled for data-disable
 +    else unchecked
-     
++
 +    HTML apply classes:
 +    - 'checked': on the parent label when input is checked
-     - 'in': on the container (e.g.: bootstrap modal) after added in DOM (removed together 
++    - 'in': on the container (e.g.: bootstrap modal) after added in DOM (removed together
 +       out is added)
 +    - 'out': on the container 1 second before removed from ths DOM
 +    - 'loading': on the container/modal when the new css is loading
  -->
  
 -    <template id="website.themes" name="Themes">
 -        <t t-call="website.layout">
 -          <div id="wrap" groups="base.group_website_publisher">
 -            <div class="container">
 -    
 -            <div class="alert alert-info mt32" t-if="theme_changed">
 -                <button type="button" class="close" data-dismiss="alert">&amp;times;</button>
 -                <p>
 -                    <h4>Theme Changed!</h4>
 -                    Have a look at <a href="/">your homepage</a> or try another theme below.
 -                </p>
 -            </div>
 -            <h1 class="text-center">Try a New Theme</h1>
 -            <h3 class="text-center text-muted">You'll be able to change the theme at anytime</h3>
 -    
 -            <div class="row mt32" id="themes-list">
 -    
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img src="/website/static/src/img/bootswatch_default_thumbnail.png" class="img-responsive" alt="Default Theme"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Default</h3>
 -                    <p>Pure Bootstrap</p>
 -                    <a class="btn btn-info" href="/website/theme_change">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/amelia/thumbnail.png" alt="Amelia"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Amelia</h3>
 -                    <p>Sweet and cheery</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_amelia">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/cerulean/thumbnail.png" alt="Cerulean"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Cerulean</h3>
 -                    <p>A calm blue sky</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_cerulean">Apply</a>
 -                  </div>
 -                </div>
 +<template id="website.theme_customize" name="Theme Modal for Customization">
 +  <div id="theme_customize_modal" class="modal fade">
 +      <div class="modal-dialog">
 +          <div class="modal-content">
 +              <input id="less" data-xmlid="website.option_bootstrap_less" style="display: none;"/>
 +
 +              <div class="loading_backdrop"></div>
 +              <div class="modal-header text-center">
 +                  <button type="button" class="close">×</button>
 +                  <a class="btn btn-primary" href="/web#return_label=Website&amp;action=website.action_module_theme">Click here to change theme</a>
 +                  <hr style="margin: 20px -10px 10px -10px;"/>
 +                  <h4 class="modal-title">Customize this default theme</h4>
                </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/cosmo/thumbnail.png" alt="Cosmo"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Cosmo</h3>
 -                    <p>An ode to Metro</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_cosmo">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/cyborg/thumbnail.png" alt="Cyborg"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Cyborg</h3>
 -                    <p>Jet black and electric blue</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_cyborg">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/flatly/thumbnail.png" alt="Flatly"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Flatly</h3>
 -                    <p>Flat and modern</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_flatly">Apply</a>
 -                  </div>
 -                </div>
 +              <div class="modal-body">
 +                  <h5 class="modal-h5">LAYOUT</h5>
 +                  <table name="layout">
 +                      <tr>
 +                          <td class=" text-center" width="50%">
 +                              <label class=" center-block">
 +                                  <div class="text-center" style="background-image: url(/website/static/src/img/theme/layout-full.gif); background-size: 100%; line-height: 40px;">FULL WIDTH</div>
 +                                  <input name="layoutvar" type="radio" data-xmlid=""/>
-                               </label>                                 
++                              </label>
 +                          </td>
 +                          <td class=" text-center">
 +                              <label class=" center-block">
 +                                 <div class="text-center" style="background-image: url(/website/static/src/img/theme/layout-boxed.gif); background-size: 100%; line-height: 40px;">BOXED</div>
 +                                  <input name="layoutvar" type="radio" data-xmlid="website.option_layout_boxed" data-enable="less"/>
 +                              </label>
 +                          </td>
 +                      </tr>
 +                  </table>
 +
 +                  <h5 class="modal-h5">MAIN COLOR</h5>
 +                  <table name="color">
 +                      <tr>
 +                          <td>
 +                              <label class="chd-color-combi">
 +                                  <img src="/website/static/src/img/theme/variant-stone.gif" alt="Stone" class="chd-color-combi-img"/>
 +                                  <input name="colorvar" type="radio" data-xmlid="" data-disable="less"/>
 +                              </label>
 +                          </td>
 +                          <td>
 +                              <label class="chd-color-combi">
 +                                  <img src="/website/static/src/img/theme/variant-emerald.gif" alt="Emerald" class="chd-color-combi-img"/>
 +                                  <input name="colorvar" type="radio" data-xmlid="website.option_color_emerald" data-enable="less"/>
 +                              </label>
 +                          </td>
 +                          <td>
 +                              <label class="chd-color-combi">
 +                                  <img src="/website/static/src/img/theme/variant-cobalt.gif" alt="Cobalt" class="chd-color-combi-img"/>
 +                                  <input name="colorvar" type="radio" data-xmlid="website.option_color_cobalt" data-enable="less"/>
 +                              </label>
 +                          </td>
 +                          <td>
 +                              <label class="chd-color-combi">
 +                                  <img src="/website/static/src/img/theme/variant-amethyst.gif" alt="Amethyst" class="chd-color-combi-img"/>
 +                                  <input name="colorvar" type="radio" data-xmlid="website.option_color_amethyst" data-enable="less"/>
 +                              </label>
 +                          </td>
 +                          <td>
 +                              <label class="chd-color-combi">
 +                                  <img src="/website/static/src/img/theme/variant-ruby.gif" alt="Blue" class="chd-color-combi-img"/>
 +                                  <input name="colorvar" type="radio" data-xmlid="website.option_color_ruby" data-enable="less"/>
 +                              </label>
 +                          </td>
 +                          <td>
 +                              <label class="chd-color-combi">
 +                                  <img src="/website/static/src/img/theme/variant-gold.gif" alt="Gold" class="chd-color-combi-img"/>
 +                                  <input name="colorvar" type="radio" data-xmlid="website.option_color_gold" data-enable="less"/>
 +                              </label>
 +                          </td>
 +                      </tr>
 +                  </table>
 +
 +                  <h5 class="modal-h5">FONTS COMBINATIONS</h5>
 +                  <table name="font">
 +                      <tr>
 +                          <td width="50%">
 +                              <label>
 +                                  <div>
 +                                      <span style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:11px">Helvetica</span>
 +                                      <span style="font-family:Georgia, 'Times New Roman', Times, serif; font-size:11px" >/ Georgia</span>
 +                                  </div>
 +                                  <input name="theme" type="radio" data-xmlid=""/>
 +                              </label>
 +                          </td>
 +                          <td width="50%">
 +                              <label>
 +                                  <div>
 +                                      <span style="font-family:Georgia, 'Times New Roman', Times, serif; font-size:11px" >Georgia</span>
 +                                      <span style="font-family:'Helvetica Neue', Helvetica, Arial, sans-serif; font-size:11px">/ Helvetica</span>
 +                                    <input name="theme" type="radio" data-xmlid="website.option_font" data-enable="less"/>
 +                                  </div>
 +                              </label>
 +                          </td>
 +                      </tr>
 +                  </table>
                </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/journal/thumbnail.png" alt="Journal"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Journal</h3>
 -                    <p>Crisp like a new sheet of paper.</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_journal">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/readable/thumbnail.png" alt="Readable"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Readable</h3>
 -                    <p>Optimized for legibility</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_readable">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/simplex/thumbnail.png" alt="Simplex"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Simplex</h3>
 -                    <p>Mini and minimalist.</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_simplex">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/slate/thumbnail.png" alt="Slate"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Slate</h3>
 -                    <p>Shades of gunmetal gray</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_slate">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/spacelab/thumbnail.png" alt="Spacelab"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Spacelab</h3>
 -                    <p>Silvery and sleek.</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_spacelab">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/united/thumbnail.png" alt="United"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>United</h3>
 -                    <p>Ubuntu orange and unique font</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_united">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -              <div class="col-md-4">
 -                <div class="well text-center">
 -                  <div class="image">
 -                    <img class="img-responsive" src="http://bootswatch.com/yeti/thumbnail.png" alt="Yeti"/>
 -                  </div>
 -                  <div class="options">
 -                    <h3>Yeti</h3>
 -                    <p>A friendly foundation</p>
 -                    <a class="btn btn-info" href="/website/theme_change?theme_id=website.theme_yeti">Apply</a>
 -                  </div>
 -                </div>
 -              </div>
 -
 -            </div>
 -            </div>
            </div>
 -        </t>
 -    </template>
 -
 +      </div>
 +  </div>
 +</template>
 +
 +<!-- color-picker -->
 +<!-- HTML class to hide option for one mode : only-text, only-bg -->
 +
 +<template id="website.colorpicker" name="Color-Picker">
 +    <table class="colorpicker">
 +        <tr>
 +            <td><button class="automatic-color" title="Automatic Color"/></td>
 +            <td><button class="bg-primary" title="Primary Color"/></td>
 +            <td><button class="bg-success" title="Success Color"/></td>
 +            <td><button class="bg-info" title="Info Color"/></td>
 +            <td><button class="bg-warning" title="Warning Color"/></td>
 +            <td><button class="bg-danger" title="Danger Color"/></td>
 +        </tr>
 +        <tr><td colspan="8"><hr style="width: 100%; height: 1px;"/></td></tr>
 +        <tr>
 +            <td><button class="bg-blue"/></td>
 +            <td><button class="bg-turquoise"/></td>
 +            <td><button class="bg-green"/></td>
 +            <td><button class="bg-yellow"/></td>
 +            <td><button class="bg-red"/></td>
 +            <td><button class="bg-pink"/></td>
 +            <td><button class="bg-purple"/></td>
 +            <td><button class="bg-brown"/></td>
 +        </tr>
 +    </table>
 +</template>
  
  <!--
 -     All Default Themes
 +     Theme
  -->
  
 -    <template id="website.theme_amelia" name="Amelia" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/amelia.min.css' t-ignore="true"/>
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/amelia.fix.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_cerulean" name="Cerulean" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/cerulean.min.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_cosmo" name="Cosmo" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/cosmo.min.css' t-ignore="true"/>
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/cosmo.fix.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_cyborg" name="Cyborg" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/cyborg.min.css' t-ignore="true"/>
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/cyborg.fix.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_flatly" name="Flatly" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/flatly.min.css' t-ignore="true"/>
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/flatly.fix.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_journal" name="Journal" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/journal.min.css' t-ignore="true"/>
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/journal.fix.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_readable" name="Readable" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/readable.min.css' t-ignore="true"/>
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/readable.fix.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_simplex" name="Simplex" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/simplex.min.css' t-ignore="true"/>
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/simplex.fix.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_slate" name="Slate" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/slate.min.css' t-ignore="true"/>
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/slate.fix.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_spacelab" name="Spacelab" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/spacelab.min.css' t-ignore="true"/>
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/spacelab.fix.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_united" name="United" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/united.min.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 -
 -    <template id="website.theme_yeti" name="Yeti" inherit_id="website.theme" active="False" customize_show="True">
 -        <xpath expr="//link[@id='bootstrap_css']" position="replace">
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/yeti.min.css' t-ignore="true"/>
 -            <link rel='stylesheet' href='/website/static/src/css/bootswatch/yeti.fix.css' t-ignore="true"/>
 -        </xpath>
 -    </template>
 +<template id="website.theme" name="Theme">
 +    <link rel="stylesheet" href='/website/static/src/css/website.css'/>
 +    <!-- Boostrap Fallback if server can't compute less files -->
 +    <link id="bootstrap_css" rel='stylesheet' href='/web/static/lib/bootstrap/css/bootstrap.css'/>
 +</template>
 +
 +<!-- Bootstrap Less File layout -->
 +
- <template id="option_bootstrap_less" name="option_bootstrap_less" inherit_id="website.theme" optional="disabled">
++<template id="option_bootstrap_less" name="option_bootstrap_less" inherit_id="website.theme" active="False" customize_show="False">
 +    <xpath expr="//link[@id='bootstrap_css']" position="replace">
 +        <link rel="stylesheet" href='/website/static/src/less/import_bootstrap.less'/>
 +        <link rel="stylesheet" href='/website/static/src/less/colors.less' t-ignore="true"/>
 +    </xpath>
 +</template>
 +
 +<!-- Option layout -->
 +
- <template id="option_layout_boxed" name="option_layout_boxed" inherit_id="website.theme" optional="disabled">
++<template id="option_layout_boxed" name="option_layout_boxed" inherit_id="website.theme" active="False" customize_show="False">
 +    <xpath expr="//link[last()]" position="after">
 +        <link href="/website/static/src/less/option_layout_boxed.less" rel="stylesheet" type="text/less"/>
 +    </xpath>
 +</template>
 +
 +<!-- Option color -->
 +
- <template id="option_color_stone" name="option_color_stone" inherit_id="website.theme" optional="disabled">
++<template id="option_color_stone" name="option_color_stone" inherit_id="website.theme" active="False" customize_show="False">
 +    <xpath expr="//link[last()]" position="after"><link href="/website/static/src/less/option_color_stone.less" rel="stylesheet" type="text/less"/></xpath>
 +</template>
- <template id="option_color_emerald" name="option_color_emerald" inherit_id="website.theme" optional="disabled">
++<template id="option_color_emerald" name="option_color_emerald" inherit_id="website.theme" active="False" customize_show="False">
 +    <xpath expr="//link[last()]" position="after"><link href="/website/static/src/less/option_color_emerald.less" rel="stylesheet" type="text/less"/></xpath>
 +</template>
- <template id="option_color_cobalt" name="option_color_cobalt" inherit_id="website.theme" optional="disabled">
++<template id="option_color_cobalt" name="option_color_cobalt" inherit_id="website.theme" active="False" customize_show="False">
 +    <xpath expr="//link[last()]" position="after"><link href="/website/static/src/less/option_color_cobalt.less" rel="stylesheet" type="text/less"/></xpath>
 +</template>
- <template id="option_color_amethyst" name="option_color_amethyst" inherit_id="website.theme" optional="disabled">
++<template id="option_color_amethyst" name="option_color_amethyst" inherit_id="website.theme" active="False" customize_show="False">
 +    <xpath expr="//link[last()]" position="after"><link href="/website/static/src/less/option_color_amethyst.less" rel="stylesheet" type="text/less"/></xpath>
 +</template>
- <template id="option_color_ruby" name="option_color_ruby" inherit_id="website.theme" optional="disabled">
++<template id="option_color_ruby" name="option_color_ruby" inherit_id="website.theme" active="False" customize_show="False">
 +    <xpath expr="//link[last()]" position="after"><link href="/website/static/src/less/option_color_ruby.less" rel="stylesheet" type="text/less"/></xpath>
 +</template>
- <template id="option_color_gold" name="option_color_gold" inherit_id="website.theme" optional="disabled">
++<template id="option_color_gold" name="option_color_gold" inherit_id="website.theme" active="False" customize_show="False">
 +    <xpath expr="//link[last()]" position="after"><link href="/website/static/src/less/option_color_gold.less" rel="stylesheet" type="text/less"/></xpath>
 +</template>
 +
- <template id="option_font" name="option_font" inherit_id="website.theme" optional="disabled">
++<template id="option_font" name="option_font" inherit_id="website.theme" active="False" customize_show="False">
 +    <xpath expr="//link[last()]" position="after"><link href="/website/static/src/less/option_font.less" rel="stylesheet" type="text/less"/></xpath>
 +</template>
  
  </data>
  </openerp>
  </template>
  
  <!-- Page -->
 -<template id="assets_frontend" inherit_id="website.assets_frontend" name="website_blog assets" >
 -    <xpath expr="/t" position="inside">
 -        <link rel='stylesheet' href='/website_blog/static/src/css/website_blog.css'/>
 -        <script type="text/javascript" src="/website_blog/static/src/js/website_blog.inline.discussion.js"></script>
 -        <script type="text/javascript" src="/website_blog/static/src/js/website_blog.js"/>
 -        <script type="text/javascript" src="/website_blog/static/lib/contentshare.js"/>
 -    </xpath>
 -</template>
 -
  <template id="index" name="Blog Navigation">
      <t t-call="website.layout">
-         <div id="wrap" class="js_blog">
+         <div id="wrap" class="js_blog website_blog">
              <t t-raw="0"/>
          </div>
      </t>
@@@ -2,16 -2,16 +2,16 @@@
  <openerp>
  <data>
  
 -<template name="Sponsors" id="event_sponsor" customize_show="True" inherit_id="website_event.layout">
 -    <xpath expr="//t[@t-call='website.layout']" position="inside">
 -        <t t-set="head">
 -            <link rel='stylesheet' href='/website_event_track/static/src/css/website_event_track.css'/>
 -            <t t-raw="head or ''"/>
 -        </t>
 +<template id="assets_frontend" inherit_id="website.assets_frontend" name="Website Event Track Assets">
 +    <xpath expr="." position="inside">
 +        <script type="text/javascript" src="/website_event_track/static/src/js/website_event_track.js"></script>
      </xpath>
 +</template>
 +
- <template name="Sponsors" id="event_sponsor" optional="enabled" inherit_id="website_event.layout">
++<template name="Sponsors" id="event_sponsor" customize_show="True" inherit_id="website_event.layout">
      <xpath expr="//div[@id='wrap']" position="inside">
          <div class="container mt32 mb16 hidden-print" t-if="event.sponsor_ids">
 -            <section data-snippet-id="title">
 +            <section>
                  <h2 class="text-center mb32">Our Sponsors</h2>
              </section>
              <div class="row">
Simple merge
@@@ -2,11 -2,10 +2,10 @@@
  <openerp>
      <data>
  
- <!-- Editor custo -->
+ <!-- Editor custom -->
 -<template id="assets_frontend" inherit_id="website.assets_frontend" name="website_forum assets">
 -    <xpath expr="/t" position="inside">
 +<template id="assets_editor" inherit_id="website.assets_editor" name="Forum Editor Assets">
 +    <xpath expr="." position="inside">
          <link rel='stylesheet' href="/website_forum/static/src/css/website_forum.css"/>
          <script type="text/javascript" src="/website_forum/static/src/js/website.tour.forum.js"/>
          <script type="text/javascript" src="/website_forum/static/src/js/website_forum.editor.js"/>
      </xpath>
  <template id="header" name="Forum Index">
      <t t-call="website.layout">
          <t t-set="head">
 -            <script type="text/javascript" src="/web/static/lib/ckeditor/ckeditor.js"/>
 -            <script type="text/javascript">
 -                CKEDITOR.config.toolbar = [['Bold','Italic','Underline','Strike'],['NumberedList','BulletedList', 'Blockquote']
 -                ,['Outdent','Indent','Link','Unlink','Image'],] ;
 -            </script>
 +            <t t-call-assets="website_forum.assets_forum"/>
+             <t t-raw="0"/>
          </t>
-         <div class="container mt16">
+         <div class="container mt16 website_forum">
              <div class="navbar navbar-default">
                  <div class="navbar-header">
                      <button type="button" class="navbar-toggle" data-toggle="collapse" data-target="#oe-help-navbar-collapse">
  <!-- Specific Post Layout -->
  <template id="post_description_full" name="Question Navigation">
      <t t-call="website_forum.header">
-         <div t-attf-class="question">
 -        <div t-attf-class="row question #{not question.active and 'alert alert-danger' or ''}">
++        <div t-attf-class="row question">
              <div class="col-md-2 hidden-xs text-center">
                  <t t-call="website_forum.vote">
                      <t t-set="post" t-value="question"/>
          <div class="col-sm-10 col-sm-offset-2">
              <div t-foreach="reversed(object.website_message_ids)" t-as="message" class="comment oe_comment_grey">
                  <small class="text-muted">
-                     <button type="button" t-if="user.partner_id.id == message.author_id.id and user.karma&gt;=750"
-                         t-attf-data-href="/forum/#{slug(forum)}/post/#{slug(object)}/comment/#{slug(message)}/delete"
-                         class="close comment_delete">&amp;times;</button>
+                     <t t-set="required_karma" t-value="message.author_id.id == user.partner_id.id and object.forum_id.karma_comment_unlink_own or object.forum_id.karma_comment_unlink_all"/>
+                     <t t-call="website_forum.link_button">
+                         <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/delete'"/>
+                         <t t-set="label" t-value="' '"/>
+                         <t t-set="karma" t-value="user.karma&lt;required_karma and required_karma or 0"/>
+                         <t t-set="classes" t-value="'close comment_delete fa-times'"/>
+                     </t>
                      <span t-field="message.body"/>
                      <t t-set="required_karma" t-value="message.author_id.id == user.partner_id.id and object.forum_id.karma_comment_convert_own or object.forum_id.karma_comment_convert_all"/>
 -                    <t t-call="website_forum.link_button">
 -                        <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/convert_to_answer'"/>
 -                        <t t-set="label" t-value="'Convert as an answer'"/>
 -                        <t t-set="karma" t-value="user.karma&lt;required_karma and required_karma or 0"/>
 -                        <t t-set="classes" t-value="'fa-magic pull-right'"/>
 +                    <t t-if="(object.parent_id and object.parent_id.state != 'close' and object.parent_id.active != False) or (not object.parent_id and object.state != 'close' and object.active != False)">
 +                        <t t-set="allow_post_comment" t-value="True" />
 +                    </t>
 +                    <t t-if="allow_post_comment">
 +                        <t t-call="website_forum.link_button" >
 +                            <t t-set="url" t-value="'/forum/' + slug(forum) + '/post/' + slug(object) + '/comment/' + slug(message) + '/convert_to_answer'"/>
 +                            <t t-set="label" t-value="'Convert as an answer'"/>
 +                            <t t-set="karma" t-value="user.karma&lt;required_karma and required_karma or 0"/>
 +                            <t t-set="classes" t-value="'fa-magic pull-right'"/>
 +                        </t>
                      </t>
                      <a t-attf-href="/forum/#{slug(forum)}/partner/#{message.author_id.id}"
                          t-field="message.author_id" t-field-options='{"widget": "contact", "country_image": true, "fields": ["name", "country_id"]}'
@@@ -13,9 -14,9 +14,10 @@@ OpenERP Sale Quote Rolle
      'data': [
          'views/website_quotation.xml',
          'views/website_quotation_backend.xml',
+         'views/report_saleorder.xml',
          'data/website_quotation_data.xml',
          'security/ir.model.access.csv',
 +        'data/quotation_tip_data.xml',
      ],
      'demo': [
          'data/website_quotation_demo.xml'
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -37,10 -37,8 +37,10 @@@ from lxml import etre
  import openerp
  from openerp import tools, api
  from openerp.http import request
 +from openerp.modules.module import get_resource_path, get_resource_from_path
  from openerp.osv import fields, osv, orm
- from openerp.tools import config, graph, SKIPPED_ELEMENT_TYPES
 -from openerp.tools import graph, SKIPPED_ELEMENT_TYPES, SKIPPED_ELEMENTS
++from openerp.tools import config, graph, SKIPPED_ELEMENT_TYPES, SKIPPED_ELEMENTS
 +from openerp.tools.convert import _fix_multiple_roots
  from openerp.tools.parse_version import parse_version
  from openerp.tools.safe_eval import safe_eval as eval
  from openerp.tools.view_validation import valid_view
Simple merge
Simple merge
Simple merge
@@@ -62,9 -62,15 +62,15 @@@ DEFAULT_LOG_HANDLER = [':INFO'
  
  def _get_default_datadir():
      home = os.path.expanduser('~')
-     func = appdirs.user_data_dir if os.path.isdir(home) else appdirs.site_data_dir
 -    if os.path.exists(home):
++    if os.path.isdir(home):
+         func = appdirs.user_data_dir
+     else:
+         if sys.platform in ['win32', 'darwin']:
+             func = appdirs.site_data_dir
+         else:
+             func = lambda **kwarg: "/var/lib/%s" % kwarg['appname'].lower()
      # No "version" kwarg as session and filestore paths are shared against series
-     return func(appname='Odoo', appauthor=release.author)
+     return func(appname=release.product_name, appauthor=release.author)
  
  class configmanager(object):
      def __init__(self, fname=None):
@@@ -961,20 -867,19 +875,20 @@@ form: module.record_id""" % (xml_id,
              report = assertion_report.assertion_report()
          self.assertion_report = report
          self.noupdate = noupdate
 +        self.xml_filename = xml_filename
          self._tags = {
-             'menuitem': self._tag_menuitem,
              'record': self._tag_record,
-             'template': self._tag_template,
-             'assert': self._tag_assert,
-             'report': self._tag_report,
-             'wizard': self._tag_wizard,
              'delete': self._tag_delete,
-             'ir_set': self._tag_ir_set,
              'function': self._tag_function,
+             'menuitem': self._tag_menuitem,
+             'template': self._tag_template,
              'workflow': self._tag_workflow,
+             'report': self._tag_report,
+             'ir_set': self._tag_ir_set,
              'act_window': self._tag_act_window,
-             'url': self._tag_url
+             'url': self._tag_url,
+             'assert': self._tag_assert,
          }
  
  def convert_file(cr, module, filename, idref, mode='update', noupdate=False, kind=None, report=None, pathname=None):
@@@ -1075,12 -981,8 +990,12 @@@ def convert_xml_import(cr, module, xmlf
  
      if idref is None:
          idref={}
 -    obj = xml_import(cr, module, idref, mode, report=report, noupdate=noupdate)
 +    if isinstance(xmlfile, file):
 +        xml_filename = xmlfile.name
 +    else:
 +        xml_filename = xmlfile
 +    obj = xml_import(cr, module, idref, mode, report=report, noupdate=noupdate, xml_filename=xml_filename)
-     obj.parse(doc.getroot())
+     obj.parse(doc.getroot(), mode=mode)
      return True
  
  
Simple merge
Simple merge
Simple merge