summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2018-07-30 14:08:56 +0200
committerChristophe Simonis <chs@odoo.com>2018-07-30 14:08:56 +0200
commita6e401a2eebd98adf3b0661a45cbe747384d3ae7 (patch)
tree3a7ee35c3a937c87580586e412a6598d61b770c0
parent1fd430d08fc71bf4205e763c92fd4d77a2c28f72 (diff)
parent44ea58234ec0d902ddf0caf7aefb367acc013627 (diff)
[MERGE] forward port branch 11.0 up to 44ea58234ec
-rw-r--r--.tx/config5
-rw-r--r--addons/account/models/account_invoice.py2
-rw-r--r--addons/event/data/email_template_data.xml1
-rw-r--r--addons/event/models/event.py11
-rw-r--r--addons/hr_timesheet/report/report_timesheet_templates.xml6
-rw-r--r--addons/mail/models/mail_template.py2
-rw-r--r--addons/point_of_sale/models/pos_config.py5
-rw-r--r--addons/web/static/src/js/views/kanban/kanban_column_progressbar.js8
-rw-r--r--addons/web/static/src/less/kanban_column_progressbar.less5
-rw-r--r--addons/website_sale_delivery/controllers/main.py2
-rw-r--r--odoo/addons/base/models/ir_qweb_fields.py12
-rw-r--r--odoo/addons/test_converter/tests/test_html.py4
-rw-r--r--odoo/service/server.py2
-rw-r--r--odoo/tools/safe_eval.py4
14 files changed, 49 insertions, 20 deletions
diff --git a/.tx/config b/.tx/config
index ba9318f5a58..c9ebc9f6226 100644
--- a/.tx/config
+++ b/.tx/config
@@ -32,6 +32,11 @@ file_filter = addons/account_budget/i18n/<lang>.po
source_file = addons/account_budget/i18n/account_budget.pot
source_lang = en
+[odoo-master.account_cash_basis_base_account]
+file_filter = addons/account_cash_basis_base_account/i18n/<lang>.po
+source_file = addons/account_cash_basis_base_account/i18n/account_cash_basis_base_account.pot
+source_lang = en
+
[odoo-master.account_cancel]
file_filter = addons/account_cancel/i18n/<lang>.po
source_file = addons/account_cancel/i18n/account_cancel.pot
diff --git a/addons/account/models/account_invoice.py b/addons/account/models/account_invoice.py
index d3aad9da4a9..8e8584d1151 100644
--- a/addons/account/models/account_invoice.py
+++ b/addons/account/models/account_invoice.py
@@ -1262,6 +1262,8 @@ class AccountInvoice(models.Model):
values[name] = line[name]
elif name == 'invoice_line_tax_ids':
values[name] = [(6, 0, line[name].ids)]
+ elif name == 'analytic_tag_ids':
+ values[name] = [(6, 0, line[name].ids)]
result.append((0, 0, values))
return result
diff --git a/addons/event/data/email_template_data.xml b/addons/event/data/email_template_data.xml
index b7788cba9a3..38329a8c6f4 100644
--- a/addons/event/data/email_template_data.xml
+++ b/addons/event/data/email_template_data.xml
@@ -326,7 +326,6 @@
<td style="padding:25px 0px;">
<strong>Add this event to your calendar</strong>
<a href="https://www.google.com/calendar/render?action=TEMPLATE&text=${object.event_id.name}&dates=${date_begin}/${date_end}&location=${location}" style="padding:3px 5px;border:1px solid #875A7B;color:#875A7B;text-decoration:none;border-radius:3px;" target="new"><img src="/web_editor/font_to_img/61525/rgb(135,90,123)/16" style="vertical-align:middle;" height="16"> Google</a>
- <a href="https://bay02.calendar.live.com/calendar/calendar.aspx?rru=addevent&summary=${object.event_id.name}&dtstart=${date_begin}&dtend=${date_end}&location=${location}" style="padding:3px 5px;border:1px solid #875A7B;color:#875A7B;text-decoration:none;border-radius:3px;" target="new"><img src="/web_editor/font_to_img/61525/rgb(135,90,123)/16" style="vertical-align:middle;" height="16"> Outlook</a>
<a href="https://calendar.yahoo.com/?v=60&view=d&type=20&title=${object.event_id.name}&in_loc=${location}&st=${format_tz(object.event_id.date_begin, tz='UTC', format='%Y%m%dT%H%M%S')}&et=${format_tz(object.event_id.date_end, tz='UTC', format='%Y%m%dT%H%M%S')}" style="padding:3px 5px;border:1px solid #875A7B;color:#875A7B;text-decoration:none;border-radius:3px;" target="new"><img src="/web_editor/font_to_img/61525/rgb(135,90,123)/16" style="vertical-align:middle;" height="16"> Yahoo</a>
</td>
</tr>
diff --git a/addons/event/models/event.py b/addons/event/models/event.py
index 99f6b35eb52..afeb345b4ee 100644
--- a/addons/event/models/event.py
+++ b/addons/event/models/event.py
@@ -484,6 +484,17 @@ class EventRegistration(models.Model):
return super(EventRegistration, self)._message_post_after_hook(message, values, notif_layout)
@api.multi
+ def message_get_default_recipients(self):
+ # Prioritize registration email over partner_id, which may be shared when a single
+ # partner booked multiple seats
+ return {
+ r.id: {'partner_ids': [],
+ 'email_to': r.email,
+ 'email_cc': False}
+ for r in self
+ }
+
+ @api.multi
def action_send_badge_email(self):
""" Open a window to compose an email, with the template - 'event_badge'
message loaded by default
diff --git a/addons/hr_timesheet/report/report_timesheet_templates.xml b/addons/hr_timesheet/report/report_timesheet_templates.xml
index fea714a5d7a..dbc0ad4a583 100644
--- a/addons/hr_timesheet/report/report_timesheet_templates.xml
+++ b/addons/hr_timesheet/report/report_timesheet_templates.xml
@@ -44,7 +44,7 @@
<t t-if="l.task_id"><span t-field="l.task_id.name"/></t>
</td>
<td class="text-right">
- <span t-esc="'%s:%02.0f' % tuple(int(round(x)) for x in divmod(l.unit_amount*60,60))"/>
+ <span t-field="l.unit_amount" t-options="{'widget': 'float_time'}"/>
</td>
</tr>
</t>
@@ -53,7 +53,9 @@
<td />
<td t-if="show_task"/>
<td class="text-right"><strong>Total</strong></td>
- <td class="text-right"><strong t-esc="'%s:%02.0f' % tuple(int(round(x)) for x in divmod(sum(docs.mapped('unit_amount'))*60,60))"/></td>
+ <t t-set="total_value" t-value="sum(docs.mapped('unit_amount'))" />
+ <t t-set="sign" t-value="'-' if total_value &lt; 0 else ''"/>
+ <td class="text-right"><strong t-esc="sign + '%s:%02.0f' % tuple(int(round(x)) for x in divmod(abs(total_value)*60,60))"/></td>
</tr>
</tbody>
</table>
diff --git a/addons/mail/models/mail_template.py b/addons/mail/models/mail_template.py
index f5d4b4e3ac6..cb9c4a433a8 100644
--- a/addons/mail/models/mail_template.py
+++ b/addons/mail/models/mail_template.py
@@ -63,7 +63,7 @@ def format_amount(env, amount, currency):
lang = env['res.lang']._lang_get(env.context.get('lang') or 'en_US')
formatted_amount = lang.format(fmt, currency.round(amount), grouping=True, monetary=True)\
- .replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'\u2011')
+ .replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}')
pre = post = u''
if currency.position == 'before':
diff --git a/addons/point_of_sale/models/pos_config.py b/addons/point_of_sale/models/pos_config.py
index 67e4f5a527b..a43246e03bd 100644
--- a/addons/point_of_sale/models/pos_config.py
+++ b/addons/point_of_sale/models/pos_config.py
@@ -255,6 +255,11 @@ class PosConfig(models.Model):
if any(self.journal_ids.mapped(lambda journal: journal.currency_id and journal.currency_id != self.currency_id)):
raise ValidationError(_("All payment methods must be in the same currency as the Sales Journal or the company currency if that is not set."))
+ @api.constrains('company_id', 'available_pricelist_ids')
+ def _check_companies(self):
+ if any(self.available_pricelist_ids.mapped(lambda pl: pl.company_id.id not in (False, self.company_id.id))):
+ raise ValidationError(_("The selected pricelists must belong to no company or the company of the point of sale."))
+
@api.onchange('iface_print_via_proxy')
def _onchange_iface_print_via_proxy(self):
self.iface_print_auto = self.iface_print_via_proxy
diff --git a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js
index fad822efdb9..b597ccf1c60 100644
--- a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js
+++ b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js
@@ -141,6 +141,7 @@ var KanbanColumnProgressBar = Widget.extend({
}
// Display and animate the progress bars
+ var barNumber = 0;
_.each(self.colors, function (val, key) {
var $bar = self.$bars[val];
var count = self.subgroupCounts && self.subgroupCounts[key] || 0;
@@ -165,7 +166,14 @@ var KanbanColumnProgressBar = Widget.extend({
window.getComputedStyle($bar[0]).getPropertyValue('width'); // Force reflow so that animations work
if (count > 0) {
$bar.addClass('o_bar_has_records');
+ // Make sure every bar that has records has some space
+ // and that everything adds up to 100%
+ var minWidth = 6*barNumber;
+ var maxWidth = 100 - minWidth;
+ self.$('.progress-bar.o_bar_has_records').css('max-width', maxWidth + '%');
+ self.$('.progress-bar.o_bar_has_records').css('min-width', minWidth + '%');
$bar.css('width', (count * 100 / self.groupCount) + '%');
+ barNumber++;
} else {
$bar.css('width', '');
}
diff --git a/addons/web/static/src/less/kanban_column_progressbar.less b/addons/web/static/src/less/kanban_column_progressbar.less
index f4cffd6c097..233ae5c0d01 100644
--- a/addons/web/static/src/less/kanban_column_progressbar.less
+++ b/addons/web/static/src/less/kanban_column_progressbar.less
@@ -73,11 +73,6 @@
margin-bottom: 0;
box-shadow: none;
cursor: pointer;
-
- // Be sure that a bar with data has a minimun width
- &.o_bar_has_records {
- min-width: 10px;
- }
}
.o_kanban_counter_label {
diff --git a/addons/website_sale_delivery/controllers/main.py b/addons/website_sale_delivery/controllers/main.py
index 5a06774fcad..52522fa8117 100644
--- a/addons/website_sale_delivery/controllers/main.py
+++ b/addons/website_sale_delivery/controllers/main.py
@@ -76,4 +76,4 @@ class WebsiteSaleDelivery(WebsiteSale):
lang = request.env['res.lang']._lang_get(request.env.context.get('lang') or 'en_US')
return lang.format(fmt, currency.round(amount), grouping=True, monetary=True)\
- .replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'\u2011')
+ .replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}')
diff --git a/odoo/addons/base/models/ir_qweb_fields.py b/odoo/addons/base/models/ir_qweb_fields.py
index 19e15ff4621..5a9000598de 100644
--- a/odoo/addons/base/models/ir_qweb_fields.py
+++ b/odoo/addons/base/models/ir_qweb_fields.py
@@ -7,6 +7,7 @@ from odoo import api, fields, models, _
from PIL import Image
import babel
from lxml import etree
+import math
from odoo.tools import html_escape as escape, posix_to_ldml, safe_eval, float_utils, format_date, pycompat
@@ -125,7 +126,7 @@ class IntegerConverter(models.AbstractModel):
@api.model
def value_to_html(self, value, options):
- return pycompat.to_text(self.user_lang().format('%d', value, grouping=True).replace(r'-', u'\u2011'))
+ return pycompat.to_text(self.user_lang().format('%d', value, grouping=True).replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}'))
class FloatConverter(models.AbstractModel):
@@ -145,7 +146,7 @@ class FloatConverter(models.AbstractModel):
value = float_utils.float_round(value, precision_digits=precision)
fmt = '%.{precision}f'.format(precision=precision)
- formatted = self.user_lang().format(fmt, value, grouping=True).replace(r'-', u'\u2011')
+ formatted = self.user_lang().format(fmt, value, grouping=True).replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}')
# %f does not strip trailing zeroes. %g does but its precision causes
# it to switch to scientific notation starting at a million *and* to
@@ -325,7 +326,7 @@ class MonetaryConverter(models.AbstractModel):
lang = self.user_lang()
formatted_amount = lang.format(fmt, display_currency.round(value),
- grouping=True, monetary=True).replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'\u2011')
+ grouping=True, monetary=True).replace(r' ', u'\N{NO-BREAK SPACE}').replace(r'-', u'-\N{ZERO WIDTH NO-BREAK SPACE}')
pre = post = u''
if display_currency.position == 'before':
@@ -367,8 +368,9 @@ class FloatTimeConverter(models.AbstractModel):
@api.model
def value_to_html(self, value, options):
- hours, minutes = divmod(value * 60, 60)
- return '%02d:%02d' % (hours, minutes)
+ sign = math.copysign(1.0, value)
+ hours, minutes = divmod(abs(value) * 60, 60)
+ return '%02d:%02d' % (sign * hours, minutes)
class DurationConverter(models.AbstractModel):
diff --git a/odoo/addons/test_converter/tests/test_html.py b/odoo/addons/test_converter/tests/test_html.py
index e915785e333..d04604a5c4f 100644
--- a/odoo/addons/test_converter/tests/test_html.py
+++ b/odoo/addons/test_converter/tests/test_html.py
@@ -73,7 +73,7 @@ class TestFloatExport(TestBasicExport):
converter = self.get_converter('float')
value = converter(-42.0)
- self.assertEqual(value, u"\u201142.0")
+ self.assertEqual(value, u"-\N{ZERO WIDTH NO-BREAK SPACE}42.0")
value = converter(42.0100)
self.assertEqual(value, "42.01")
@@ -120,7 +120,7 @@ class TestCurrencyExport(TestExport):
converted = self.convert(obj, dest=currency)
self.assertEqual(
- converted, u'<span class="oe_currency_value">\u20110.12</span>'
+ converted, u'<span class="oe_currency_value">-\N{ZERO WIDTH NO-BREAK SPACE}0.12</span>'
u'\N{NO-BREAK SPACE}{symbol}'.format(
obj=obj,
symbol=currency.symbol
diff --git a/odoo/service/server.py b/odoo/service/server.py
index 8899760ce91..4820b1e3257 100644
--- a/odoo/service/server.py
+++ b/odoo/service/server.py
@@ -131,7 +131,7 @@ class FSWatcher(object):
if isinstance(event, (FileCreatedEvent, FileModifiedEvent, FileMovedEvent)):
if not event.is_directory:
path = getattr(event, 'dest_path', event.src_path)
- if path.endswith('.py'):
+ if path.endswith('.py') and not os.path.basename(path).startswith('.~'):
try:
source = open(path, 'rb').read() + b'\n'
compile(source, path, 'exec')
diff --git a/odoo/tools/safe_eval.py b/odoo/tools/safe_eval.py
index 7a5ec03707a..ccb2e3e25b4 100644
--- a/odoo/tools/safe_eval.py
+++ b/odoo/tools/safe_eval.py
@@ -107,8 +107,8 @@ _SAFE_OPCODES = _EXPR_OPCODES.union(set(opmap[x] for x in [
'JUMP_FORWARD', 'JUMP_IF_TRUE', 'JUMP_IF_FALSE', 'JUMP_ABSOLUTE',
# New in Python 2.7 - http://bugs.python.org/issue4715 :
'JUMP_IF_FALSE_OR_POP', 'JUMP_IF_TRUE_OR_POP', 'POP_JUMP_IF_FALSE',
- 'POP_JUMP_IF_TRUE', 'SETUP_EXCEPT', 'END_FINALLY', 'RAISE_VARARGS',
- 'LOAD_NAME', 'STORE_NAME', 'DELETE_NAME', 'LOAD_ATTR',
+ 'POP_JUMP_IF_TRUE', 'SETUP_EXCEPT', 'SETUP_FINALLY', 'END_FINALLY',
+ 'RAISE_VARARGS', 'LOAD_NAME', 'STORE_NAME', 'DELETE_NAME', 'LOAD_ATTR',
'LOAD_FAST', 'STORE_FAST', 'DELETE_FAST', 'UNPACK_SEQUENCE',
'LOAD_GLOBAL', # Only allows access to restricted globals
] if x in opmap))