[MERGE] forward port branch saas-14 up to 73822d4eaf

This commit is contained in:
Christophe Simonis
2017-10-18 16:06:07 +02:00
15 changed files with 115 additions and 18 deletions
+8
View File
@@ -273,6 +273,14 @@ class Lead(models.Model):
# ORM override (CRUD, fields_view_get, ...)
# ----------------------------------------
@api.model
def name_create(self, name):
res = super(Lead, self).name_create(name)
# update the probability of the lead if the stage is set to update it automatically
self.browse(res[0])._onchange_stage_id()
return res
@api.model
def create(self, vals):
# set up context used to find the lead's sales channel which is needed
+4 -3
View File
@@ -340,7 +340,8 @@
('activity_ids.date_deadline', '<=', (context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d'))
]"/>
<filter string="Overdue Activities" name="activities_overdue"
domain="[('activity_ids.date_deadline', '&lt;', context_today().strftime('%Y-%m-%d'))]"
domain="[('activity_ids.date_deadline', '&lt;', context_today().strftime('%Y-%m-%d')),
('date_closed', '=', False)]"
help="Show all records which has next action date is before today"/>
<group expand="0" string="Group By">
<filter string="Salesperson" name="groupby_salesperson" domain="[]" context="{'group_by':'user_id'}"/>
@@ -583,10 +584,10 @@
('activity_ids.date_deadline', '&lt;=', (context_today()+datetime.timedelta(days=7)).strftime('%Y-%m-%d'))
]"/>
<filter string="Overdue Activities" name="activities_overdue"
domain="[('activity_ids.date_deadline', '&lt;', context_today().strftime('%Y-%m-%d'))]"
domain="[('activity_ids.date_deadline', '&lt;', context_today().strftime('%Y-%m-%d')), ('date_closed', '=', False)]"
help="Show all opportunities for which the next action date is before today"/>
<filter string="Overdue Opportunities" name="overdue_opp"
domain="[('date_deadline', '&lt;', context_today().strftime('%Y-%m-%d'))]"
domain="[('date_deadline', '&lt;', context_today().strftime('%Y-%m-%d')), ('date_closed', '=', False)]"
help="Show all opportunities with a deadline for which the next action date is before today"/>
<separator/>
<filter string="Unread Messages" name="message_needaction" domain="[('message_needaction','=',True)]"/>
+2 -3
View File
@@ -87,9 +87,8 @@ class MailController(http.Controller):
record_sudo.sudo(uid).check_access_rule('read')
except AccessError:
return cls._redirect_to_messaging()
if record_action['type'] == 'ir.actions.act_url':
return werkzeug.utils.redirect(record_action['url'])
if record_action['type'] == 'ir.actions.act_url':
return werkzeug.utils.redirect(record_action['url'])
url_params = {
'view_type': record_action['view_type'],
+1 -2
View File
@@ -1475,7 +1475,7 @@ exports.Orderline = Backbone.Model.extend({
var recompute_base = function(base_amount, fixed_amount, percent_amount){
if(fixed_amount === 0.0 && percent_amount === 0.0)
return base_amount;
return round_pr((base_amount - fixed_amount) / (1.0 + percent_amount / 100.0), currency_rounding);
return (base_amount - fixed_amount) / (1.0 + percent_amount / 100.0);
}
// 4) Iterate the taxes in the reversed sequence order to retrieve the initial base of the computation.
@@ -1529,7 +1529,6 @@ exports.Orderline = Backbone.Model.extend({
taxes_vals.push(tax_vals);
});
return {
taxes: taxes_vals,
total_excluded: round_pr(total_excluded, currency_rounding_bak),
+1 -1
View File
@@ -868,7 +868,7 @@ class SaleOrderLine(models.Model):
return price
else:
from_currency = self.order_id.company_id.currency_id
return from_currency.compute(product[pricelist_item.base], self.order_id.pricelist_id.currency_id)
return from_currency.compute(pricelist_item and product[pricelist_item.base] or product.lst_price, self.order_id.pricelist_id.currency_id)
@api.multi
@api.onchange('product_id')
+1 -1
View File
@@ -968,7 +968,7 @@ class StockMove(models.Model):
self._propagate_split(new_move, qty)
# returning the first element of list returned by action_confirm is ok because we checked it wouldn't be exploded (and
# thus the result of action_confirm should always be a list of 1 element length)
new_move.action_confirm()
new_move = new_move.action_confirm()
# TDE FIXME: due to action confirm change
return new_move.id
+22
View File
@@ -578,6 +578,28 @@ var RTE = Widget.extend({
_.defer(function () {
self.historyRecordUndo($target, 'activate', true);
});
// To Fix Google Chrome Tripleclick Issue, which selects the ending
// whitespace characters (so Tripleclicking then typing text will remove
// the whole paragraph instead of its content).
// http://stackoverflow.com/questions/38467334/why-does-google-chrome-always-add-space-after-selected-text
if ($.browser.chrome === true && event.originalEvent.detail === 3) {
var currentSelection = range.create();
if (currentSelection.sc.parentNode === currentSelection.ec) {
_selectSC(currentSelection);
} else if (currentSelection.eo === 0) {
var $hasNext = $(currentSelection.sc).parent();
while (!$hasNext.next().length && !$hasNext.is('body')) {
$hasNext = $hasNext.parent();
}
if ($hasNext.next()[0] === currentSelection.ec) {
_selectSC(currentSelection);
}
}
}
function _selectSC(selection) {
range.create(selection.sc, selection.so, selection.sc, selection.sc.length).select();
}
},
editable: function () {
@@ -23,7 +23,9 @@ html, body {
/* ----- GENERIC LAYOUTING HELPERS ---- */
/* table */
#wrapwrap, .o_editable {
table.table {
// Only style editor-made tables (shop/portal/... tables are not supposed to
// use table-bordered...)
table.table.table-bordered {
table-layout: fixed;
td {
min-width: 20px;
+1
View File
@@ -4,3 +4,4 @@
import sale_order
import sale_quote
import product_template
import ir_model_fields
@@ -0,0 +1,35 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models
# !! Attention, this is a hack of a hack, do not try this at home !!
# This is done because website_quote defines the website_description
# field which is also defined by website_sale, but these two modules
# are independent of each other, the part of the ORM that generates
# xmlids does not support this case therefore it only creates a single
# pair of xmlids for whichever module is installed first, therefore
# when uninstalling any of the two modules the website_descripion field
# will be deleted from the db and the other module won't be able to
# use this field, resulting in a crash and data-loss.
# See opw-776464 for more details.
#
# This is hotfixed by overriding the unlink method so as to not delete
# the website_description field if website_quote is uninstalled, it's
# an ugly hack but it works and big changes can't be done to the ORM
# in stable versions, Odoo v12+ will properly fix this
class IrModelFields(models.Model):
_inherit = "ir.model.fields"
@api.multi
def unlink(self):
# Prevent the deletion of the field "website_description"
self = self.filtered(
lambda rec: not (
rec.model in ('product.product', 'product.template') and
rec.name == 'website_description'
)
)
return super(IrModelFields, self).unlink()
+6
View File
@@ -3,6 +3,7 @@
from odoo import api, fields, models, tools, _
import odoo.addons.decimal_precision as dp
from odoo.tools.translate import html_translate
from odoo.tools import float_is_zero
class ProductStyle(models.Model):
@@ -139,6 +140,7 @@ class ProductTemplate(models.Model):
website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price'))
website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price'))
website_price_difference = fields.Boolean('Website price difference', compute='_website_price')
def _website_price(self):
# First filter out the ones that have no variant:
@@ -148,6 +150,7 @@ class ProductTemplate(models.Model):
for template, product in zip(self, self.mapped('product_variant_id')):
template.website_price = product.website_price
template.website_public_price = product.website_public_price
template.website_price_difference = product.website_price_difference
def _default_website_sequence(self):
self._cr.execute("SELECT MIN(website_sequence) FROM %s" % self._table)
@@ -188,6 +191,7 @@ class Product(models.Model):
website_price = fields.Float('Website price', compute='_website_price', digits=dp.get_precision('Product Price'))
website_public_price = fields.Float('Website public price', compute='_website_price', digits=dp.get_precision('Product Price'))
website_price_difference = fields.Boolean('Website price difference', compute='_website_price')
def _website_price(self):
qty = self._context.get('quantity', 1.0)
@@ -204,6 +208,8 @@ class Product(models.Model):
for p, p2 in zip(self, self2):
taxes = partner.property_account_position_id.map_tax(p.taxes_id.sudo().filtered(lambda x: x.company_id == company_id))
p.website_price = taxes.compute_all(p2.price, pricelist.currency_id, quantity=qty, product=p2, partner=partner)[ret]
price_without_pricelist = taxes.compute_all(p.list_price, pricelist.currency_id)[ret]
p.website_price_difference = False if float_is_zero(price_without_pricelist - p.website_price, precision_rounding=pricelist.currency_id.rounding) else True
p.website_public_price = taxes.compute_all(p2.lst_price, quantity=qty, product=p2, partner=partner)[ret]
@api.multi
@@ -6,10 +6,10 @@ var ajax = require('web.ajax');
$(document).ready(function () {
// If option is enable
if ($("#checkbox_cgv").length) {
var enabling_button = function() {
$("#checkbox_cgv").change(function() {
$("div.oe_sale_acquirer_button").find('input, button').prop("disabled", !this.checked);
};
$("#checkbox_cgv").click(enabling_button).each(enabling_button);
});
$('#checkbox_cgv').trigger('change');
}
// When choosing an acquirer, display its Pay Now button
+3 -3
View File
@@ -104,7 +104,7 @@
</h5>
<div itemprop="offers" itemscope="itemscope" itemtype="http://schema.org/Offer" class="product_price" t-if="product.product_variant_ids">
<b>
<t t-if="(compute_currency(product.lst_price) - product.website_price ) &gt; 0.01 and website.get_current_pricelist().discount_policy=='without_discount'">
<t t-if="product.website_price_difference and website.get_current_pricelist().discount_policy=='without_discount'">
<del class="text-danger mr8" style="white-space: nowrap;" t-esc="compute_currency(product.website_public_price)" t-options="{'widget': 'monetary', 'display_currency': website.get_current_pricelist().currency_id, 'from_currency': website.currency_id}" />
</t>
@@ -595,7 +595,7 @@
<div itemprop="offers" itemscope="itemscope" itemtype="http://schema.org/Offer" class="product_price mt16">
<h4 class="oe_price_h4 css_editable_mode_hidden">
<span class="text-danger oe_default_price" style="text-decoration: line-through; white-space: nowrap;"
t-esc="compute_currency(product.website_public_price)" t-options="{'widget': 'monetary', 'display_currency': website.get_current_pricelist().currency_id, 'from_currency': website.currency_id}" t-att-style="'text-decoration: line-through; white-space: nowrap; ' + '' if (compute_currency(product.lst_price) - product.website_price) &gt; 0.01 and website.get_current_pricelist().discount_policy == 'without_discount' else 'display: none;'"
t-esc="compute_currency(product.website_public_price)" t-options="{'widget': 'monetary', 'display_currency': website.get_current_pricelist().currency_id, 'from_currency': website.currency_id}" t-att-style="'text-decoration: line-through; white-space: nowrap; ' + '' if product.website_price_difference and website.get_current_pricelist().discount_policy == 'without_discount' else 'display: none;'"
/>
<b class="oe_price" style="white-space: nowrap;" t-esc="product.website_price" t-options="{'widget': 'monetary', 'display_currency': website.currency_id}"/>
<span itemprop="price" style="display:none;" t-esc="product.website_price"/>
@@ -1002,7 +1002,7 @@
<div class="text-muted hidden-xs" t-field="product.description_sale" />
</td>
<td class='td-price'>
<t t-if="(compute_currency(product.lst_price) - product.website_price) &gt; 0.01 and website.get_current_pricelist().discount_policy=='without_discount'">
<t t-if="product.website_price_difference and website.get_current_pricelist().discount_policy=='without_discount'">
<del class="text-danger mr8" style="white-space: nowrap;" t-field="product.lst_price" t-options="{'widget': 'monetary','from_currency': product.currency_id, 'display_currency': website.currency_id}" />
</t>
<span t-field="product.website_price" style="white-space: nowrap;" t-options="{'widget': 'monetary','display_currency': website.currency_id}" />
+1 -1
View File
@@ -324,7 +324,7 @@ class IrHttp(models.AbstractModel):
# cache
etag = hasattr(request, 'httprequest') and request.httprequest.headers.get('If-None-Match')
retag = '"%s"' % hashlib.md5(last_update).hexdigest()
retag = '"%s"' % hashlib.md5(content).hexdigest()
status = status or (304 if etag == retag else 200)
headers.append(('ETag', retag))
headers.append(('Cache-Control', 'max-age=%s' % (STATIC_CACHE if unique else 0)))
@@ -687,6 +687,30 @@ class TestFields(common.TransactionCase):
self.assertEqual(len(discussion.important_messages), 2)
self.assertEqual(len(discussion.very_important_messages), 2)
def test_70_x2many_write(self):
discussion = self.env.ref('test_new_api.discussion_0')
Message = self.env['test_new_api.message']
# There must be 3 messages, 0 important
self.assertEqual(len(discussion.messages), 3)
self.assertEqual(len(discussion.important_messages), 0)
self.assertEqual(len(discussion.very_important_messages), 0)
discussion.important_messages = [(0, 0, {
'body': 'What is the answer?',
'important': True,
})]
# There must be 4 messages, 1 important
self.assertEqual(len(discussion.messages), 4)
self.assertEqual(len(discussion.important_messages), 1)
self.assertEqual(len(discussion.very_important_messages), 1)
discussion.very_important_messages |= Message.new({
'body': '42',
'important': True,
})
# There must be 5 messages, 2 important
self.assertEqual(len(discussion.messages), 5)
self.assertEqual(len(discussion.important_messages), 2)
self.assertEqual(len(discussion.very_important_messages), 2)
class TestHtmlField(common.TransactionCase):