summaryrefslogtreecommitdiff
path: root/addons
diff options
context:
space:
mode:
authorChristophe Simonis <chs@odoo.com>2017-10-02 13:05:17 +0200
committerChristophe Simonis <chs@odoo.com>2017-10-02 13:05:17 +0200
commit5ce21c7355b6f8f4c587f011417af3bcca7603a1 (patch)
treeacf66dcf1b1fd0e19b34e2d48bbd214a00b41abd /addons
parentabfac77a0644cad5eafe5a261b693ce4549bb0b5 (diff)
parentb3d0897f2d80352184874098d0f9fe2a6737d7a8 (diff)
[MERGE] forward port branch saas-16 up to b3d0897f2d8
Diffstat (limited to 'addons')
-rw-r--r--addons/account/static/src/js/reconciliation/reconciliation_model.js35
-rw-r--r--addons/calendar/models/calendar.py2
-rw-r--r--addons/calendar/tests/test_calendar.py44
-rw-r--r--addons/hr_payroll/models/hr_payslip.py8
-rw-r--r--addons/hr_payroll/models/hr_salary_rule.py4
-rw-r--r--addons/sale/views/sale_views.xml2
-rw-r--r--addons/web/static/tests/fields/relational_fields_tests.js47
-rw-r--r--addons/website_slides/models/slides.py3
8 files changed, 118 insertions, 27 deletions
diff --git a/addons/account/static/src/js/reconciliation/reconciliation_model.js b/addons/account/static/src/js/reconciliation/reconciliation_model.js
index a16594d69cb..b35802422e4 100644
--- a/addons/account/static/src/js/reconciliation/reconciliation_model.js
+++ b/addons/account/static/src/js/reconciliation/reconciliation_model.js
@@ -717,26 +717,27 @@ var StatementModel = BasicModel.extend({
args: args,
})
.then(function (result) {
- var tax = result.taxes[0];
- var tax_prop = self._formatQuickCreate(line, {
- 'link': prop.id,
- 'tax_id': tax.id,
- 'amount': tax.amount,
- 'label': tax.name,
- 'account_id': tax.account_id ? [tax.account_id, null] : prop.account_id,
- 'analytic': tax.analytic,
- 'is_tax': true,
- '__focus': false
- });
+ _.each(result.taxes, function(tax){
+ var tax_prop = self._formatQuickCreate(line, {
+ 'link': prop.id,
+ 'tax_id': tax.id,
+ 'amount': tax.amount,
+ 'label': tax.name,
+ 'account_id': tax.account_id ? [tax.account_id, null] : prop.account_id,
+ 'analytic': tax.analytic,
+ 'is_tax': true,
+ '__focus': false
+ });
- prop.amount = tax.base;
- prop.amount_str = field_utils.format.monetary(Math.abs(prop.amount), {}, formatOptions);
- prop.invalid = !self._isValid(prop);
+ prop.amount = tax.base;
+ prop.amount_str = field_utils.format.monetary(Math.abs(prop.amount), {}, formatOptions);
+ prop.invalid = !self._isValid(prop);
- tax_prop.amount_str = field_utils.format.monetary(Math.abs(tax_prop.amount), {}, formatOptions);
- tax_prop.invalid = prop.invalid;
+ tax_prop.amount_str = field_utils.format.monetary(Math.abs(tax_prop.amount), {}, formatOptions);
+ tax_prop.invalid = prop.invalid;
- reconciliation_proposition.push(tax_prop);
+ reconciliation_proposition.push(tax_prop);
+ });
}));
} else {
var currencyData = {
diff --git a/addons/calendar/models/calendar.py b/addons/calendar/models/calendar.py
index 6b061c6b79a..6de011b2915 100644
--- a/addons/calendar/models/calendar.py
+++ b/addons/calendar/models/calendar.py
@@ -1296,8 +1296,6 @@ class Meeting(models.Model):
meeting_origin = self.browse(real_id)
data = self.read(['allday', 'start', 'stop', 'rrule', 'duration'])[0]
- data['start_date' if data['allday'] else 'start_datetime'] = data['start']
- data['stop_date' if data['allday'] else 'stop_datetime'] = data['stop']
if data.get('rrule'):
data.update(
values,
diff --git a/addons/calendar/tests/test_calendar.py b/addons/calendar/tests/test_calendar.py
index 5d3ffcc5e23..7fabe934a94 100644
--- a/addons/calendar/tests/test_calendar.py
+++ b/addons/calendar/tests/test_calendar.py
@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
+import datetime
from datetime import datetime, timedelta
@@ -100,6 +101,49 @@ class TestCalendar(TransactionCase):
self.assertEqual(calendar_event_sprint_review.byday, '1', 'rrule_type should be mothly')
self.assertEqual(calendar_event_sprint_review.week_list, 'MO', 'rrule_type should be mothly')
+ def test_validation_error(self):
+ """
+ Ideally this should build the base event in such a way that calling
+ write() triggers detach_recurring_event, but I've no idea how that
+ actually works so just calling it directly for now
+ """
+ m = self.CalendarEvent.create({
+ 'name': "wheee",
+ 'start': '2017-07-12 14:30:00',
+ 'allday': False,
+ 'rrule': u'FREQ=WEEKLY;BYDAY=WE;INTERVAL=1;COUNT=100',
+ 'duration': 0.5,
+ 'stop': '2017-07-12 15:00:00',
+ })
+
+ values = {
+ 'allday': False,
+ 'name': u'wheee',
+ 'attendee_ids': [
+ (0, 0, {'state': u'needsAction', 'partner_id': 8, 'email': u'bob@example.com'}),
+ (0, 0, {'state': u'needsAction', 'partner_id': 10, 'email': u'ed@example.com'}),
+ ],
+ 'recurrency': True,
+ 'privacy': u'public',
+ 'stop': '2017-07-10 16:00:00',
+ 'alarm_ids': [(6, 0, [])],
+ 'start': '2017-07-10 15:30:00',
+ 'location': u"XXX",
+ 'duration': 0.5,
+ 'partner_ids': [(4, 10), (4, 8)],
+ 'description': u"A thing"
+ }
+
+ records = m.detach_recurring_event(values)
+ self.assertEqual(
+ (m.start_datetime, m.stop_datetime),
+ (u'2017-07-12 14:30:00', u'2017-07-12 15:00:00'),
+ )
+ self.assertEquals(
+ (records.start_datetime, records.stop_datetime),
+ (u'2017-07-10 15:30:00', u'2017-07-10 16:00:00'),
+ )
+
def test_event_order(self):
""" check the ordering of events when searching """
def create_event(name, date):
diff --git a/addons/hr_payroll/models/hr_payslip.py b/addons/hr_payroll/models/hr_payslip.py
index 562604a591d..3aaa01910ee 100644
--- a/addons/hr_payroll/models/hr_payslip.py
+++ b/addons/hr_payroll/models/hr_payslip.py
@@ -156,7 +156,7 @@ class HrPayslip(models.Model):
# if we don't give the contract, then the rules to apply should be for all current contracts of the employee
contract_ids = payslip.contract_id.ids or \
self.get_contract(payslip.employee_id, payslip.date_from, payslip.date_to)
- lines = [(0, 0, line) for line in self.get_payslip_lines(contract_ids, payslip.id)]
+ lines = [(0, 0, line) for line in self._get_payslip_lines(contract_ids, payslip.id)]
payslip.write({'line_ids': lines, 'number': number})
return True
@@ -226,7 +226,7 @@ class HrPayslip(models.Model):
return res
@api.model
- def get_payslip_lines(self, contract_ids, payslip_id):
+ def _get_payslip_lines(self, contract_ids, payslip_id):
def _sum_salary_rule_category(localdict, category, amount):
if category.parent_id:
localdict = _sum_salary_rule_category(localdict, category.parent_id, amount)
@@ -327,9 +327,9 @@ class HrPayslip(models.Model):
localdict['result_qty'] = 1.0
localdict['result_rate'] = 100
#check if the rule can be applied
- if rule.satisfy_condition(localdict) and rule.id not in blacklist:
+ if rule._satisfy_condition(localdict) and rule.id not in blacklist:
#compute the amount of the rule
- amount, qty, rate = rule.compute_rule(localdict)
+ amount, qty, rate = rule._compute_rule(localdict)
#check if there is already a rule computed with that code
previous_amount = rule.code in localdict and localdict[rule.code] or 0.0
#set/overwrite the amount computed for this rule in the localdict
diff --git a/addons/hr_payroll/models/hr_salary_rule.py b/addons/hr_payroll/models/hr_salary_rule.py
index cf1b01fa60c..5d6c49a0bf7 100644
--- a/addons/hr_payroll/models/hr_salary_rule.py
+++ b/addons/hr_payroll/models/hr_salary_rule.py
@@ -177,7 +177,7 @@ class HrSalaryRule(models.Model):
#TODO should add some checks on the type of result (should be float)
@api.multi
- def compute_rule(self, localdict):
+ def _compute_rule(self, localdict):
"""
:param localdict: dictionary containing the environement in which to compute the rule
:return: returns a tuple build as the base/amount computed, the quantity and the rate
@@ -204,7 +204,7 @@ class HrSalaryRule(models.Model):
raise UserError(_('Wrong python code defined for salary rule %s (%s).') % (self.name, self.code))
@api.multi
- def satisfy_condition(self, localdict):
+ def _satisfy_condition(self, localdict):
"""
@param contract_id: id of hr.contract to be tested
@return: returns True if the given rule match the condition for the given contract. Return False otherwise.
diff --git a/addons/sale/views/sale_views.xml b/addons/sale/views/sale_views.xml
index 09a4a37b1ce..32ef3464bae 100644
--- a/addons/sale/views/sale_views.xml
+++ b/addons/sale/views/sale_views.xml
@@ -185,7 +185,7 @@
<form string="Sales Order" class="o_sale_order">
<header>
<button name="action_quotation_send" string="Send by Email" type="object" states="draft" class="btn-primary"/>
- <button name="action_quotation_send" type="object" string="Send PRO-FORMA Invoice" groups="sale.group_proforma_sales" class="btn-primary" attrs="{'invisible': ['|', ('state', 'in', ['sent', 'sale']), ('invoice_count','&gt;=',1)]}" context="{'proforma': True}"/>
+ <button name="action_quotation_send" type="object" string="Send PRO-FORMA Invoice" groups="sale.group_proforma_sales" class="btn-primary" attrs="{'invisible': ['|', ('state', '!=', 'draft'), ('invoice_count','&gt;=',1)]}" context="{'proforma': True}"/>
<button name="print_quotation" string="Print" type="object" states="draft" class="btn-primary o_sale_print"/>
<button name="action_confirm" id="action_confirm"
string="Confirm Sale" class="btn-primary" type="object"
diff --git a/addons/web/static/tests/fields/relational_fields_tests.js b/addons/web/static/tests/fields/relational_fields_tests.js
index bb7dc5db00e..0c910e5b4de 100644
--- a/addons/web/static/tests/fields/relational_fields_tests.js
+++ b/addons/web/static/tests/fields/relational_fields_tests.js
@@ -6791,6 +6791,53 @@ QUnit.module('relational_fields', {
form.destroy();
});
+ QUnit.test('many2many checkboxes with default values', function (assert) {
+ assert.expect(7);
+
+ this.data.partner.fields.turtles.default = [3];
+ this.data.partner.fields.turtles.type = "many2many";
+
+ var form = createView({
+ View: FormView,
+ model: 'partner',
+ data: this.data,
+ arch:'<form string="Partners">' +
+ '<field name="turtles" widget="many2many_checkboxes">' +
+ '</field>' +
+ '</form>',
+ mockRPC: function (route, args) {
+ if (args.method === 'create') {
+ assert.deepEqual(args.args[0].turtles, [[6, false, [1]]],
+ "correct values should have been sent to create");
+ }
+ return this._super.apply(this, arguments);
+ }
+ });
+
+ assert.notOk(form.$('.o_checkbox input').eq(0).prop('checked'),
+ "first checkbox should not be checked");
+ assert.notOk(form.$('.o_checkbox input').eq(1).prop('checked'),
+ "second checkbox should not be checked");
+ assert.ok(form.$('.o_checkbox input').eq(2).prop('checked'),
+ "third checkbox should be checked");
+
+ form.$('.o_checkbox input:checked').click(); // Uncheck default record
+ form.$('.o_checkbox input').first().click(); // Check first record
+ form.$('.o_checkbox input').first().click(); // Uncheck first record
+ form.$('.o_checkbox input').first().click(); // Recheck first record
+
+ assert.ok(form.$('.o_checkbox input').eq(0).prop('checked'),
+ "first checkbox should be checked");
+ assert.notOk(form.$('.o_checkbox input').eq(1).prop('checked'),
+ "second checkbox should not be checked");
+ assert.notOk(form.$('.o_checkbox input').eq(2).prop('checked'),
+ "third checkbox should not be checked");
+
+ form.$buttons.find('.o_form_button_save').click();
+
+ form.destroy();
+ });
+
QUnit.test('many2many list with x2many: add a record', function (assert) {
assert.expect(18);
diff --git a/addons/website_slides/models/slides.py b/addons/website_slides/models/slides.py
index fbf48b596ad..b7632e96527 100644
--- a/addons/website_slides/models/slides.py
+++ b/addons/website_slides/models/slides.py
@@ -354,7 +354,7 @@ class Slide(models.Model):
record.embed_code = '<iframe src="//www.youtube.com/embed/%s?theme=light" allowFullScreen="true" frameborder="0"></iframe>' % (record.document_id)
else:
# embed google doc video
- record.embed_code = '<embed src="https://video.google.com/get_player?ps=docs&partnerid=30&docid=%s" type="application/x-shockwave-flash"></embed>' % (record.document_id)
+ record.embed_code = '<iframe src="//drive.google.com/file/d/%s/preview" allowFullScreen="true" frameborder="0"></iframe>' % (record.document_id)
else:
record.embed_code = False
@@ -557,6 +557,7 @@ class Slide(models.Model):
'name': snippet['title'],
'image': self._fetch_data(snippet['thumbnails']['high']['url'], {}, 'image')['values'],
'description': snippet['description'],
+ 'mime_type': False,
})
return {'values': values}