[MERGE] forward port of branch 8.0 up to 2b192be
authorChristophe Simonis <chs@odoo.com>
Thu, 16 Oct 2014 14:04:39 +0000 (16:04 +0200)
committerChristophe Simonis <chs@odoo.com>
Thu, 16 Oct 2014 14:04:39 +0000 (16:04 +0200)
57 files changed:
1  2 
README.md
addons/account/account_bank_statement.py
addons/account/account_invoice.py
addons/account/res_config.py
addons/account_analytic_analysis/account_analytic_analysis.py
addons/calendar/calendar.py
addons/crm/crm_lead.py
addons/event/event.py
addons/hr_holidays/hr_holidays.py
addons/mrp/mrp.py
addons/point_of_sale/point_of_sale_view.xml
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/xml/pos.xml
addons/product/product.py
addons/product/product_view.xml
addons/project/project.py
addons/purchase/purchase.py
addons/purchase/purchase_view.xml
addons/stock/static/src/js/widgets.js
addons/stock/stock.py
addons/stock_landed_costs/stock_landed_costs_view.xml
addons/web/static/src/css/base.css
addons/web/static/src/css/base.sass
addons/web/static/src/js/openerpframework.js
addons/web/static/src/js/view_form.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/models/ir_http.py
addons/website/models/ir_qweb.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.js
addons/website/static/src/js/website.snippets.editor.js
addons/website/static/src/xml/website.editor.xml
addons/website/views/snippets.xml
addons/website_event/data/event_demo.xml
addons/website_event/models/event.py
addons/website_event_sale/static/src/js/website.tour.event_sale.js
addons/website_membership/views/website_membership.xml
addons/website_quote/data/website_quotation_data.xml
addons/website_quote/models/order.py
addons/website_quote/views/website_quotation.xml
addons/website_sale/controllers/main.py
addons/website_sale/views/templates.xml
doc/conf.py
openerp/addons/base/ir/ir_attachment.py
openerp/addons/base/ir/ir_model.py
openerp/addons/base/ir/ir_qweb.py
openerp/addons/base/ir/ir_ui_view.py
openerp/addons/base/res/res_users.py
openerp/models.py
openerp/tools/config.py
openerp/tools/mail.py

diff --cc README.md
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -154,18 -139,21 +154,23 @@@ class event_event(models.Model)
          else:
              self.date_end_located = False
  
+     @api.one
+     @api.depends('address_id')
+     def _compute_country(self):
+         self.country_id = self.address_id.country_id
 -    date_begin_located = fields.Datetime(string='Start Date Located', compute='_compute_date_begin_tz')
 -    date_end_located = fields.Datetime(string='End Date Located', compute='_compute_date_end_tz')
 -
      state = fields.Selection([
 -            ('draft', 'Unconfirmed'),
 -            ('cancel', 'Cancelled'),
 -            ('confirm', 'Confirmed'),
 -            ('done', 'Done')
 -        ], string='Status', default='draft', readonly=True, required=True, copy=False,
 +        ('draft', 'Unconfirmed'), ('cancel', 'Cancelled'),
 +        ('confirm', 'Confirmed'), ('done', 'Done')],
 +        string='Status', default='draft', readonly=True, required=True, copy=False,
          help="If event is created, the status is 'Draft'. If event is confirmed for the particular dates the status is set to 'Confirmed'. If the event is over, the status is set to 'Done'. If event is cancelled the status is set to 'Cancelled'.")
 +    auto_confirm = fields.Boolean(string='Auto Confirmation Activated', compute='_compute_auto_confirm')
 +
 +    @api.one
 +    def _compute_auto_confirm(self):
 +        self.auto_confirm = self.env['ir.values'].get_default('marketing.config.settings', 'auto_confirmation')
 +
 +    # Mailing
      email_registration_id = fields.Many2one(
          'email.template', string='Registration Confirmation Email',
          domain=[('model', '=', 'event.registration')],
          'email.template', string='Event Confirmation Email',
          domain=[('model', '=', 'event.registration')],
          help="If you set an email template, each participant will receive this email announcing the confirmation of the event.")
 -    reply_to = fields.Char(string='Reply-To Email',
 -        readonly=False, states={'done': [('readonly', True)]},
 +    reply_to = fields.Char(
 +        string='Reply-To Email', readonly=False, states={'done': [('readonly', True)]},
          help="The email address of the organizer is likely to be put here, with the effect to be in the 'Reply-To' of the mails sent automatically at event or registrations confirmation. You can also put the email address of your mail gateway if you use one.")
 -    address_id = fields.Many2one('res.partner', string='Location',
 -        default=lambda self: self.env.user.company_id.partner_id,
 +    address_id = fields.Many2one(
 +        'res.partner', string='Location', default=lambda self: self.env.user.company_id.partner_id,
          readonly=False, states={'done': [('readonly', True)]})
-     country_id = fields.Many2one(
-         'res.country', string='Country', related='address_id.country_id',
-         store=True, readonly=False, states={'done': [('readonly', True)]})
+     country_id = fields.Many2one('res.country', string='Country',
+         store=True, compute='_compute_country')
 -    description = fields.Html(string='Description', oldname='note', translate=True,
 +    description = fields.Html(
 +        string='Description', oldname='note', translate=True,
          readonly=False, states={'done': [('readonly', True)]})
 -    company_id = fields.Many2one('res.company', string='Company', change_default=True,
 -        default=lambda self: self.env['res.company']._company_default_get('event.event'),
 -        required=False, readonly=False, states={'done': [('readonly', True)]})
 -    organizer_id = fields.Many2one('res.partner', string='Organizer',
 -        default=lambda self: self.env.user.company_id.partner_id)
 -
 -    is_subscribed = fields.Boolean(string='Subscribed',
 -        compute='_compute_subscribe')
 -
 -    @api.one
 -    @api.depends('registration_ids')
 -    def _count_registrations(self):
 -        self.count_registrations = len(self.registration_ids)
 -
 -    @api.one
 -    @api.depends('registration_ids.user_id', 'registration_ids.state')
 -    def _compute_subscribe(self):
 -        """ Determine whether the current user is already subscribed to any event in `self` """
 -        user = self.env.user
 -        self.is_subscribed = any(
 -            reg.user_id == user and reg.state in ('open', 'done')
 -            for reg in self.registration_ids
 -        )
  
      @api.multi
      @api.depends('name', 'date_begin', 'date_end')
Simple merge
Simple merge
@@@ -1080,158 -1105,155 +1080,166 @@@ function openerp_pos_screens(instance, 
                  }
              }
          },
 -        back: function() {
 -            this.remove_empty_lines();
 -            this.pos_widget.screen_selector.set_current_screen(this.back_screen);
 +        click_numpad: function(button) {
 +            this.payment_input(button.data('action'));
          },
 -        bind_events: function() {
 -            if(this.old_order){
 -                this.old_order.unbind(null,null,this);
 -            }
 -            var order = this.pos.get('selectedOrder');
 -                order.bind('change:selected_paymentline',this.focus_selected_line,this);
 -
 -            this.old_order = order;
 -
 -            if(this.old_paymentlines){
 -                this.old_paymentlines.unbind(null,null,this);
 -            }
 -            var paymentlines = order.get('paymentLines');
 -                paymentlines.bind('add', this.add_paymentline, this);
 -                paymentlines.bind('change:selected', this.rerender_paymentline, this);
 -                paymentlines.bind('change:amount', function(line){
 -                        if(!line.selected && line.node){
 -                            line.node.value = line.amount.toFixed(2);
 -                        }
 -                        this.update_payment_summary();
 -                    },this);
 -                paymentlines.bind('remove', this.remove_paymentline, this);
 -                paymentlines.bind('all', this.update_payment_summary, this);
 -
 -            this.old_paymentlines = paymentlines;
 -
 -            if(this.old_orderlines){
 -                this.old_orderlines.unbind(null,null,this);
 +        render_numpad: function() {
 +            var self = this;
 +            var numpad = $(QWeb.render('PaymentScreen-Numpad', { widget:this }));
 +            numpad.on('click','button',function(){
 +                self.click_numpad($(this));
 +            });
 +            return numpad;
 +        },
 +        click_delete_paymentline: function(cid){
 +            var lines = this.pos.get_order().get('paymentLines').models;
 +            for ( var i = 0; i < lines.length; i++ ) {
 +                if (lines[i].cid === cid) {
 +                    this.pos.get_order().removePaymentline(lines[i]);
 +                    this.reset_input();
 +                    this.render_paymentlines();
 +                    return;
 +                }
              }
 -            var orderlines = order.get('orderLines');
 -                orderlines.bind('all', this.update_payment_summary, this);
 -
 -            this.old_orderlines = orderlines;
          },
 -        focus_selected_line: function(){
 -            var line = this.pos.get('selectedOrder').selected_paymentline;
 -            if(line){
 -                var input = line.node.querySelector('input');
 -                if(!input){
 +        click_paymentline: function(cid){
 +            var lines = this.pos.get_order().get('paymentLines').models;
 +            for ( var i = 0; i < lines.length; i++ ) {
 +                if (lines[i].cid === cid) {
 +                    this.pos.get_order().selectPaymentline(lines[i]);
 +                    this.reset_input();
 +                    this.render_paymentlines();
                      return;
                  }
 -                var value = input.value;
 -                input.focus();
 +            }
 +        },
 +        render_paymentlines: function() {
 +            var self  = this;
 +            var order = this.pos.get_order();
 +            var lines = order.get('paymentLines').models;
  
 -                if(this.numpad_state){
 -                    this.numpad_state.reset();
 -                }
 +            this.$('.paymentlines-container').empty();
 +            var lines = $(QWeb.render('PaymentScreen-Paymentlines', { 
 +                widget: this, 
 +                order: order,
 +                paymentlines: lines,
 +            }));
  
 -                if(Number(value) === 0){
 -                    input.value = '';
 -                }else{
 -                    input.value = value;
 -                    input.select();
 +            lines.on('click','.delete-button',function(){
 +                self.click_delete_paymentline($(this).data('cid'));
 +            });
 +
 +            lines.on('click','.paymentline',function(){
 +                self.click_paymentline($(this).data('cid'));
 +            });
 +                
 +            lines.appendTo(this.$('.paymentlines-container'));
 +        },
 +        click_paymentmethods: function(id) {
 +            var cashregister = null;
 +            for ( var i = 0; i < this.pos.cashregisters.length; i++ ) {
 +                if ( this.pos.cashregisters[i].journal_id[0] === id ){
 +                    cashregister = this.pos.cashregisters[i];
 +                    break;
                  }
              }
 +            this.pos.get_order().addPaymentline( cashregister );
 +            this.reset_input();
 +            this.render_paymentlines();
          },
 -        add_paymentline: function(line) {
 -            var list_container = this.el.querySelector('.payment-lines');
 -                list_container.appendChild(this.render_paymentline(line));
 -            
 -            if(this.numpad_state){
 -                this.numpad_state.reset();
 +        render_paymentmethods: function() {
 +            var self = this;
 +            var methods = $(QWeb.render('PaymentScreen-Paymentmethods', { widget:this }));
 +                methods.on('click','.paymentmethod',function(){
 +                    self.click_paymentmethods($(this).data('id'));
 +                });
 +            return methods;
 +        },
 +        click_invoice: function(){
 +            var order = this.pos.get_order();
 +            order.set_to_invoice(!order.is_to_invoice());
 +            if (order.is_to_invoice()) {
 +                this.$('.js_invoice').addClass('highlight');
 +            } else {
 +                this.$('.js_invoice').removeClass('highlight');
              }
          },
 -        render_paymentline: function(line){
 -            var el_html  = openerp.qweb.render('Paymentline',{widget: this, line: line});
 -                el_html  = _.str.trim(el_html);
 +        renderElement: function() {
 +            var self = this;
 +            this._super();
  
 -            var el_node  = document.createElement('tbody');
 -                el_node.innerHTML = el_html;
 -                el_node = el_node.childNodes[0];
 -                el_node.line = line;
 -                el_node.querySelector('.paymentline-delete')
 -                    .addEventListener('click', this.line_delete_handler);
 -                el_node.addEventListener('click', this.line_click_handler);
 -                el_node.querySelector('input')
 -                    .addEventListener('keyup', this.line_change_handler);
 +            var numpad = this.render_numpad();
 +            numpad.appendTo(this.$('.payment-numpad'));
  
 -            line.node = el_node;
 +            var methods = this.render_paymentmethods();
 +            methods.appendTo(this.$('.paymentmethods-container'));
 +
 +            this.render_paymentlines();
 +
 +            this.$('.back').click(function(){
 +                self.pos_widget.screen_selector.back();
 +            });
 +
 +            this.$('.next').click(function(){
 +                self.validate_order();
 +            });
 +
 +            this.$('.js_invoice').click(function(){
 +                self.click_invoice();
 +            });
  
 -            return el_node;
 -        },
 -        rerender_paymentline: function(line){
 -            var old_node = line.node;
 -            var new_node = this.render_paymentline(line);
 -            
 -            old_node.parentNode.replaceChild(new_node,old_node);
          },
 -        remove_paymentline: function(line){
 -            line.node.parentNode.removeChild(line.node);
 -            line.node = undefined;
 +        show: function(){
 +            this.pos.get_order().clean_empty_paymentlines();
 +            this.reset_input();
 +            this.render_paymentlines();
 +            this.order_changes();
 +            window.document.body.addEventListener('keydown',this.keyboard_handler);
 +            this._super();
          },
 -        renderElement: function(){
 +        hide: function(){
 +            window.document.body.removeEventListener('keydown',this.keyboard_handler);
              this._super();
 -
 -            var paymentlines   = this.pos.get('selectedOrder').get('paymentLines').models;
 -            var list_container = this.el.querySelector('.payment-lines');
 -
 -            for(var i = 0; i < paymentlines.length; i++){
 -                list_container.appendChild(this.render_paymentline(paymentlines[i]));
 -            }
 -            
 -            this.update_payment_summary();
 -        },
 -        update_payment_summary: function() {
 -            var currentOrder = this.pos.get('selectedOrder');
 -            var paidTotal = currentOrder.getPaidTotal();
 -            var dueTotal = currentOrder.getTotalTaxIncluded();
 -            var remaining = dueTotal > paidTotal ? dueTotal - paidTotal : 0;
 -            var change = paidTotal > dueTotal ? paidTotal - dueTotal : 0;
 -
 -            this.$('.payment-due-total').html(this.format_currency(dueTotal));
 -            this.$('.payment-paid-total').html(this.format_currency(paidTotal));
 -            this.$('.payment-remaining').html(this.format_currency(remaining));
 -            this.$('.payment-change').html(this.format_currency(change));
 -            if(currentOrder.selected_orderline === undefined){
 -                remaining = 1;  // What is this ? 
 -            }
 -                
 -            if(this.pos_widget.action_bar){
 -                this.pos_widget.action_bar.set_button_disabled('validation', !this.is_paid());
 -                this.pos_widget.action_bar.set_button_disabled('invoice', !this.is_paid());
 +        },
 +        // sets up listeners to watch for order changes
 +        watch_order_changes: function() {
 +            var self = this;
 +            var order = this.pos.get_order();
 +            if(this.old_order){
 +                this.old_order.unbind(null,null,this);
              }
 +            order.bind('all',function(){
 +                self.order_changes();
 +            });
 +            this.old_order = order;
          },
 -        is_paid: function(){
 -            var currentOrder = this.pos.get('selectedOrder');
 -            return (currentOrder.getTotalTaxIncluded() < 0.000001 
 -                   || currentOrder.getPaidTotal() + 0.000001 >= currentOrder.getTotalTaxIncluded());
 -
 +        // called when the order is changed, used to show if
 +        // the order is paid or not
 +        order_changes: function(){
 +            var self = this;
 +            var order = this.pos.get_order();
 +            if (order.isPaid()) {
 +                self.$('.next').addClass('highlight');
 +            }else{
 +                self.$('.next').removeClass('highlight');
 +            }
          },
 -        validate_order: function(options) {
 +        // Check if the order is paid, then sends it to the backend,
 +        // and complete the sale process
 +        validate_order: function() {
              var self = this;
 -            options = options || {};
  
 -            var currentOrder = this.pos.get('selectedOrder');
 +            var order = this.pos.get_order();
  
 -            if(currentOrder.get('orderLines').models.length === 0){
++            if(order.get('orderLines').models.length === 0){
+                 this.pos_widget.screen_selector.show_popup('error',{
+                     'message': _t('Empty Order'),
+                     'comment': _t('There must be at least one product in your order before it can be validated'),
+                 });
+                 return;
+             }
 -            if(!this.is_paid()){
 +            if (!order.isPaid() || this.invoicing) {
                  return;
              }
  
@@@ -41,11 -33,11 +41,11 @@@ function openerp_pos_basewidget(instanc
                      amount = amount.toFixed(decimals);
                  }
                  if(this.currency.position === 'after'){
-                     return amount + ' ' + this.currency.symbol;
+                     return amount + ' ' + (this.currency.symbol || '');
                  }else{
-                     return this.currency.symbol + ' ' + amount;
+                     return (this.currency.symbol || '') + ' ' + amount;
                  }
 -            }
 +            };
  
          },
          show: function(){
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -1,4 -1,4 +1,4 @@@
--@charset "utf-8";
++@charset "UTF-8";
  /*       THIS CSS FILE IS FOR WEBSITE THEMING CUSTOMIZATION ONLY
   *
   * css for editor buttons, openerp widget included in the website and other
  
  /* Extra Styles */
  img.shadow {
--  -webkit-border-radius: 3px;
    -moz-border-radius: 3px;
--  -ms-border-radius: 3px;
--  -o-border-radius: 3px;
++  -webkit-border-radius: 3px;
    border-radius: 3px;
--  -webkit-box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.2);
    -moz-box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.2);
++  -webkit-box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.2);
    box-shadow: 0px 3px 8px rgba(0, 0, 0, 0.2);
    margin: 0 auto;
  }
@@@ -104,7 -104,7 +102,7 @@@ header a.navbar-brand img 
  }
  
  #wrapwrap p:empty:after {
--  content: "\2060";
++  content: "⁠";
  }
  
  /* ----- Snippets Styles ----- */
  #oe_main_menu_navbar {
    min-height: 34px;
    z-index: 1001;
--  -webkit-border-radius: 0px;
    -moz-border-radius: 0px;
--  -ms-border-radius: 0px;
--  -o-border-radius: 0px;
++  -webkit-border-radius: 0px;
    border-radius: 0px;
    margin-bottom: 0px;
  }
  
  /* ----- BOOTSTRAP HACK FOR STICKY FOOTER ----- */
  html, body, #wrapwrap {
--  -webkit-box-sizing: border-box;
    -moz-box-sizing: border-box;
++  -webkit-box-sizing: border-box;
    box-sizing: border-box;
    height: 100%;
  }
@@@ -356,114 -360,63 +352,171 @@@ ul.nav-stacked > li > a 
    padding: 4px 0;
  }
  
+ .o_image_floating {
+   width: 40%;
+   margin: 4px;
+ }
+ .o_image_floating div.o_container {
+   position: relative;
+ }
+ .o_image_floating div.o_container mark {
+   display: block;
+   position: absolute;
+   bottom: 0;
+   width: 100%;
+   background-color: rgba(86, 61, 124, 0.25);
+ }
+ .o_image_floating div.o_container mark a {
+   color: white;
+ }
+ .o_image_floating.o_hide_link div.o_container mark {
+   display: none;
+ }
+ .o_image_floating.o_margin_s {
+   margin-bottom: 4px;
+ }
+ .o_image_floating.o_margin_s.pull-right {
+   margin-left: 8px;
+ }
+ .o_image_floating.o_margin_s.pull-left {
+   margin-right: 8px;
+ }
+ .o_image_floating.o_margin_m {
+   margin-bottom: 8px;
+ }
+ .o_image_floating.o_margin_m.pull-right {
+   margin-left: 12px;
+ }
+ .o_image_floating.o_margin_m.pull-left {
+   margin-right: 12px;
+ }
+ .o_image_floating.o_margin_l {
+   margin-bottom: 12px;
+ }
+ .o_image_floating.o_margin_l.pull-right {
+   margin-left: 16px;
+ }
+ .o_image_floating.o_margin_l.pull-left {
+   margin-right: 16px;
+ }
+ .o_image_floating.o_margin_xl {
+   margin-bottom: 24px;
+ }
+ .o_image_floating.o_margin_xl.pull-right {
+   margin-left: 32px;
+ }
+ .o_image_floating.o_margin_xl.pull-left {
+   margin-right: 32px;
+ }
 +/* gallery */
 +.o_gallery.o_grid.o_spc-none div.row, .o_gallery.o_masonry.o_spc-none div.row {
 +  margin: 0;
 +}
 +.o_gallery.o_grid.o_spc-none div.row > *, .o_gallery.o_masonry.o_spc-none div.row > * {
 +  padding: 0;
 +}
 +.o_gallery.o_grid.o_spc-small div.row, .o_gallery.o_masonry.o_spc-small div.row {
 +  margin: 5px 0;
 +}
 +.o_gallery.o_grid.o_spc-small div.row > *, .o_gallery.o_masonry.o_spc-small div.row > * {
 +  padding: 0 5px;
 +}
 +.o_gallery.o_grid.o_spc-medium div.row, .o_gallery.o_masonry.o_spc-medium div.row {
 +  margin: 10px 0;
 +}
 +.o_gallery.o_grid.o_spc-medium div.row > *, .o_gallery.o_masonry.o_spc-medium div.row > * {
 +  padding: 0 10px;
 +}
 +.o_gallery.o_grid.o_spc-big div.row, .o_gallery.o_masonry.o_spc-big div.row {
 +  margin: 15px 0;
 +}
 +.o_gallery.o_grid.o_spc-big div.row > *, .o_gallery.o_masonry.o_spc-big div.row > * {
 +  padding: 0 15px;
 +}
 +.o_gallery.o_grid .img, .o_gallery.o_masonry .img {
 +  width: 100%;
 +}
 +.o_gallery.o_grid.size-auto .row {
 +  height: auto;
 +}
 +.o_gallery.o_grid.size-small .row {
 +  height: 100px;
 +}
 +.o_gallery.o_grid.size-medium .row {
 +  height: 250px;
 +}
 +.o_gallery.o_grid.size-big .row {
 +  height: 400px;
 +}
 +.o_gallery.o_grid.size-small .img, .o_gallery.o_grid.size-medium .img, .o_gallery.o_grid.size-big .img {
 +  height: 100%;
 +}
 +.o_gallery.o_nomode.o_spc-none .img {
 +  padding: 0;
 +}
 +.o_gallery.o_nomode.o_spc-small .img {
 +  padding: 5px;
 +}
 +.o_gallery.o_nomode.o_spc-medium .img {
 +  padding: 10px;
 +}
 +.o_gallery.o_nomode.o_spc-big .img {
 +  padding: 15px;
 +}
 +.o_gallery.o_slideshow .carousel ul.carousel-indicators li {
-   border: 1px solid #aaaaaa;
++  border: 1px solid #aaa;
 +}
 +.o_gallery .carousel-inner .item img {
 +  max-width: none;
 +}
 +
 +.o_gallery.o_slideshow > .container {
 +  height: 100%;
 +}
 +
 +.o_gallery.o_slideshow .carousel, .modal-body.o_slideshow .carousel {
 +  height: 100%;
 +}
 +.o_gallery.o_slideshow .carousel img, .modal-body.o_slideshow .carousel img {
 +  max-height: 100%;
 +  max-width: 100%;
 +  margin: auto;
 +  position: relative;
 +  top: 50%;
 +  -webkit-transform: translateY(-50%);
 +  -ms-transform: translateY(-50%);
 +  transform: translateY(-50%);
 +}
 +.o_gallery.o_slideshow .carousel ul.carousel-indicators, .modal-body.o_slideshow .carousel ul.carousel-indicators {
 +  display: block;
 +  height: auto;
 +  padding: 0;
 +  border-width: 0;
 +  position: absolute;
 +  bottom: 0;
 +}
 +.o_gallery.o_slideshow .carousel ul.carousel-indicators li, .modal-body.o_slideshow .carousel ul.carousel-indicators li {
 +  list-style-image: none;
 +  display: inline-block;
 +  width: 35px;
 +  height: 35px;
 +  margin: 0 0px 5px 5px;
 +  padding: 0;
-   border: 1px solid #aaaaaa;
++  border: 1px solid #aaa;
 +  text-indent: initial;
 +  background-size: cover;
 +  opacity: 0.5;
-   background-color: black;
++  background-color: #000;
 +}
 +.o_gallery.o_slideshow .carousel ul.carousel-indicators li.active, .modal-body.o_slideshow .carousel ul.carousel-indicators li.active {
 +  opacity: 1;
 +}
 +.o_gallery.o_slideshow .carousel .carousel-control.left, .o_gallery.o_slideshow .carousel .carousel-control.right, .modal-body.o_slideshow .carousel .carousel-control.left, .modal-body.o_slideshow .carousel .carousel-control.right {
 +  background-image: none;
 +  background-color: transparent;
 +}
 +
  /* Parallax Theme */
  div.carousel .carousel-indicators li {
    border: 1px solid grey;
@@@ -497,6 -450,62 +550,62 @@@ div.carousel div.carousel-content 
    padding: 32px 0;
  }
  
 -/* Background */
++/* Background (kept for 8.0 compatibility) */
+ .oe_dark {
+   background: #eff8f8;
+   background: rgba(200, 200, 200, 0.14);
+ }
+ .oe_black {
+   background-color: rgba(0, 0, 0, 0.9);
+   color: white;
+ }
+ .oe_green {
 -  background-color: #169c78;
++  background-color: #169C78;
+   color: white;
+ }
+ .oe_green .text-muted {
 -  color: #dddddd;
++  color: #ddd;
+ }
+ .oe_blue_light {
+   background-color: #41b6ab;
+   color: white;
+ }
+ .oe_blue_light .text-muted {
 -  color: #dddddd;
++  color: #ddd;
+ }
+ .oe_blue {
+   background-color: #34495e;
+   color: white;
+ }
+ .oe_orange {
+   background-color: #f05442;
+   color: white;
+ }
+ .oe_orange .text-muted {
 -  color: #dddddd;
++  color: #ddd;
+ }
+ .oe_purple {
+   background-color: #b163a3;
+   color: white;
+ }
+ .oe_purple .text-muted {
 -  color: #dddddd;
++  color: #ddd;
+ }
+ .oe_red {
 -  background-color: #9c1b31;
++  background-color: #9C1b31;
+   color: white;
+ }
+ .oe_red .text-muted {
 -  color: #dddddd;
++  color: #ddd;
+ }
  /* Misc */
  .texttop {
    vertical-align: top;
@@@ -547,10 -556,10 +656,8 @@@ span[data-oe-type="monetary"] 
  }
  
  .oe_template_fallback {
--  -webkit-column-count: 3;
    -moz-column-count: 3;
--  -ms-column-count: 3;
--  -o-column-count: 3;
++  -webkit-column-count: 3;
    column-count: 3;
  }
  
@@@ -285,102 -288,48 +285,144 @@@ ul.nav-stacked > li > 
  .hr
      padding: 4px 0
  
+ .o_image_floating
+     width: 40%
+     margin: 4px
+     div.o_container
+         position: relative
+         mark
+             display: block
+             position: absolute
+             bottom: 0
+             width: 100%
+             background-color: rgba(86,61,124,.25)
+             a
+                 color: white
+     &.o_hide_link div.o_container mark
+         display: none
+     &.o_margin_s
+         margin-bottom: 4px
+         &.pull-right
+             margin-left: 8px
+         &.pull-left
+             margin-right: 8px
+     &.o_margin_m
+         margin-bottom: 8px
+         &.pull-right
+             margin-left: 12px
+         &.pull-left
+             margin-right: 12px
+     &.o_margin_l
+         margin-bottom: 12px
+         &.pull-right
+             margin-left: 16px
+         &.pull-left
+             margin-right: 16px
+     &.o_margin_xl
+         margin-bottom: 24px
+         &.pull-right
+             margin-left: 32px
+         &.pull-left
+             margin-right: 32px
 +/* gallery */
 +
 +.o_gallery
 +    &.o_grid, &.o_masonry
 +        &.o_spc-none
 +            div.row
 +                margin: 0
 +            div.row > *
 +                padding: 0
 +        &.o_spc-small
 +            div.row
 +                margin: 5px 0
 +            div.row > *
 +                padding: 0 5px
 +        &.o_spc-medium
 +            div.row
 +                margin: 10px 0
 +            div.row > *
 +                padding: 0 10px
 +        &.o_spc-big
 +            div.row
 +                margin: 15px 0
 +            div.row > *
 +                padding: 0 15px
 +        .img
 +            width: 100%
 +    &.o_grid
 +        &.size-auto .row
 +            height: auto
 +        &.size-small .row
 +            height: 100px
 +        &.size-medium .row
 +            height: 250px
 +        &.size-big .row
 +            height: 400px
 +        &.size-small, &.size-medium, &.size-big
 +            .img
 +                height: 100%
 +    &.o_nomode
 +        &.o_spc-none
 +            .img
 +                padding: 0
 +        &.o_spc-small
 +            .img
 +                padding: 5px
 +        &.o_spc-medium
 +            .img
 +                padding: 10px
 +        &.o_spc-big
 +            .img
 +                padding: 15px
 +
 +    &.o_slideshow .carousel ul.carousel-indicators li
 +        border: 1px solid #aaa
 +    .carousel-inner .item img
 +        max-width: none
 +
 +.o_gallery.o_slideshow > .container
 +    height: 100%
 +
 +.o_gallery.o_slideshow .carousel, .modal-body.o_slideshow .carousel
 +    height: 100%
 +    img
 +        max-height: 100%
 +        max-width: 100%
 +        margin: auto
 +        position: relative
 +        top: 50%
 +        -webkit-transform: translateY(-50%)
 +        -ms-transform: translateY(-50%)
 +        transform: translateY(-50%)
 +    ul.carousel-indicators
 +        display: block
 +        height: auto
 +        padding: 0
 +        border-width: 0
 +        position: absolute
 +        bottom: 0
 +        li
 +            list-style-image: none
 +            display: inline-block
 +            width: 35px
 +            height: 35px
 +            margin: 0 0px 5px 5px
 +            padding: 0
 +            border: 1px solid #aaa
 +            text-indent: initial
 +            background-size: cover
 +            opacity: 0.5
 +            background-color: #000
 +        li.active
 +            opacity: 1
 +    .carousel-control.left, .carousel-control.right
 +        background-image: none
 +        background-color: transparent
 +
  /* Parallax Theme */
  
  div.carousel
              vertical-align: middle
              padding: 32px 0
  
 -/* Background */
++/* Background (kept for 8.0 compatibility) */
+ .oe_dark
+     background: #eff8f8
+     background: rgba(200, 200, 200, 0.14)
+ .oe_black
+     background-color: rgba(0, 0, 0, 0.9)
+     color: white
+ .oe_green
+     background-color: #169C78
+     color: white
+     .text-muted
+         color: #ddd
+ .oe_blue_light
+     background-color: #41b6ab
+     color: white
+     .text-muted
+         color: #ddd
+ .oe_blue
+     background-color: #34495e
+     color: white
+ .oe_orange
+     background-color: #f05442
+     color: white
+     .text-muted
+         color: #ddd
+ .oe_purple
+     background-color: #b163a3
+     color: white
+     .text-muted
+         color: #ddd
+ .oe_red
+     background-color: #9C1b31
+     color: white
+     .text-muted
+         color: #ddd
  /* Misc */
  
  .texttop
              var self = this;
              this.$target.find('.carousel-control').off('click').on('click', function () {
                  self.$target.carousel( $(this).data('slide')); });
-             this.$target.find('.carousel-image, .carousel-inner .content > div').attr('contentEditable', 'true');
-             this.$target.find('.carousel-image').attr('attributeEditable', 'true');
              this._super();
+             /* Fix: backward compatibility saas-3 */
+             this.$target.find('.item.text_image, .item.image_text, .item.text_only').find('.container > .carousel-caption > div, .container > img.carousel-image').attr('contentEditable', 'true');
          },
      });
 -
      website.snippet.options.marginAndResize = website.snippet.Option.extend({
          start: function () {
              var self = this;
          </section>
      </div>
  
+     <div name="Image-Text" class="o_block_image_float">
+         <div class="oe_snippet_thumbnail">
+             <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_text_image.png"/>
+             <span class="oe_snippet_thumbnail_title">Image-Floating</span>
+         </div>
+         <section class="oe_snippet_body para_large">
+             <div class="container">
+                 <div class="row">
+                     <div class="col-md-12 mb16 mt16">
+                         <div class="o_image_floating o_margin_l pull-right">
+                             <div class="o_container">
+                                 <img class="img img-rounded img-responsive" src="/website/static/src/img/odoo.jpg"/>
+                                 <mark class="text-center"><a href="#"><strong>Click Here</strong></a></mark>
+                             </div>
+                             <div class="o_footer">
+                                 <small class="text-muted">A great way to catch your reader's attention is to tell a story. Everything you consider writing can be told as a story.</small>
+                             </div>
+                         </div>
+                         <h3>What a day it was yesterday - such a big day for us!</h3>
+                         <p style="text-align: justify;">
+                             In case you still feel a bit puzzled about all
+                             of our yesterday's announcements, here is a little
+                             summary for you. <br/>
+                             We have decided to change the
+                             name because <b>"OpenERP"</b> didn't reflect the offering
+                             of the company anymore. With our newest apps, such
+                             as Website Builder, PoS or eCommerce, we have
+                             moved beyond the ERP territory. <br/>
+                             But <u>don't worry</u>, <b>Odoo</b> is and always will be
+                             fully open source. You can read more about the new name here.
+                             We have also prepared a short FAQ to explain all these changes
+                             to all of you. <br/>
+                         </p>
+                         <h3>Discover more about Odoo</h3>
+                         <p style="text-align: justify;">
+                             With Odoo's fully integrated software, you can easily manage your
+                             meetings, schedule business calls, create recurring meetings,
+                             synchronize your agenda and easily keep in touch with your colleagues,
+                             partners and other people involved in projects or business discussions.
+                             <br/><br/><a href="#">Check now and discover more today!</a>
+                         </p>
+                     </div>
+                 </div>
+             </div>
+         </section>
+     </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_jumbotron.png"/>
 -            <span class="oe_snippet_thumbnail_title">Big Message</span>
 -        </div>
 -        <section class="oe_snippet_body jumbotron mt16 mb16">
 +    <div name="Big Message" class="o_block_jumbotron">
 +        <section class="jumbotron mt16 mb16">
              <div class="container">
                  <h1>Sell Online. Easily.</h1>
                  <p>
          </div>
      </div>
  
+     <div name="Image Floating" class="o_block_image_floating">
+         <div class="oe_snippet_thumbnail">
+             <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_text_image.png"/>
+             <span class="oe_snippet_thumbnail_title">Image Floating</span>
+         </div>
+         <div class="oe_snippet_body o_image_floating o_margin_l pull-right">
+             <div class="o_container">
+                 <img class="img img-rounded img-responsive" src="/website/static/src/img/library/ipad.png"/>
+                 <mark class="text-center"><a href="#"><strong>Click Here</strong></a></mark>
+             </div>
+             <div class="o_footer">
+                 <small class="text-muted">A great way to catch your reader's attention is to tell a story. Everything you consider writing can be told as a story.</small>
+             </div>
+         </div>
+     </div>
  
 -    <div>
 -        <div class="oe_snippet_thumbnail">
 -            <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_separator.png"/>
 -            <span class="oe_snippet_thumbnail_title">Separator</span>
 -        </div>
 -        <hr class="oe_snippet_body"/>
 +    <div name="Separator" class="o_block_separator">
 +        <hr/>
      </div>
  
  
              </ul>
          </li>
      </div>
 +     
 +    <div data-js='gallery' data-selector=".o_gallery">
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Mode</a>
 +            
 +            <ul class="dropdown-menu">
 +                <li data-mode="nomode"   > <a>None</a></li>
 +                <li data-mode="masonry"  > <a>Masonry</a> </li>
 +                <li data-mode="grid"     > <a>Grid</a> </li>
 +                <li data-mode="slideshow"> <a>Slideshow</a> </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Slideshow speed</a>
 +            <ul class="dropdown-menu">
 +                 <li data-interval="1000"> <a>1s</a> </li>
 +                 <li data-interval="2000"> <a>2s</a> </li>
 +                 <li data-interval="3000"> <a>3s</a> </li>
 +                 <li data-interval="5000"> <a>5s</a> </li>
 +                 <li data-interval="10000"> <a>10s</a></li>
 +                 <li data-interval="0"   > <a>Disable autoplay</a> </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Columns</a>
 +            
 +            <ul class="dropdown-menu">
 +                <li data-columns="1"  > <a>1</a> </li>
 +                <li data-columns="2"  > <a>2</a> </li>
 +                <li data-columns="3"  > <a>3</a> </li>
 +                <li data-columns="4"  > <a>4</a> </li>
 +                <li data-columns="6"  > <a>6</a> </li>
 +                <li data-columns="12" > <a>12</a> </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Images spacing</a>
  
 -    <div data-snippet-option-id='carousel'
 -        data-selector=".carousel">
 -        <li class="divider"></li>
 -        <li>
 -            <a href="#" class="button js_add">Add Slide</a>
 +            <ul class="dropdown-menu">
 +                <li data-select_class="o_spc-none"  > <a>None</a>   </li>
 +                <li data-select_class="o_spc-small" > <a>Small</a>  </li>
 +                <li data-select_class="o_spc-medium"> <a>Medium</a> </li>
 +                <li data-select_class="o_spc-big"   > <a>Big</a>    </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +           <a tabindex="-2" href="#">Album</a>
 +           
 +           <ul class="dropdown-menu">
 +               <li data-albumimages="images_add"> <a>Add images</a></li>
 +               <li data-albumimages="images_rm"><a>Remove all images</a></li>
 +           </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +           <a tabindex="-2" href="#">Styling</a>
 +           
 +           <ul class="dropdown-menu">
 +               <li data-styling="img-rounded"   ><a>Rounded corners</a></li>
 +               <li data-styling="img-thumbnail" ><a>Thumbnails</a></li>
 +               <li data-styling="img-circle"    ><a>Circle</a></li>
 +               <li data-styling="shadow"        ><a>Shadows</a></li>
 +               <li data-styling="fa-spin"       ><a>Spinning</a></li>
 +           </ul>
 +        </li>
 +    </div>
 +
 +    <div data-js='colorpicker'
 +        data-selector="section, :not(.o_gallery > .container) > .carousel, .parallax">
 +        <li class="dropdown-submenu">
 +            <a tabindex="-1" href="#">Color</a>
 +            <ul class="dropdown-menu">
 +                <li></li>
 +            </ul>
          </li>
 -        <li>
 -            <a href="#" class="button js_remove">Remove Slide</a>
 +    </div>
 +     
 +    <div data-js='gallery' data-selector=".gallery">
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Mode</a>
 +            
 +            <ul class="dropdown-menu">
 +                <li data-mode="nomode"   > <a>None</a></li>
 +                <li data-mode="masonry"  > <a>Masonry</a> </li>
 +                <li data-mode="grid"     > <a>Grid</a> </li>
 +                <li data-mode="slideshow"> <a>Slideshow</a> </li>
 +            </ul>
          </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Slideshow speed</a>
 +            <ul class="dropdown-menu">
 +                 <li data-interval="1000"> <a>1s</a> </li>
 +                 <li data-interval="2000"> <a>2s</a> </li>
 +                 <li data-interval="3000"> <a>3s</a> </li>
 +                 <li data-interval="5000"> <a>5s</a> </li>
 +                 <li data-interval="10000"> <a>10s</a></li>
 +                 <li data-interval="0"   > <a>Disable autoplay</a> </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Columns</a>
 +            
 +            <ul class="dropdown-menu">
 +                <li data-columns="1"  > <a>1</a> </li>
 +                <li data-columns="2"  > <a>2</a> </li>
 +                <li data-columns="3"  > <a>3</a> </li>
 +                <li data-columns="4"  > <a>4</a> </li>
 +                <li data-columns="6"  > <a>6</a> </li>
 +                <li data-columns="12" > <a>12</a> </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Images spacing</a>
 +
 +            <ul class="dropdown-menu">
 +                <li data-select_class="spc-none"  > <a>None</a>   </li>
 +                <li data-select_class="spc-small" > <a>Small</a>  </li>
 +                <li data-select_class="spc-medium"> <a>Medium</a> </li>
 +                <li data-select_class="spc-big"   > <a>Big</a>    </li>
 +            </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +           <a tabindex="-2" href="#">Album</a>
 +           
 +           <ul class="dropdown-menu">
 +               <li data-albumimages="images_add"> <a>Add images</a></li>
 +               <li data-albumimages="images_rm"><a>Remove all images</a></li>
 +           </ul>
 +        </li>
 +        <li class="dropdown-submenu">
 +           <a tabindex="-2" href="#">Styling</a>
 +           
 +           <ul class="dropdown-menu">
 +               <li data-styling="img-rounded"   ><a>Rounded corners</a></li>
 +               <li data-styling="img-thumbnail" ><a>Thumbnails</a></li>
 +               <li data-styling="img-circle"    ><a>Circle</a></li>
 +               <li data-styling="shadow"        ><a>Shadows</a></li>
 +               <li data-styling="fa-spin"       ><a>Spinning</a></li>
 +           </ul>
 +        </li>
 +    </div>
 +
 +    <div data-js='carousel'
 +        data-selector=":not(.o_gallery > .container) > .carousel">
 +        <li class="dropdown-submenu">
 +            <a tabindex="-2" href="#">Slideshow speed</a>
 +            <ul class="dropdown-menu">
 +                 <li data-interval="1000"> <a>1s</a> </li>
 +                 <li data-interval="2000"> <a>2s</a> </li>
 +                 <li data-interval="3000"> <a>3s</a> </li>
 +                 <li data-interval="5000"> <a>5s</a> </li>
 +                 <li data-interval="10000"> <a>10s</a></li>
 +                 <li data-interval="0"   > <a>Disable autoplay</a> </li>
 +            </ul>
 +        </li>
 +        <li class="divider"></li>
 +        <li data-add_slide="true"> <a href="#">Add Slide</a> </li>
 +        <li data-remove_slide="true"> <a href="#" >Remove Slide</a></li>
      </div>
  
 -    <div data-snippet-option-id='margin-y'
 -        data-selector="section, .row > [class*='col-md-'], .carousel, .parallax, hr">
 +    <div data-js='margin-y'
 +        data-selector="section, .row > [class*='col-md-'], :not(.o_gallery > .container) > .carousel, .parallax, hr">
      </div>
  
 -    <div data-snippet-option-id='resize'
 -        data-selector="section, .carousel, .parallax"
 -        data-selector-children=".oe_structure, [data-oe-type=html]">
 +    <div data-js='resize'
 +        data-selector="section, :not(.o_gallery > .container) > .carousel, .parallax"
 +        data-drop-in=".oe_structure, [data-oe-type=html]">
      </div>
  
 -    <div data-snippet-option-id='margin-x'
 +    <div data-js='margin-x'
          data-selector=".row > [class*='col-md-']"
 -        data-selector-vertical-children='.row'>
 +        data-drop-near=".row > [class*='col-md-']">
      </div>
  
 -    <div data-snippet-option-id='content'
 +    <div data-js='content'
-         data-selector="blockquote, .well, .panel, .oe_share"
+         data-selector="blockquote, .well, .panel, .oe_share, .o_image_floating"
 -        data-selector-siblings="p, h1, h2, h3, blockquote, .well, .panel, .oe_share"
 -        data-selector-children=".content">
 +        data-drop-near="p, h1, h2, h3, blockquote, .well, .panel, .oe_share"
 +        data-drop-in=".content">
      </div>
  
 -    <div data-snippet-option-id='separator'
 +    <div data-js='separator'
          data-selector="hr"
 -        data-selector-children=".oe_structure, [data-oe-type=html]">
 +        data-drop-in=".oe_structure, [data-oe-type=html]">
      </div>
  
+     <div data-snippet-option-id='image_floating_margin'
+         data-selector=".o_image_floating">
+         <li class="dropdown-submenu">
+             <a tabindex="-2" href="#">Margin</a>
+             <ul class="dropdown-menu">
+                 <li data-value="o_margin_xl"> <a>Extra-Large</a> </li>
+                 <li data-value="o_margin_l"> <a>Large</a> </li>
+                 <li data-value="o_margin_m"  > <a>Medium</a> </li>
+                 <li data-value="o_margin_s"  > <a>Small</a></li>
+                 <li data-value=""  > <a>None</a></li>
+             </ul>
+         </li>
+     </div>
+     <div data-snippet-option-id='image_floating_hidelink'
+         data-selector=".o_image_floating">
+         <li data-value="o_hide_link"><a>Hide link</a></li>
+     </div>
+     <div data-snippet-option-id='image_floating_side'
+          data-selector=".o_image_floating">
+         <li class="dropdown-submenu">
+             <a tabindex="-2" href="#">Float</a>
+             <ul class="dropdown-menu">
+                 <li data-value="pull-left"><a>Left</a></li>
+                 <li data-value="pull-right"><a>Right</a></li>
+             </ul>
+         </li>
+     </div>
 -    <div data-snippet-option-id='parallax'
 +    <div data-js='parallax'
          data-selector=".parallax">
          <li class="dropdown-submenu">
              <a tabindex="-1" href="#">Scroll Speed</a>
@@@ -12,39 -28,18 +12,45 @@@ import r
  from openerp.addons.website.models.website import slug
  
  
 -class event(osv.osv):
 +class event(models.Model):
      _name = 'event.event'
 -    _inherit = ['event.event','website.seo.metadata']
 +    _inherit = ['event.event', 'website.seo.metadata']
+     _track = {
+         'website_published': {
+             'website_event.mt_event_published': lambda self, cr, uid, obj, ctx=None: obj.website_published,
+             'website_event.mt_event_unpublished': lambda self, cr, uid, obj, ctx=None: not obj.website_published
+         },
+     }
  
 -    def _get_new_menu_pages(self, cr, uid, event, context=None):
 -        context = context or {}
 +    twitter_hashtag = fields.Char('Twitter Hashtag', default=lambda self: self._default_hashtag())
 +    website_published = fields.Boolean('Visible in Website', copy=False)
 +    # TDE TODO FIXME: when website_mail/mail_thread.py inheritance work -> this field won't be necessary
 +    website_message_ids = fields.One2many(
 +        'mail.message', 'res_id',
 +        domain=lambda self: [
 +            '&', ('model', '=', self._name), ('type', '=', 'comment')
 +        ],
 +        string='Website Messages',
 +        help="Website communication history",
 +    )
 +    website_url = fields.Char('Website url', compute='_website_url')
 +
 +    @api.one
 +    @api.depends('name')
 +    def _website_url(self):
 +        if isinstance(self.id, NewId):
 +            self.website_url = ''
 +        else:
 +            self.website_url = "/event/" + slug(self)
 +
 +    def _default_hashtag(self):
 +        return re.sub("[- \\.\\(\\)\\@\\#\\&]+", "", self.env.user.company_id.name).lower()
 +
 +    show_menu = fields.Boolean('Has Dedicated Menu', compute='_get_show_menu', inverse='_set_show_menu')
 +    menu_id = fields.Many2one('website.menu', 'Event Menu')
 +
 +    @api.one
 +    def _get_new_menu_pages(self):
          todo = [
              (_('Introduction'), 'website_event.template_intro'),
              (_('Location'), 'website_event.template_location')
              ]]></field>
          </record>
  
 +        <record id="website_quote_template_default" model="sale.quote.template">
 +            <field name="name">Default Template</field>
 +            <field name="number_of_days">30</field>
 +            <field name="website_description" type="xml">
 +                <section data-snippet-id="title">
 +                    <center><h1 class="page-header">Our offer</h1></center>
 +                </section>
 +                <section data-snippet-id="text-block">
 +                    <div class="row">
 +                        <div class="col-md-12">
 +                            <p>
 +                                <h3 class="text-muted">Our offer is based on 3 commitments, which drive our business and our partners:</h3>
 +                            </p>
 +                        </div>
 +                    </div>
 +                </section>
 +                <section data-snippet-id="quality">
 +                    <div class="row mt32">
 +                        <div class="col-md-4">
 +                            <div class="panel panel-info">
 +                                <div class="panel-heading">
 +                                   <center><h3 class="panel-title">Quality</h3></center>
 +                                </div>
 +                                <div class="panel-body">
 +                                   <p>
 +                                       Quality in many ways, our reputation was built on the first value.
 +                                   </p>
 +                                </div>
 +                            </div>
 +                        </div>
 +                        <div class="col-md-4">
 +                            <div class="panel panel-info">
 +                                <div class="panel-heading">
 +                                   <center><h3 class="panel-title">Service</h3></center>
 +                                </div>
 +                                <div class="panel-body">
 +                                   <p>
 +                                       We are always reachable to help you, do not hesitate to contact us at any time.
 +                                   </p>
 +                                </div>
 +                            </div>
 +                        </div>
 +                        <div class="col-md-4">
 +                            <div class="panel panel-info">
 +                                <div class="panel-heading">
 +                                   <center><h3 class="panel-title">Price</h3></center>
 +                                </div>
 +                                <div class="panel-body">
 +                                   <p>
 +                                     Our prices are the lowest in the region, if you find cheaper elsewhere, we will refund the difference 
 +                                   </p>
 +                                </div>
 +                            </div>
 +                        </div>
 +                    </div>
 +                </section>
 +                <section data-snippet-id="text-block">
 +                    <center><h2>Your products/services</h2></center>
 +                    <p>
 +                        <h3 class="text-muted">
 +                            The description of products/services from your quotation will be displayed below
 +                        </h3>
 +                    </p>
 +                    <p>
 +                           <b> To write a quotation description, edit your product, go the sales tab and add a text in "Description for quotations"</b>
 +                    </p>
 +                </section>
 +            </field>
 +        </record>
      </data>
+     <!-- Mail template is done in a NOUPDATE block
+          so users can freely customize/delete them -->
+     <data noupdate="1">
+         <!--Email template -->
+         <record id="email_template_edi_sale" model="email.template">
+             <field name="name">Sales Order - Send by Email (Online Quote)</field>
+             <field name="email_from">${(object.user_id.email or '')|safe}</field>
+             <field name="subject">${object.company_id.name|safe} ${object.state in ('draft', 'sent') and 'Quotation' or 'Order'} (Ref ${object.name or 'n/a' })</field>
+             <field name="partner_to">${object.partner_invoice_id.id}</field>
+             <field name="model_id" ref="sale.model_sale_order"/>
+             <field name="auto_delete" eval="True"/>
+             <field name="report_template" ref="sale.report_sale_order"/>
+             <field name="report_name">${(object.name or '').replace('/','_')}_${object.state == 'draft' and 'draft' or ''}</field>
+             <field name="lang">${object.partner_id.lang}</field>
+             <field name="user_signature" eval="True"/>
+             <field name="body_html"><![CDATA[
+ <div style="font-family: 'Lucica Grande', Ubuntu, Arial, Verdana, sans-serif; font-size: 12px; color: rgb(34, 34, 34); background-color: rgb(255, 255, 255); ">
+     <p>Hello ${object.partner_id.name},</p>
+     <p>Here is your ${object.state in ('draft', 'sent') and 'quotation' or 'order confirmation'} from ${object.company_id.name}: </p>
+     <p style="border-left: 1px solid #8e0000; margin-left: 30px;">
+        &nbsp;&nbsp;<strong>REFERENCES</strong><br />
+        &nbsp;&nbsp;Order number: <strong>${object.name}</strong><br />
+        &nbsp;&nbsp;Order total: <strong>${object.amount_total} ${object.pricelist_id.currency_id.name}</strong><br />
+        &nbsp;&nbsp;Order date: ${object.date_order}<br />
+        % if object.origin:
+        &nbsp;&nbsp;Order reference: ${object.origin}<br />
+        % endif
+        % if object.client_order_ref:
+        &nbsp;&nbsp;Your reference: ${object.client_order_ref}<br />
+        % endif
+        % if object.user_id:
+        &nbsp;&nbsp;Your contact: <a href="mailto:${object.user_id.email or ''}?subject=Order%20${object.name}">${object.user_id.name}</a>
+        % endif
+     </p>
+     <% set signup_url = object.get_signup_url() %>
+     % if signup_url:
+     <p>
+     You can access this document and pay online via our Customer Portal:
+     </p>
+         <a style="display:block; width: 150px; height:20px; margin-left: 120px; color: #DDD; font-family: 'Lucida Grande', Helvetica, Arial, sans-serif; font-size: 13px; font-weight: bold; text-align: center; text-decoration: none !important; line-height: 1; padding: 5px 0px 0px 0px; background-color: #8E0000; border-radius: 5px 5px; background-repeat: repeat no-repeat;"
+            href="${signup_url}">View ${object.state in ('draft', 'sent') and 'Quotation' or 'Order'}</a>
+     % endif
+     % if object.paypal_url:
+     <br/>
+     <p>It is also possible to directly pay with Paypal:</p>
+         <a style="margin-left: 120px;" href="${object.paypal_url}">
+             <img class="oe_edi_paypal_button" src="https://www.paypal.com/en_US/i/btn/btn_paynowCC_LG.gif"/>
+         </a>
+     % endif
+     <br/>
+     <p>If you have any question, do not hesitate to contact us.</p>
+     <p>Thank you for choosing ${object.company_id.name or 'us'}!</p>
+     <br/>
+     <br/>
+     <div style="width: 375px; margin: 0px; padding: 0px; background-color: #8E0000; border-top-left-radius: 5px 5px; border-top-right-radius: 5px 5px; background-repeat: repeat no-repeat;">
+         <h3 style="margin: 0px; padding: 2px 14px; font-size: 12px; color: #DDD;">
+             <strong style="text-transform:uppercase;">${object.company_id.name}</strong></h3>
+     </div>
+     <div style="width: 347px; margin: 0px; padding: 5px 14px; line-height: 16px; background-color: #F2F2F2;">
+         <span style="color: #222; margin-bottom: 5px; display: block; ">
+         % if object.company_id.street:
+             ${object.company_id.street}<br/>
+         % endif
+         % if object.company_id.street2:
+             ${object.company_id.street2}<br/>
+         % endif
+         % if object.company_id.city or object.company_id.zip:
+             ${object.company_id.zip} ${object.company_id.city}<br/>
+         % endif
+         % if object.company_id.country_id:
+             ${object.company_id.state_id and ('%s, ' % object.company_id.state_id.name) or ''} ${object.company_id.country_id.name or ''}<br/>
+         % endif
+         </span>
+         % if object.company_id.phone:
+             <div style="margin-top: 0px; margin-right: 0px; margin-bottom: 0px; margin-left: 0px; padding-top: 0px; padding-right: 0px; padding-bottom: 0px; padding-left: 0px; ">
+                 Phone:&nbsp; ${object.company_id.phone}
+             </div>
+         % endif
+         % if object.company_id.website:
+             <div>
+                 Web :&nbsp;<a href="${object.company_id.website}">${object.company_id.website}</a>
+             </div>
+         % endif
+         <p></p>
+     </div>
+ </div>
+             ]]></field>
+         </record>
+     </data>
  </openerp>
Simple merge
diff --cc doc/conf.py
Simple merge
Simple merge
@@@ -1440,15 -1461,14 +1485,15 @@@ class PreprocessedCSS(StylesheetAsset)
          if self.url:
              ira = self.registry['ir.attachment']
              url = self.html_url % self.url
 -            domain = [('type', '=', 'binary'), ('url', '=', self.url)]
 +            domain = [('type', '=', 'binary'), ('url', '=', url)]
-             ira_id = ira.search(self.cr, self.uid, domain, context=self.context)
+             ira_id = ira.search(self.cr, openerp.SUPERUSER_ID, domain, context=self.context)
 +            datas = self.content.encode('utf8').encode('base64')
              if ira_id:
                  # TODO: update only if needed
 -                ira.write(self.cr, openerp.SUPERUSER_ID, [ira_id], {'datas': self.content}, context=self.context)
 +                ira.write(self.cr, openerp.SUPERUSER_ID, ira_id, {'datas': datas}, context=self.context)
              else:
                  ira.create(self.cr, openerp.SUPERUSER_ID, dict(
 -                    datas=self.content.encode('utf8').encode('base64'),
 +                    datas=datas,
                      mimetype='text/css',
                      type='binary',
                      name=url,
Simple merge
Simple merge
Simple merge
Simple merge
Simple merge