[MERGE] forward port of branch saas-3 up to revid 9298 chm@openerp.com-20140311130852...
authorChristophe Simonis <chs@openerp.com>
Tue, 11 Mar 2014 14:52:05 +0000 (15:52 +0100)
committerChristophe Simonis <chs@openerp.com>
Tue, 11 Mar 2014 14:52:05 +0000 (15:52 +0100)
bzr revid: chs@openerp.com-20140311145205-s56fj113fsrnisc3

25 files changed:
1  2 
addons/account/account_invoice_view.xml
addons/auth_oauth/controllers/main.py
addons/auth_signup/views/auth_signup_login.xml
addons/crm/crm_lead.py
addons/crm/crm_phonecall_menu.xml
addons/email_template/email_template.py
addons/mail/mail_thread.py
addons/mrp/mrp.py
addons/mrp_repair/__openerp__.py
addons/point_of_sale/point_of_sale.py
addons/point_of_sale/static/src/js/models.js
addons/sale/sale_view.xml
addons/sale_crm/sale_crm_view.xml
addons/website/controllers/main.py
addons/website/models/website.py
addons/website/static/src/css/website.css
addons/website/static/src/css/website.sass
addons/website/static/src/js/website.tour.banner.js
addons/website/views/snippets.xml
addons/website/views/website_templates.xml
addons/website_event/views/website_event.xml
addons/website_event_track/views/website_event.xml
addons/website_mail/models/email_template.py
addons/website_sale/controllers/main.py
addons/website_sale/views/website_sale.xml

                              <group>
                                  <group>
                                      <field domain="[('partner_id', '=', partner_id)]" name="partner_bank_id" on_change="onchange_partner_bank(partner_bank_id)"/>
 -                                    <field name="user_id" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'account.group_account_invoice']}"/>
 +                                    <field name="user_id" string="Responsible" context="{'default_groups_ref': ['base.group_user', 'base.group_partner_manager', 'account.group_account_invoice']}"/>
                                      <field name="name" invisible="1"/>
-                                     <field name="payment_term" widget="selection"/>
+                                     <field name="payment_term" options="{'no_create': True}"/>
                                  </group>
                                  <group>
                                      <field name="move_id" groups="account.group_account_user"/>
@@@ -93,24 -93,7 +98,25 @@@ class OAuthLogin(openerp.addons.web.con
  
          return response
  
 +    @http.route()
 +    def web_auth_signup(self, *args, **kw):
 +        providers = self.list_providers()
 +        if len(providers) == 1:
 +            werkzeug.exceptions.abort(werkzeug.utils.redirect(providers[0]['auth_link'], 303))
 +        response = super(OAuthLogin, self).web_auth_signup(*args, **kw)
 +        response.qcontext.update(providers=providers)
 +        return response
 +
 +    @http.route()
 +    def web_auth_reset_password(self, *args, **kw):
 +        providers = self.list_providers()
 +        if len(providers) == 1:
 +            werkzeug.exceptions.abort(werkzeug.utils.redirect(providers[0]['auth_link'], 303))
 +        response = super(OAuthLogin, self).web_auth_reset_password(*args, **kw)
 +        response.qcontext.update(providers=providers)
 +        return response
 +
  class OAuthController(http.Controller):
  
      @http.route('/auth_oauth/signin', type='http', auth='none')
              </xpath>
          </template>
  
 -        <template id="auth_signup.signup" name="Sign up">
 -            <t t-call="web.login_layout">
 -                <t t-set="head">
 -                    <t t-foreach="css" t-as="css_file">
 -                        <link rel="stylesheet" t-att-href="css_file"/>
 -                    </t>
 -                    <t t-foreach="js" t-as="js_file">
 -                        <script type="text/javascript" t-att-src="js_file"></script>
 -                    </t>
 -                </t>
 -                <script type="text/javascript">
 -                    $(function() {
 -                        var s = new openerp.init(<t t-raw="modules"/>);
 -                        var login_form = new openerp.web.LoginForm($('.oe_signup_form'));
 -                    });
 -                </script>
 -
 -                <t t-set="reset_without_token" t-value="mode == 'reset' and not token"/>
 -
 -                <form class="oe_signup_form" role="form" method="post">
 -                    <t t-call="web.database_select"/>
 -
 -                    <div class="form-group field-login">
 -                        <label for="login" class="control-label">Your Email</label>
 -                        <input type="email" name="login" t-att-value="login" id="login" class="form-control" autofocus="autofocus"
 -                            required="required" t-att-disabled="'disabled' if mode == 'reset' and token else None"/>
 -                        <input type="hidden" name="login" t-att-value="login" t-if="mode == 'reset' and token"/>
 -                    </div>
 +        <template id="auth_signup.fields" name="Auth Signup/ResetPassword form fields">
 +            <t t-call="web.database_select"/>
  
 -                    <div class="form-group field-name" t-if="not reset_without_token">
 -                        <label for="name" class="control-label">Your Name</label>
 -                        <input type="text" name="name" t-att-value="name" id="name" class="form-control" placeholder="e.g. John Doe"
 -                            required="required" t-att-disabled="'disabled' if mode == 'reset' and token else None"
 -                            t-att-autofocus="'autofocus' if mode != 'reset' and login else None"/>
 -                    </div>
++            <div class="form-group field-login">
++                <label for="login" class="control-label">Your Email</label>
++                <input type="text" name="login" t-att-value="login" id="login" class="form-control" autofocus="autofocus"
++                    required="required" t-att-readonly="'readonly' if only_passwords else None"/>
++            </div>
 -                    <div class="form-group field-password" t-if="not reset_without_token">
 -                        <label for="password" class="control-label">Password</label>
 -                        <input type="password" name="password" id="password" class="form-control"
 -                            required="required" t-att-autofocus="'autofocus' if mode == 'reset' and token else None"/>
 -                    </div>
 +            <div class="form-group field-name">
 +                <label for="name" class="control-label">Your Name</label>
 +                <input type="text" name="name" t-att-value="name" id="name" class="form-control" placeholder="e.g. John Doe"
-                     required="required" t-att-autofocus="'autofocus' if not only_passwords else None" t-att-readonly="'readonly' if only_passwords else None"/>
-             </div>
-             <div class="form-group field-login">
-                 <label for="login" class="control-label">Your Email</label>
-                 <input type="text" name="login" t-att-value="login" id="login" class="form-control"
 +                    required="required" t-att-readonly="'readonly' if only_passwords else None"/>
 +            </div>
  
 -                    <div class="form-group field-confirm_password" t-if="not reset_without_token">
 -                        <label for="confirm_password" class="control-label">Confirm Password</label>
 -                        <input type="password" name="confirm_password" id="confirm_password" class="form-control" required="required"/>
 -                    </div>
 +            <div class="form-group field-password">
 +                <label for="password" class="control-label">Password</label>
 +                <input type="password" name="password" autofocus="autofocus" id="password" class="form-control"
 +                    required="required" t-att-autofocus="'autofocus' if only_passwords else None"/>
 +            </div>
 +
 +            <div class="form-group field-confirm_password">
 +                <label for="confirm_password" class="control-label">Confirm Password</label>
 +                <input type="password" name="confirm_password" id="confirm_password" class="form-control" required="required"/>
 +            </div>
 +        </template>
 +
 +        <template id="auth_signup.signup" name="Sign up login">
 +            <t t-call="web.login_layout">
 +                <form class="oe_signup_form" role="form" t-attf-action="/web/signup{{ '?debug' if debug else '' }}" method="post" t-if="not message">
 +
 +                    <t t-call="auth_signup.fields"/>
  
                      <p class="alert alert-danger" t-if="error">
                          <t t-esc="error"/>
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -59,6 -57,8 +59,7 @@@ The following topics should be covered 
               'test/test_mrp_repair_b4inv.yml',
               'test/test_mrp_repair_afterinv.yml',
               'test/test_mrp_repair_cancel.yml',
 -             'test/mrp_repair_report.yml',
+              'test/test_mrp_repair_fee.yml',
      ],
      'installable': True,
      'auto_install': False,
Simple merge
Simple merge
Simple merge
Simple merge
@@@ -585,15 -567,33 +586,42 @@@ class ir_attachment(osv.osv)
          'website_url': fields.function(_website_url_get, string="Attachment URL", type='char')
      }
  
 +    def create(self, cr, uid, values, context=None):
 +        chk = self._compute_checksum(values)
 +        if chk:
 +            match = self.search(cr, uid, [('datas_checksum', '=', chk)], context=context)
 +            if match:
 +                return match[0]
 +        return super(ir_attachment, self).create(
 +            cr, uid, values, context=context)
 +
+     def try_remove(self, cr, uid, ids, context=None):
+         """ Removes a web-based image attachment if it is used by no view
+         (template)
+         Returns a dict mapping attachments which would not be removed (if any)
+         mapped to the views preventing their removal
+         """
+         Views = self.pool['ir.ui.view']
+         attachments_to_remove = []
+         # views blocking removal of the attachment
+         removal_blocked_by = {}
+         for attachment in self.browse(cr, uid, ids, context=context):
+             # in-document URLs are html-escaped, a straight search will not
+             # find them
+             url = werkzeug.utils.escape(attachment.website_url)
+             ids = Views.search(cr, uid, [('arch', 'like', url)], context=context)
+             if ids:
+                 removal_blocked_by[attachment.id] = Views.read(
+                     cr, uid, ids, ['name'], context=context)
+             else:
+                 attachments_to_remove.append(attachment.id)
+         if attachments_to_remove:
+             self.unlink(cr, uid, attachments_to_remove, context=context)
+         return removal_blocked_by
  class res_partner(osv.osv):
      _inherit = "res.partner"
  
                  },
                  {
                      waitFor:   '.oe_overlay_options .oe_options:visible',
-                     element:   '#wrap [data-snippet-id=carousel]:first .carousel-caption',
+                     element:   '#wrap [data-snippet-id=carousel]:first .carousel-caption > div',
                      placement: 'top',
-                     title:     _("Customize banner's text"),
-                     content:   _("Click in the text and start editing it."),
+                     title:     _t("Customize banner's text"),
 -                    content:   _t("Click in the text and start editing it. Click continue once it's done."),
++                    content:   _t("Click in the text and start editing it."),
                      popover:   { next: _t("Continue") },
                  },
                  {
      <div data-snippet-id="parallax_quote" data-selector-children=".oe_structure, [data-oe-type=html]">
          <div class="oe_snippet_thumbnail">
              <img class="oe_snippet_thumbnail_img" src="/website/static/src/img/blocks/block_quotes_slider.png"/>
 -            <span class="oe_snippet_thumbnail_title">Parallax Slider</span>        
 +            <span class="oe_snippet_thumbnail_title">Parallax Slider</span>
          </div>
          <section class="oe_snippet_body parallax" data-snippet-id="parallax"
-                  style="height: 320px; background-image: url('/website/static/src/img/parallax/quote.png')"
+                  style="background-image: url('/website/static/src/img/parallax/quote.png')"
                  data-scroll-background-ratio="0.3">
-             <div>
-                 <div class="oe_structure">
+             <div><div><div class="oe_structure">
                      <div id="myQuoteCarousel" class="carousel quotecarousel slide mb0" data-snippet-id="slider">
                          <!-- Indicators -->
                          <ol class="carousel-indicators mb0">
@@@ -80,8 -80,8 +80,8 @@@
  
              <script type="text/javascript" src="/website/static/src/js/website.js"></script>
              
-             <script type="text/javascript" src="/web/static/lib/bootstrap/js/bootstrap.js"></script>
              <script t-if="not translatable" type="text/javascript" src="/website/static/src/js/website.snippets.animation.js"></script>
 -            <script type="text/javascript" src="/website/static/lib/bootstrap/js/bootstrap.js"></script>
++            <script type="text/javascript" src="/web/static/lib/bootstrap/js/bootstrap.js"></script>
  
              <t t-raw="head or ''" name='layout_head'/>
          </head>
@@@ -59,9 -66,9 +59,9 @@@
                                      </t>
                                  </div>
                                  <div>
-                                     <i class="fa fa-clock-o"></i> <span itemprop="startDate" t-field="event.date_begin"> </span> <i>to</i> <span itemprop="endDate" t-field="event.date_end"> </span>
 -                                    <i class="fa fa-clock-o"></i> <span t-field="event.date_begin" t-field-options='{"hide_seconds":"True"}'> </span> <i>to</i> <span t-field="event.date_end" t-field-options='{"hide_seconds":"True"}'> </span>
++                                    <i class="fa fa-clock-o"></i> <span itemprop="startDate" t-field="event.date_begin" t-field-options='{"hide_seconds":"True"}'> </span> <i>to</i> <span itemprop="endDate" t-field="event.date_end" t-field-options='{"hide_seconds":"True"}'> </span>
                                  </div>
 -                                <div t-field="event.address_id" t-field-options='{
 +                                <div itemprop="location" t-field="event.address_id" t-field-options='{
                                      "widget": "contact",
                                      "fields": ["city"]
                                      }'/>
  
  <template id="event_details">
      <t t-call="website_event.layout">
 -        <div class="container">
 -            <h1 class="text-center" t-field="event.name"></h1>
 +        <div itemscope="itemscope" itemtype="http://schema.org/Event" class="container">
 +            <h1 itemprop="name" class="text-center" t-field="event.name"></h1>
              <h4 class="text-center text-muted">
-                 <i class="fa fa-clock-o"></i> <span itemprop="startDate" t-field="event.date_begin"/> to
-                 <span itemprop="endDate" t-field="event.date_end"/>
 -                <i class="fa fa-clock-o"></i> <span t-field="event.date_begin" t-field-options='{"hide_seconds":"True"}'/> to
 -                <span t-field="event.date_end" t-field-options='{"hide_seconds":"True"}'/>
++                <i class="fa fa-clock-o"></i> <span itemprop="startDate" t-field="event.date_begin" t-field-options='{"hide_seconds":"True"}'/> to
++                <span itemprop="endDate" t-field="event.date_end" t-field-options='{"hide_seconds":"True"}'/>
              </h4>
              <h4 class="text-center text-muted"
                  t-field="event.address_id" t-field-options='{
@@@ -717,10 -732,12 +732,12 @@@ class Ecommerce(http.Controller)
              order = self.get_order()
          else:
              order = request.registry['sale.order'].browse(cr, SUPERUSER_ID, sale_order_id, context=context)
 -            assert order.website_session_id == request.httprequest.session['website_session_id']
 +            assert order.website_session_id == request.session['website_session_id']
  
-         if not tx or not order:
+         if not order:
              return request.redirect('/shop/')
+         elif order.amount_total and not tx:
+             return request.redirect('/shop/mycart')
  
          if not order.amount_total or tx.state == 'done':
              # confirm the quotation
    </form>
  </template>
  
- <template id="products_cart" name="Shopping cart">
+ <template id="products_cart" name="Product Cell">
 +  <div itemscope="itemscope" itemtype="http://schema.org/Product">
    <div class="ribbon-wrapper">
      <div class="ribbon btn btn-danger">Sale</div>
    </div>
    <div class="oe_product_image">
 -      <a t-attf-href="/shop/product/{{ slug(product) }}/?{{ keep_query('search', 'filters', category=(category and int(category)), page=(pager['page']['num'] if pager['page']['num']>1 else None)) }}">
 -          <img class="img img-responsive" t-attf-src="/website/image/product.template/#{product.id}/image#{'' if product_image_big else '?max_width=300&amp;max_height=300'}"/>
 +      <a itemprop="url" t-attf-href="/shop/product/{{ slug(product) }}/?{{ keep_query('search', 'filters', category=(category and int(category)), page=(pager['page']['num'] if pager['page']['num']>1 else None)) }}">
-           <span itemprop="image" t-field="product.image" t-field-options='{"widget": "image"}'/>
++          <img itemprop="image" class="img img-responsive" t-attf-src="/website/image/product.template/#{product.id}/image#{'' if product_image_big else '?max_width=300&amp;max_height=300'}"/>
        </a>
    </div>
    <section>
 -      <h5><strong><a t-attf-href="/shop/product/{{ slug(product) }}/?{{ keep_query('search', 'filters', category=(category and int(category)), page=(pager['page']['num'] if pager['page']['num']>1 else None)) }}" t-field="product.name"/></strong></h5>
 -      <div class="product_price" t-if="product.product_variant_ids">
 +      <h5><strong><a itemprop="name" t-attf-href="/shop/product/{{ slug(product) }}/?{{ keep_query('search', 'filters', category=(category and int(category)), page=(pager['page']['num'] if pager['page']['num']>1 else None)) }}" t-field="product.name"/></strong></h5>
 +      <div itemprop="offers" itemscope="itemscope" itemtype="http://schema.org/Offer" class="product_price" t-if="product.product_variant_ids">
            <b>
-               <t t-if="abs(product.product_variant_ids[0].lst_price - product.product_variant_ids[0].price) &gt; 0.2">
+               <t t-if="product.product_variant_ids[0].lst_price != product.product_variant_ids[0].price">
                  <del class="text-danger"
                    t-field="product.product_variant_ids[0].lst_price" t-field-options='{
                         "widget": "monetary",
  
  <template id="product_description" inherit_option_id="website_sale.products_cart" name="Product Description">
    <xpath expr="//div[@class='product_price']" position="before">
-       <div class="text-info oe_subdescription oe_shadow" t-field="product.description_sale"/>
-       <div itemprop="description" class="text-info oe_subdescription" t-field="product.description_sale"/>
+       <div class="text-info oe_subdescription" contenteditable="false">
 -        <div t-field="product.description_sale"></div>
++        <div itemprop="description" t-field="product.description_sale"></div>
+       </div>
    </xpath>
  </template>
  
                                   "widget": "monetary",
                                   "display_currency": "website.pricelist_id.currency_id"
                               }'/>
 +                            <span itemprop="price" style="display:none;" t-esc="product.product_variant_ids[0].price"/>
 +                            <span itemprop="priceCurrency" style="display:none;" t-esc="website.pricelist_id.currency_id.name"/>
                          </h4>
                      </div>
-                     <button class="btn btn-primary btn-lg mt8">Add to Cart</button>
+                     <a class="btn btn-primary btn-lg mt8 a-submit">Add to Cart</a>
                      <hr t-if="product.description_sale"/>
                      <div><p t-field="product.description_sale" class="text-muted"/></div>
                      <hr/>