summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2017-10-26 19:03:19 +0200
committerChristophe Simonis <chs@odoo.com>2017-10-26 19:03:19 +0200
commita2890c1e76c9c73d80689f78aa2e6665ecdc9f31 (patch)
tree9eb71d9b266535bb9a789a0c9e5692a4431993ce
parentf86141aac265bb972e5dd6688f7bde674f4d1249 (diff)
parentbbc226cd6cc17c69979f81831a3da8cc668bf064 (diff)
[MERGE] forward port branch 10.0 up to bbc226cd6cc
-rw-r--r--addons/account/models/account_move.py14
-rw-r--r--addons/google_calendar/models/google_calendar.py2
-rw-r--r--addons/hr_expense/models/hr_expense.py22
-rw-r--r--addons/l10n_ca/data/account_chart_template_after_data.xml2
-rw-r--r--addons/l10n_ca/data/l10n_ca_chart_data.xml2
-rw-r--r--addons/l10n_fr_fec/wizard/account_fr_fec.py14
-rw-r--r--addons/mrp/models/stock_move.py2
-rw-r--r--addons/sale/models/sale.py18
-rw-r--r--addons/website/static/src/js/website.js2
-rw-r--r--addons/website_event/static/src/js/website_event.js4
-rw-r--r--addons/website_event/views/website_event_templates.xml4
-rw-r--r--addons/website_event_questions/views/website_event_questions_templates.xml2
-rw-r--r--addons/website_mail_channel/controllers/main.py14
-rw-r--r--addons/website_mail_channel/tests/__init__.py2
-rw-r--r--addons/website_mail_channel/tests/test_unsubscribe.py71
15 files changed, 137 insertions, 38 deletions
diff --git a/addons/account/models/account_move.py b/addons/account/models/account_move.py
index f724ef8dcd3..79c539dcacf 100644
--- a/addons/account/models/account_move.py
+++ b/addons/account/models/account_move.py
@@ -1533,6 +1533,15 @@ class AccountPartialReconcile(models.Model):
partial_reconciles._compute_partial_lines()
return move_lines, partial_reconciles
+ def _get_tax_cash_basis_base_account(self, line, tax):
+ ''' Get the account of lines that will contain the base amount of taxes.
+
+ :param line: An account.move.line record
+ :param tax: An account.tax record
+ :return: An account record
+ '''
+ return line.account_id
+
def create_tax_cash_basis_entry(self, percentage_before_rec):
self.ensure_one()
move_date = self.debit_move_id.date
@@ -1590,11 +1599,12 @@ class AccountPartialReconcile(models.Model):
newly_created_move = self._create_tax_basis_move()
#create cash basis entry for the base
for tax in line.tax_ids:
+ account_id = self._get_tax_cash_basis_base_account(line, tax)
self.env['account.move.line'].with_context(check_move_validity=False).create({
'name': line.name,
'debit': rounded_amt > 0 and rounded_amt or 0.0,
'credit': rounded_amt < 0 and abs(rounded_amt) or 0.0,
- 'account_id': line.account_id.id,
+ 'account_id': account_id.id,
'tax_exigible': True,
'tax_ids': [(6, 0, [tax.id])],
'move_id': newly_created_move.id,
@@ -1606,7 +1616,7 @@ class AccountPartialReconcile(models.Model):
'name': line.name,
'credit': rounded_amt > 0 and rounded_amt or 0.0,
'debit': rounded_amt < 0 and abs(rounded_amt) or 0.0,
- 'account_id': line.account_id.id,
+ 'account_id': account_id.id,
'tax_exigible': True,
'move_id': newly_created_move.id,
'currency_id': line.currency_id.id,
diff --git a/addons/google_calendar/models/google_calendar.py b/addons/google_calendar/models/google_calendar.py
index 710b0ddaab9..5caeaf87e89 100644
--- a/addons/google_calendar/models/google_calendar.py
+++ b/addons/google_calendar/models/google_calendar.py
@@ -922,7 +922,7 @@ class GoogleCalendar(models.AbstractModel):
def get_minTime(self):
number_of_week = self.env['ir.config_parameter'].sudo().get_param('calendar.week_synchro', default=13)
- return datetime.now() - timedelta(weeks=number_of_week)
+ return datetime.now() - timedelta(weeks=int(number_of_week))
def get_need_synchro_attendee(self):
return self.env['ir.config_parameter'].sudo().get_param('calendar.block_synchro_attendee', default=True)
diff --git a/addons/hr_expense/models/hr_expense.py b/addons/hr_expense/models/hr_expense.py
index 023ade1b359..cbcab281e5a 100644
--- a/addons/hr_expense/models/hr_expense.py
+++ b/addons/hr_expense/models/hr_expense.py
@@ -426,13 +426,7 @@ class HrExpenseSheet(models.Model):
@api.model
def create(self, vals):
- # Add the followers at creation, so they can be notified
- if vals.get('employee_id'):
- employee = self.env['hr.employee'].browse(vals['employee_id'])
- users = self._get_users_to_subscribe(employee=employee) - self.env.user
- vals['message_follower_ids'] = []
- for partner in users.mapped('partner_id'):
- vals['message_follower_ids'] += self.env['mail.followers']._add_follower_command(self._name, [], {partner.id: None}, {})[0]
+ self._create_set_followers(vals)
sheet = super(HrExpenseSheet, self).create(vals)
self.check_consistency()
return sheet
@@ -484,6 +478,20 @@ class HrExpenseSheet(models.Model):
users = self._get_users_to_subscribe()
self.message_subscribe_users(user_ids=users.ids)
+ @api.model
+ def _create_set_followers(self, values):
+ # Add the followers at creation, so they can be notified
+ employee_id = values.get('employee_id')
+ if not employee_id:
+ return
+
+ employee = self.env['hr.employee'].browse(employee_id)
+ users = self._get_users_to_subscribe(employee=employee) - self.env.user
+ values['message_follower_ids'] = []
+ MailFollowers = self.env['mail.followers']
+ for partner in users.mapped('partner_id'):
+ values['message_follower_ids'] += MailFollowers._add_follower_command(self._name, [], {partner.id: None}, {})[0]
+
@api.onchange('employee_id')
def _onchange_employee_id(self):
self.address_id = self.employee_id.address_home_id
diff --git a/addons/l10n_ca/data/account_chart_template_after_data.xml b/addons/l10n_ca/data/account_chart_template_after_data.xml
index a3c1e720b18..6216f65899b 100644
--- a/addons/l10n_ca/data/account_chart_template_after_data.xml
+++ b/addons/l10n_ca/data/account_chart_template_after_data.xml
@@ -8,7 +8,7 @@
<field name="property_account_payable_id" ref="chart2111_en"/>
<field name="property_account_income_categ_id" ref="chart411_en"/>
<field name="property_account_expense_categ_id" ref="chart5111_en"/>
- <field name="property_stock_account_input_categ_id" ref="chart2141_en"/>
+ <field name="property_stock_account_input_categ_id" ref="chart2171_en"/>
<field name="property_stock_account_output_categ_id" ref="chart1145_en"/>
<field name="property_stock_valuation_account_id" ref="chart1141_en"/>
<field name="income_currency_exchange_account_id" ref="chart42_en"/>
diff --git a/addons/l10n_ca/data/l10n_ca_chart_data.xml b/addons/l10n_ca/data/l10n_ca_chart_data.xml
index 0a463374290..8610079a78f 100644
--- a/addons/l10n_ca/data/l10n_ca_chart_data.xml
+++ b/addons/l10n_ca/data/l10n_ca_chart_data.xml
@@ -217,7 +217,7 @@
<record id="chart2171_en" model="account.account.template">
<field name="code">2171</field>
- <field name="user_type_id" ref="account.data_account_type_current_liabilities"/>
+ <field name="user_type_id" ref="account.data_account_type_current_assets"/>
<field name="name">Stock Received But Not Billed</field>
<field name="chart_template_id" ref="ca_en_chart_template_en"/>
</record>
diff --git a/addons/l10n_fr_fec/wizard/account_fr_fec.py b/addons/l10n_fr_fec/wizard/account_fr_fec.py
index 215ed49cb4e..5b5bcc0fc88 100644
--- a/addons/l10n_fr_fec/wizard/account_fr_fec.py
+++ b/addons/l10n_fr_fec/wizard/account_fr_fec.py
@@ -5,10 +5,12 @@
import base64
import csv
+from datetime import datetime
import StringIO
from odoo import api, fields, models, _
from odoo.exceptions import Warning
+from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
class AccountFrFec(models.TransientModel):
@@ -33,7 +35,7 @@ class AccountFrFec(models.TransientModel):
SELECT
'OUV' AS JournalCode,
'Balance initiale' AS JournalLib,
- 'Balance initiale PL' AS EcritureNum,
+ 'OUVERTURE/' || %s AS EcritureNum,
%s AS EcritureDate,
'120/129' AS CompteNum,
'Benefice (perte) reporte(e)' AS CompteLib,
@@ -67,8 +69,10 @@ class AccountFrFec(models.TransientModel):
'''
company = self.env.user.company_id
formatted_date_from = self.date_from.replace('-', '')
+ date_from = datetime.strptime(self.date_from, DEFAULT_SERVER_DATE_FORMAT)
+ formatted_date_year = date_from.year
self._cr.execute(
- sql_query, (formatted_date_from, formatted_date_from, formatted_date_from, self.date_from, company.id))
+ sql_query, (formatted_date_year, formatted_date_from, formatted_date_from, formatted_date_from, self.date_from, company.id))
listrow = []
row = self._cr.fetchone()
listrow = list(row)
@@ -130,7 +134,7 @@ class AccountFrFec(models.TransientModel):
SELECT
'OUV' AS JournalCode,
'Balance initiale' AS JournalLib,
- 'Balance initiale ' || MIN(aa.name) AS EcritureNum,
+ 'OUVERTURE/' || %s AS EcritureNum,
%s AS EcritureDate,
MIN(aa.code) AS CompteNum,
replace(MIN(aa.name), '|', '/') AS CompteLib,
@@ -170,8 +174,10 @@ class AccountFrFec(models.TransientModel):
HAVING sum(aml.balance) != 0
'''
formatted_date_from = self.date_from.replace('-', '')
+ date_from = datetime.strptime(self.date_from, DEFAULT_SERVER_DATE_FORMAT)
+ formatted_date_year = date_from.year
self._cr.execute(
- sql_query, (formatted_date_from, formatted_date_from, formatted_date_from, self.date_from, company.id))
+ sql_query, (formatted_date_year, formatted_date_from, formatted_date_from, formatted_date_from, self.date_from, company.id))
for row in self._cr.fetchall():
listrow = list(row)
diff --git a/addons/mrp/models/stock_move.py b/addons/mrp/models/stock_move.py
index 12e036bb2d5..21be5d5b4ba 100644
--- a/addons/mrp/models/stock_move.py
+++ b/addons/mrp/models/stock_move.py
@@ -161,7 +161,7 @@ class StockMove(models.Model):
def create_lots(self):
lots = self.env['stock.move.lots']
for move in self:
- unlink_move_lots = move.move_lot_ids.filtered(lambda x : (x.quantity_done == 0) and not x.workorder_id)
+ unlink_move_lots = move.move_lot_ids.filtered(lambda x : (x.quantity_done == 0) and x.done_wo)
unlink_move_lots.sudo().unlink()
group_new_quant = {}
old_move_lot = {}
diff --git a/addons/sale/models/sale.py b/addons/sale/models/sale.py
index 6d3199f4a18..8fece8eb81f 100644
--- a/addons/sale/models/sale.py
+++ b/addons/sale/models/sale.py
@@ -858,14 +858,11 @@ class SaleOrderLine(models.Model):
if self.order_id.pricelist_id.discount_policy == 'with_discount':
return product.with_context(pricelist=self.order_id.pricelist_id.id).price
final_price, rule_id = self.order_id.pricelist_id.get_product_price_rule(self.product_id, self.product_uom_qty or 1.0, self.order_id.partner_id)
- pricelist_item = self.env['product.pricelist.item'].browse(rule_id)
- if pricelist_item.base == 'pricelist':
- base_price, rule_id = pricelist_item.base_pricelist_id.get_product_price_rule(self.product_id, self.product_uom_qty or 1.0, self.order_id.partner_id)
- base_price = pricelist_item.base_pricelist_id.currency_id.compute(base_price, self.order_id.pricelist_id.currency_id)
- else:
- base_price = product[pricelist_item.base] if pricelist_item else product.lst_price
- base_price = product.currency_id.compute(base_price, self.order_id.pricelist_id.currency_id)
- # negative discounts (= surcharge) are included in the display price (= unit price)
+ context_partner = dict(self.env.context, partner_id=self.order_id.partner_id.id, date=self.order_id.date_order)
+ base_price, currency_id = self.with_context(context_partner)._get_real_price_currency(self.product_id, rule_id, self.product_uom_qty, self.product_uom, self.order_id.pricelist_id.id)
+ if currency_id != self.order_id.pricelist_id.currency_id.id:
+ base_price = self.env['res.currency'].browse(currency_id).with_context(context_partner).compute(base_price, self.order_id.pricelist_id.currency_id)
+ # negative discounts (= surcharge) are included in the display price
return max(base_price, final_price)
@api.multi
@@ -1008,11 +1005,10 @@ class SaleOrderLine(models.Model):
price, rule_id = self.order_id.pricelist_id.with_context(pricelist_context).get_product_price_rule(self.product_id, self.product_uom_qty or 1.0, self.order_id.partner_id)
new_list_price, currency_id = self.with_context(context_partner)._get_real_price_currency(self.product_id, rule_id, self.product_uom_qty, self.product_uom, self.order_id.pricelist_id.id)
- new_list_price = self.env['account.tax']._fix_tax_included_price_company(new_list_price, self.product_id.taxes_id, self.tax_id, self.company_id)
if new_list_price != 0:
- if self.product_id.company_id and self.order_id.pricelist_id.currency_id != self.product_id.company_id.currency_id:
- # new_list_price is in company's currency while price in pricelist currency
+ if self.order_id.pricelist_id.currency_id.id != currency_id:
+ # we need new_list_price in the same currency as price, which is in the SO's pricelist's currency
new_list_price = self.env['res.currency'].browse(currency_id).with_context(context_partner).compute(new_list_price, self.order_id.pricelist_id.currency_id)
discount = (new_list_price - price) / new_list_price * 100
if discount > 0:
diff --git a/addons/website/static/src/js/website.js b/addons/website/static/src/js/website.js
index 5ab4aca782c..3c063ba60dc 100644
--- a/addons/website/static/src/js/website.js
+++ b/addons/website/static/src/js/website.js
@@ -218,7 +218,7 @@ odoo.define('website.website', function (require) {
init_kanban(this);
});
- $('.js_website_submit_form').on('submit', function () {
+ $('body').on('submit', '.js_website_submit_form', function() {
var $buttons = $(this).find('button[type="submit"], a.a-submit');
_.each($buttons, function (btn) {
$(btn).attr('data-loading-text', '<i class="fa fa-spinner fa-spin"></i> ' + $(btn).text()).button('loading');
diff --git a/addons/website_event/static/src/js/website_event.js b/addons/website_event/static/src/js/website_event.js
index cb531d0035a..2038494a3e5 100644
--- a/addons/website_event/static/src/js/website_event.js
+++ b/addons/website_event/static/src/js/website_event.js
@@ -13,6 +13,7 @@ var EventRegistrationForm = Widget.extend({
.off('click')
.removeClass('a-submit')
.click(function (ev) {
+ $(this).attr('disabled', true);
self.on_click(ev);
});
});
@@ -28,7 +29,8 @@ var EventRegistrationForm = Widget.extend({
});
return ajax.jsonRpc($form.attr('action'), 'call', post).then(function (modal) {
var $modal = $(modal);
- $modal.appendTo($form).modal();
+ $modal.find('.modal-body > div').removeClass('container'); // retrocompatibility - REMOVE ME in master / saas-19
+ $modal.after($form).modal();
$modal.on('click', '.js_goto_event', function () {
$modal.modal('hide');
});
diff --git a/addons/website_event/views/website_event_templates.xml b/addons/website_event/views/website_event_templates.xml
index 2004ed074ea..80738d60c30 100644
--- a/addons/website_event/views/website_event_templates.xml
+++ b/addons/website_event/views/website_event_templates.xml
@@ -466,7 +466,7 @@
<template id="registration_attendee_details" name="Registration Attendee Details">
<div id="modal_attendees_registration" class="modal fade" tabindex="-1" role="dialog">
<div class="modal-dialog modal-lg">
- <form id="attendee_registration" t-attf-action="/event/#{slug(event)}/registration/confirm" method="post">
+ <form id="attendee_registration" t-attf-action="/event/#{slug(event)}/registration/confirm" method="post" class="js_website_submit_form">
<input type="hidden" name="csrf_token" t-att-value="request.csrf_token()"/>
<div class="modal-content">
<div class="modal-header">
@@ -474,7 +474,7 @@
<h4 class="modal-title" id="myModalLabel"><strong>Attendees</strong></h4>
</div>
<div class="modal-body">
- <div class="container">
+ <div class="">
<t t-set="counter_type" t-value="1"/>
<t t-set="counter" t-value="0"/>
<t t-foreach="tickets" t-as="ticket">
diff --git a/addons/website_event_questions/views/website_event_questions_templates.xml b/addons/website_event_questions/views/website_event_questions_templates.xml
index 6b47483fd44..b27abbfd259 100644
--- a/addons/website_event_questions/views/website_event_questions_templates.xml
+++ b/addons/website_event_questions/views/website_event_questions_templates.xml
@@ -30,7 +30,7 @@
</xpath>
<!-- Generic questions -->
- <xpath expr="//div[@class='container']/t[last()]" position="after">
+ <xpath expr="//div[hasclass('modal-body')]/div/t[last()]" position="after">
<t t-if="event.general_question_ids">
<h4 class="page-header mt8"><strong>Common Questions</strong></h4>
<div>
diff --git a/addons/website_mail_channel/controllers/main.py b/addons/website_mail_channel/controllers/main.py
index 4a9e2c449a8..3aa9491bf54 100644
--- a/addons/website_mail_channel/controllers/main.py
+++ b/addons/website_mail_channel/controllers/main.py
@@ -228,15 +228,19 @@ class MailGroup(http.Controller):
def confirm_unsubscribe(self, channel, partner_id, token, **kw):
subscriber = request.env['mail.channel.partner'].search([('channel_id', '=', channel.id), ('partner_id', '=', partner_id)])
if not subscriber:
+ partner = request.env['res.partner'].browse(partner_id).sudo().exists()
# FIXME: remove try/except in master
try:
- return request.render(
- 'website_mail_channel.not_subscribed', {
- 'partner_id': partner_id
- })
+ response = request.render(
+ 'website_mail_channel.not_subscribed',
+ {'partner_id': partner})
+ # make sure the rendering (and thus error if template is
+ # missing) happens inside the try block
+ response.flatten()
+ return response
except ValueError:
return _("The address %s is already unsubscribed or was never subscribed to any mailing list") % (
- partner_id.email
+ partner.email
)
subscriber_token = channel._generate_action_token(partner_id, action='unsubscribe')
diff --git a/addons/website_mail_channel/tests/__init__.py b/addons/website_mail_channel/tests/__init__.py
new file mode 100644
index 00000000000..2e3364d701d
--- /dev/null
+++ b/addons/website_mail_channel/tests/__init__.py
@@ -0,0 +1,2 @@
+# -*- coding: utf-8 -*-
+from . import test_unsubscribe
diff --git a/addons/website_mail_channel/tests/test_unsubscribe.py b/addons/website_mail_channel/tests/test_unsubscribe.py
new file mode 100644
index 00000000000..44128c30b86
--- /dev/null
+++ b/addons/website_mail_channel/tests/test_unsubscribe.py
@@ -0,0 +1,71 @@
+# -*- coding: utf-8 -*-
+import requests
+
+from odoo.api import Environment
+from odoo.tests import common
+from odoo.tools.misc import mute_logger
+
+
+class TestConfirmUnsubscribe(common.HttpCase):
+ def setUp(self):
+ super(TestConfirmUnsubscribe, self).setUp()
+
+ cr = self.registry.cursor()
+ # apparently HttpCase does not properly update self.env?
+ self.env2 = env = Environment(cr, self.uid, {})
+ self.partner = env['res.partner'].create({
+ 'name': 'Bob',
+ 'email': 'bob@bob.bob'
+ })
+ self.mailing_list = env['mail.channel'].create({
+ 'name': 'Test Mailing List',
+ 'public': 'public',
+ })
+ self.token = self.mailing_list._generate_action_token(self.partner.id, action='unsubscribe')
+
+ def test_not_subscribed(self):
+ """Test warning works"""
+ self.env2.cr.release()
+
+ self._unsubscribe_check("The address %s is already unsubscribed" % self.partner.email)
+
+ @mute_logger('odoo.addons.website.models.ir_ui_view')
+ def test_not_subscribed_no_template(self):
+ """ Test warning works on db without template (code update w/o module update) """
+ self.env2.ref('website_mail_channel.not_subscribed').unlink()
+ self.assertEquals(
+ self.env2['ir.model.data'].search_count([
+ ('module', '=', 'website_mail_channel'),
+ ('name', '=', 'not_subscribed'),
+ ]), 0, 'XID for template should have been deleted')
+ self.env2.cr.release()
+
+ self._unsubscribe_check("The address %s is already unsubscribed or was never subscribed to any mailing list" % self.partner.email)
+
+ def test_wrong_token(self):
+ self.mailing_list.sudo().write({
+ 'channel_partner_ids': [(4, self.partner.id, False)]
+ })
+ self.env2.cr.release()
+ self.token = 'XXX'
+
+ self._unsubscribe_check("Invalid or expired confirmation link.")
+
+ def test_successful_unsubscribe(self):
+ self.mailing_list.sudo().write({
+ 'channel_partner_ids': [(4, self.partner.id, False)]
+ })
+ self.env2.cr.release()
+
+ self._unsubscribe_check("You have been correctly unsubscribed")
+
+ def _unsubscribe_check(self, text):
+ url = "/groups/unsubscribe/{}/{}/{}".format(
+ self.mailing_list.id, self.partner.id,
+ self.token
+ )
+ # FIXME: may need to be altered during 11.0 forward port
+ r = self.url_open(url)
+ body = r.read().decode('utf-8')
+ # normalize space to make matching simpler
+ self.assertIn(text, u' '.join(body.split()))