summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2019-08-29 16:45:15 +0200
committerChristophe Simonis <chs@odoo.com>2019-08-29 16:45:15 +0200
commit8bd6a93c74de7aa68b0a85cc6132aa22975462d8 (patch)
treeaf6334a048dd1e2c03f3a937c03feacc5b462efd /addons
parent3d6e91789968719c726420554d25b25f81282a55 (diff)
parentede253f1b2edbd10a1df3991438262a4a47059c1 (diff)
[MERGE] forward port branch saas-11.3 up to ede253f1b2e
Diffstat (limited to 'addons')
-rw-r--r--addons/account/models/account.py2
-rw-r--r--addons/account/models/account_move.py2
-rw-r--r--addons/account/tests/test_reconciliation.py62
-rw-r--r--addons/account_check_printing/models/account_payment.py5
-rw-r--r--addons/account_check_printing/views/account_payment_views.xml1
-rw-r--r--addons/auth_oauth/controllers/main.py17
-rw-r--r--addons/gamification/views/goal.xml5
-rw-r--r--addons/hr_recruitment/views/hr_recruitment_views.xml1
-rw-r--r--addons/mail/static/src/js/utils.js7
-rw-r--r--addons/maintenance/views/maintenance_views.xml8
-rw-r--r--addons/web/static/src/js/fields/relational_fields.js2
-rw-r--r--addons/web/static/src/js/views/graph/graph_view.js3
-rw-r--r--addons/web/static/src/js/widgets/auto_complete.js12
-rw-r--r--addons/web/static/tests/views/graph_tests.js21
-rw-r--r--addons/website/models/website.py7
-rw-r--r--addons/website_event_sale/models/sale_order.py5
-rw-r--r--addons/website_event_track/models/event_track.py2
17 files changed, 132 insertions, 30 deletions
diff --git a/addons/account/models/account.py b/addons/account/models/account.py
index c4569e91886..48185ea1b1c 100644
--- a/addons/account/models/account.py
+++ b/addons/account/models/account.py
@@ -824,7 +824,7 @@ class AccountJournal(models.Model):
@api.depends('company_id')
def _belong_to_company(self):
for journal in self:
- journal.belong_to_company = (journal.company_id.id == self.env.user.company_id.id)
+ journal.belongs_to_company = (journal.company_id.id == self.env.user.company_id.id)
@api.multi
def _search_company_journals(self, operator, value):
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py
index edb8f4849a1..b2125d4eb4c 100644
--- a/addons/account/models/account_move.py
+++ b/addons/account/models/account_move.py
@@ -541,7 +541,7 @@ class AccountMoveLine(models.Model):
else:
date = partial_line.credit_move_id.date if partial_line.debit_move_id == line else partial_line.debit_move_id.date
rate = line.currency_id.with_context(date=date).rate
- amount_residual_currency += sign_partial_line * partial_line.amount * rate
+ amount_residual_currency += sign_partial_line * line.currency_id.round(partial_line.amount * rate)
#computing the `reconciled` field.
reconciled = False
diff --git a/addons/account/tests/test_reconciliation.py b/addons/account/tests/test_reconciliation.py
index e9b494b385e..28ce8f054f1 100644
--- a/addons/account/tests/test_reconciliation.py
+++ b/addons/account/tests/test_reconciliation.py
@@ -1181,6 +1181,68 @@ class TestReconciliationExec(TestReconciliation):
self.assertEqual(invoice_cust_1.state, 'open',
'Invoice is in status %s' % invoice_cust_1.state)
+ def test_inv_refund_foreign_payment_writeoff_domestic(self):
+ company = self.env.ref('base.main_company')
+ self.env['res.currency.rate'].search([]).unlink()
+ self.env['res.currency.rate'].create({
+ 'name': time.strftime('%Y') + '-07-01',
+ 'rate': 1.0,
+ 'currency_id': self.currency_euro_id,
+ 'company_id': company.id
+ })
+ self.env['res.currency.rate'].create({
+ 'name': time.strftime('%Y') + '-07-01',
+ 'rate': 1.113900, # Don't change this !
+ 'currency_id': self.currency_usd_id,
+ 'company_id': self.env.ref('base.main_company').id
+ })
+ inv1 = self.create_invoice(invoice_amount=480, currency_id=self.currency_usd_id)
+ inv2 = self.create_invoice(type="out_refund", invoice_amount=140, currency_id=self.currency_usd_id)
+
+ payment = self.env['account.payment'].create({
+ 'payment_method_id': self.inbound_payment_method.id,
+ 'payment_type': 'inbound',
+ 'partner_type': 'customer',
+ 'partner_id': inv1.partner_id.id,
+ 'amount': 287.20,
+ 'journal_id': self.bank_journal_euro.id,
+ 'company_id': company.id,
+ })
+ payment.post()
+
+ inv1_receivable = inv1.move_id.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
+ inv2_receivable = inv2.move_id.line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
+ pay_receivable = payment.move_line_ids.filtered(lambda l: l.account_id.internal_type == 'receivable')
+
+ data_for_reconciliation = [
+ {
+ 'type': 'partner',
+ 'id': inv1.partner_id.id,
+ 'mv_line_ids': (inv1_receivable + inv2_receivable + pay_receivable).ids,
+ 'new_mv_line_dicts': [
+ {
+ 'credit': 20.09, # 18.04 in foreign currency
+ 'debit': 0.00,
+ 'journal_id': self.bank_journal_euro.id,
+ 'name': 'Total WriteOff (Fees)',
+ 'account_id': self.diff_expense_account.id
+ }
+ ]
+ }
+ ]
+
+ self.env["account.reconciliation.widget"].process_move_lines(data_for_reconciliation)
+
+ self.assertTrue(inv1_receivable.full_reconcile_id.exists())
+ self.assertEquals(inv1_receivable.full_reconcile_id, inv2_receivable.full_reconcile_id)
+ self.assertEquals(inv1_receivable.full_reconcile_id, pay_receivable.full_reconcile_id)
+
+ self.assertTrue(inv1.reconciled)
+ self.assertTrue(inv2.reconciled)
+
+ self.assertEquals(inv1.state, 'paid')
+ self.assertEquals(inv2.state, 'paid')
+
def test_multiple_term_reconciliation_opw_1906665(self):
'''Test that when registering a payment to an invoice with multiple
payment term lines the reconciliation happens against the line
diff --git a/addons/account_check_printing/models/account_payment.py b/addons/account_check_printing/models/account_payment.py
index 882cf796db0..c706502985b 100644
--- a/addons/account_check_printing/models/account_payment.py
+++ b/addons/account_check_printing/models/account_payment.py
@@ -115,6 +115,11 @@ class AccountPayment(models.Model):
""" This method is a hook for l10n_xx_check_printing modules to implement actual check printing capabilities """
raise UserError(_("You have to choose a check layout. For this, go in Apps, search for 'Checks layout' and install one."))
+
+ def set_check_amount_in_words(self):
+ for payment in self:
+ payment.check_amount_in_words = payment.currency_id.amount_to_text(payment.amount) if payment.currency_id else ''
+
#######################
#CHECK PRINTING METHODS
#######################
diff --git a/addons/account_check_printing/views/account_payment_views.xml b/addons/account_check_printing/views/account_payment_views.xml
index 56e3944b9d7..596449f9474 100644
--- a/addons/account_check_printing/views/account_payment_views.xml
+++ b/addons/account_check_printing/views/account_payment_views.xml
@@ -8,6 +8,7 @@
<xpath expr="//button[@name='post']" position="before">
<button name="print_checks" class="oe_highlight" attrs="{'invisible': ['|', ('payment_method_code', '!=', 'check_printing'), ('state', '!=', 'posted')]}" string="Print Check" type="object"/>
<button name="unmark_sent" attrs="{'invisible': ['|', ('payment_method_code', '!=', 'check_printing'), ('state', '!=', 'sent')]}" string="Unmark Sent" type="object"/>
+ <button name="set_check_amount_in_words" attrs="{'invisible': ['|', ('payment_method_code', '!=', 'check_printing'), ('check_amount_in_words', '!=', False)]}" string="Reset Amount in Words" type="object" groups="base.group_no_one"/>
</xpath>
<xpath expr="//div[@name='amount_div']" position="after">
<field name="check_amount_in_words" attrs="{'invisible': [('payment_method_code', '!=', 'check_printing')], 'readonly': [('state', '!=', 'draft')]}" groups="base.group_no_one"/>
diff --git a/addons/auth_oauth/controllers/main.py b/addons/auth_oauth/controllers/main.py
index 3b300070929..00eea3268b6 100644
--- a/addons/auth_oauth/controllers/main.py
+++ b/addons/auth_oauth/controllers/main.py
@@ -109,19 +109,10 @@ class OAuthLogin(Home):
return response
- @http.route()
- def web_auth_signup(self, *args, **kw):
- providers = self.list_providers()
- 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()
- response = super(OAuthLogin, self).web_auth_reset_password(*args, **kw)
- response.qcontext.update(providers=providers)
- return response
+ def get_auth_signup_qcontext(self):
+ result = super(OAuthLogin, self).get_auth_signup_qcontext()
+ result["providers"] = self.list_providers()
+ return result
class OAuthController(http.Controller):
diff --git a/addons/gamification/views/goal.xml b/addons/gamification/views/goal.xml
index a3386496a47..da625c5eb51 100644
--- a/addons/gamification/views/goal.xml
+++ b/addons/gamification/views/goal.xml
@@ -135,6 +135,7 @@
<field name="completeness"/>
<field name="state"/>
<field name="target_goal"/>
+ <field name="definition_description"/>
<field name="definition_condition"/>
<field name="definition_suffix"/>
<field name="definition_display"/>
@@ -143,7 +144,9 @@
<field name="last_update"/>
<templates>
<t t-name="kanban-tooltip">
- <field name="definition_description"/>
+ <ul class="oe_kanban_tooltip">
+ <li><t t-esc="record.definition_description.value" /></li>
+ </ul>
</t>
<t t-name="kanban-box">
<div t-attf-class="oe_kanban_card o_kanban_gamification #{record.end_date.raw_value &lt; record.last_update.raw_value &amp; record.state.raw_value == 'failed' ? 'oe_kanban_color_2' : ''} #{record.end_date.raw_value &lt; record.last_update.raw_value &amp; record.state.raw_value == 'reached' ? 'oe_kanban_color_5' : ''}">
diff --git a/addons/hr_recruitment/views/hr_recruitment_views.xml b/addons/hr_recruitment/views/hr_recruitment_views.xml
index 5fa6424e959..2d81b4a6297 100644
--- a/addons/hr_recruitment/views/hr_recruitment_views.xml
+++ b/addons/hr_recruitment/views/hr_recruitment_views.xml
@@ -277,6 +277,7 @@
<field name="user_email"/>
<field name="partner_name"/>
<field name="type_id"/>
+ <field name="partner_id"/>
<field name="job_id"/>
<field name="department_id"/>
<field name="message_needaction_counter"/>
diff --git a/addons/mail/static/src/js/utils.js b/addons/mail/static/src/js/utils.js
index 740be8eb54d..3673dd2ab21 100644
--- a/addons/mail/static/src/js/utils.js
+++ b/addons/mail/static/src/js/utils.js
@@ -8,7 +8,12 @@ var _t = core._t;
function parseAndTransform(htmlString, transformFunction) {
var openToken = "OPEN" + Date.now();
var string = htmlString.replace(/&lt;/g, openToken);
- var children = $('<div>').html(string).contents();
+ var children;
+ try {
+ children = $('<div>').html(string).contents();
+ } catch (e) {
+ children = $('<div>').html('<pre>' + string + '</pre>').contents();
+ }
return _parseAndTransform(children, transformFunction)
.replace(new RegExp(openToken, "g"), "&lt;");
}
diff --git a/addons/maintenance/views/maintenance_views.xml b/addons/maintenance/views/maintenance_views.xml
index 6d847f32290..84369193854 100644
--- a/addons/maintenance/views/maintenance_views.xml
+++ b/addons/maintenance/views/maintenance_views.xml
@@ -126,8 +126,8 @@
<templates>
<t t-name="kanban-tooltip">
<ul class="oe_kanban_tooltip">
- <li><b>Category:</b> <field name="category_id"/></li>
- <li><b>Request to:</b> <field name="user_id"/></li>
+ <li t-if="record.category_id.raw_value"><b>Category:</b> <t t-esc="record.category_id.value"/></li>
+ <li t-if="record.user_id.raw_value"><b>Request to:</b> <t t-esc="record.user_id.value"/></li>
</ul>
</t>
<t t-name="kanban-box">
@@ -424,8 +424,8 @@
<templates>
<t t-name="kanban-tooltip">
<ul class="oe_kanban_tooltip">
- <li><b>Serial Number:</b> <field name="serial_no"/></li>
- <li><b>Model Number:</b> <field name="model"/></li>
+ <li t-if="record.serial_no.raw_value"><b>Serial Number:</b> <t t-esc="record.serial_no.value"/></li>
+ <li t-if="record.model.raw_value"><b>Model Number:</b> <t t-esc="record.model.value"/></li>
</ul>
</t>
<t t-name="kanban-box">
diff --git a/addons/web/static/src/js/fields/relational_fields.js b/addons/web/static/src/js/fields/relational_fields.js
index f1086f2a2d2..f591af6ddac 100644
--- a/addons/web/static/src/js/fields/relational_fields.js
+++ b/addons/web/static/src/js/fields/relational_fields.js
@@ -2308,7 +2308,7 @@ var FieldStatus = AbstractField.extend({
var FieldSelection = AbstractField.extend({
template: 'FieldSelection',
specialData: "_fetchSpecialRelation",
- supportedFieldTypes: ['selection', 'many2one'],
+ supportedFieldTypes: ['selection'],
events: _.extend({}, AbstractField.prototype.events, {
'change': '_onChange',
}),
diff --git a/addons/web/static/src/js/views/graph/graph_view.js b/addons/web/static/src/js/views/graph/graph_view.js
index a55da16c6da..ca6c5bdf44c 100644
--- a/addons/web/static/src/js/views/graph/graph_view.js
+++ b/addons/web/static/src/js/views/graph/graph_view.js
@@ -53,6 +53,9 @@ var GraphView = AbstractView.extend({
this.arch.children.forEach(function (field) {
var fieldName = field.attrs.name;
+ if (fieldName === "id") {
+ return;
+ }
var interval = field.attrs.interval;
if (interval) {
intervalMapping[fieldName] = interval;
diff --git a/addons/web/static/src/js/widgets/auto_complete.js b/addons/web/static/src/js/widgets/auto_complete.js
index a25dc0150f5..1821e555331 100644
--- a/addons/web/static/src/js/widgets/auto_complete.js
+++ b/addons/web/static/src/js/widgets/auto_complete.js
@@ -127,12 +127,22 @@ return Widget.extend({
var $item = self.make_list_item(result).appendTo($list);
result.$el = $item;
});
+ // IE9 doesn't support addEventListener with option { once: true }
+ this.el.onmousemove = function (ev) {
+ self.$('li').each(function (index, li) {
+ li.onmouseenter = self.focus_element.bind(self, $(li));
+ });
+ var targetFocus = ev.target.tagName === 'LI' ?
+ ev.target :
+ ev.target.closest('li');
+ self.focus_element($(targetFocus));
+ self.el.onmousemove = null;
+ };
this.show();
},
make_list_item: function (result) {
var self = this;
var $li = $('<li>')
- .hover(function () {self.focus_element($li);})
.mousedown(function (ev) {
if (ev.button === 0) { // left button
self.select(ev, {item: {facet: result.facet}});
diff --git a/addons/web/static/tests/views/graph_tests.js b/addons/web/static/tests/views/graph_tests.js
index afa3ea9d0ef..cea1ce9fdd8 100644
--- a/addons/web/static/tests/views/graph_tests.js
+++ b/addons/web/static/tests/views/graph_tests.js
@@ -122,6 +122,27 @@ QUnit.module('Views', {
graph.destroy();
});
+ QUnit.test('field id not in groupBy', function (assert) {
+ assert.expect(1);
+
+ var graph = createView({
+ View: GraphView,
+ model: "foo",
+ data: this.data,
+ arch: '<graph string="Partners">' +
+ '<field name="id"/>' +
+ '</graph>',
+ mockRPC: function (route, args) {
+ if (args.method === 'read_group') {
+ assert.deepEqual(args.kwargs.groupby, [],
+ 'groupby should not contain id field');
+ }
+ return this._super.apply(this, arguments);
+ }
+ });
+ graph.destroy();
+ });
+
QUnit.test('switching mode', function (assert) {
assert.expect(6);
diff --git a/addons/website/models/website.py b/addons/website/models/website.py
index 3b25ca5fcf4..62f4ff1db97 100644
--- a/addons/website/models/website.py
+++ b/addons/website/models/website.py
@@ -725,9 +725,6 @@ class Website(models.Model):
domain_part, url = rule.build(value, append_unknown=False)
if not query_string or query_string.lower() in url.lower():
page = {'loc': url}
- for key, val in value.items():
- if key.startswith('__'):
- page[key[2:]] = val
if url in ('/sitemap.xml',):
continue
if url in url_set:
@@ -751,9 +748,9 @@ class Website(models.Model):
for page in pages:
record = {'loc': page['url'], 'id': page['id'], 'name': page['name']}
if page.view_id and page.view_id.priority != 16:
- record['__priority'] = min(round(page.view_id.priority / 32.0, 1), 1)
+ record['priority'] = min(round(page.view_id.priority / 32.0, 1), 1)
if page['write_date']:
- record['__lastmod'] = page['write_date'].date()
+ record['lastmod'] = page['write_date'].date()
yield record
@api.multi
diff --git a/addons/website_event_sale/models/sale_order.py b/addons/website_event_sale/models/sale_order.py
index cd25e6e1943..c13e8a4c23e 100644
--- a/addons/website_event_sale/models/sale_order.py
+++ b/addons/website_event_sale/models/sale_order.py
@@ -41,7 +41,10 @@ class SaleOrder(models.Model):
values['product_id'] = ticket.product_id.id
values['event_id'] = ticket.event_id.id
values['event_ticket_id'] = ticket.id
- values['price_unit'] = ticket.price_reduce
+ if order.pricelist_id.discount_policy == 'without_discount':
+ values['price_unit'] = ticket.price
+ else:
+ values['price_unit'] = ticket.price_reduce
values['name'] = ticket.get_ticket_multiline_description_sale()
# avoid writing related values that end up locking the product record
diff --git a/addons/website_event_track/models/event_track.py b/addons/website_event_track/models/event_track.py
index 2f35e86bb0e..caeb64f8a84 100644
--- a/addons/website_event_track/models/event_track.py
+++ b/addons/website_event_track/models/event_track.py
@@ -160,7 +160,7 @@ class Track(models.Model):
def message_get_suggested_recipients(self):
recipients = super(Track, self).message_get_suggested_recipients()
for track in self:
- if track.partner_email != track.partner_id.email:
+ if track.partner_email and track.partner_email != track.partner_id.email:
track._message_add_suggested_recipient(recipients, email=track.partner_email, reason=_('Speaker Email'))
return recipients