[MERGE] forward port branch 11.0 up to 169f899e29
This commit is contained in:
@@ -510,6 +510,7 @@ class account_payment(models.Model):
|
||||
(transfer_credit_aml + transfer_debit_aml).reconcile()
|
||||
|
||||
rec.write({'state': 'posted', 'move_name': move.name})
|
||||
return True
|
||||
|
||||
@api.multi
|
||||
def action_draft(self):
|
||||
@@ -524,7 +525,7 @@ class account_payment(models.Model):
|
||||
if any(len(record.invoice_ids) != 1 for record in self):
|
||||
# For multiple invoices, there is account.register.payments wizard
|
||||
raise UserError(_("This method should only be called to process a single invoice's payment."))
|
||||
self.post();
|
||||
return self.post()
|
||||
|
||||
def _create_payment_entry(self, amount):
|
||||
""" Create a journal entry corresponding to a payment, if the payment references invoice(s) they are reconciled.
|
||||
|
||||
@@ -61,7 +61,7 @@
|
||||
<div class="o_setting_right_pane">
|
||||
<label for="module_crm_phone_validation"/>
|
||||
<div class="text-muted" id="module_crm_phone_validation">
|
||||
Validate and normalize phone numbers.
|
||||
Formats phone numbers
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -13,7 +13,6 @@ CRM Phone Numbers Validation
|
||||
This module allows for validate and format phone numbers for leads and contacts.""",
|
||||
'data': [
|
||||
'views/res_config_settings_views.xml',
|
||||
'views/crm_lead_views.xml'
|
||||
],
|
||||
'depends': [
|
||||
'phone_validation',
|
||||
|
||||
@@ -1,13 +0,0 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="crm_lead_opportunity_view_form" model="ir.ui.view">
|
||||
<field name="name">crm.lead.form.opportunity.inherit.crm.phone.validation</field>
|
||||
<field name="model">crm.lead</field>
|
||||
<field name="inherit_id" ref="crm.crm_case_form_view_oppor" />
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//group[@name='Misc']" position="inside">
|
||||
<field name="company_id" invisible="1"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -135,7 +135,7 @@
|
||||
<th>Net Imposable</th>
|
||||
<th>Plafond s.s.</th>
|
||||
<th></th>
|
||||
<th>Coût Global Salarié</th>
|
||||
<th>Total versé par l'employeur</th>
|
||||
</tr>
|
||||
</thead>
|
||||
<tbody>
|
||||
|
||||
@@ -9,11 +9,12 @@ class PhoneValidationMixin(models.AbstractModel):
|
||||
_name = 'phone.validation.mixin'
|
||||
|
||||
def _phone_get_country(self):
|
||||
if 'country_id' in self:
|
||||
if 'country_id' in self and self.country_id:
|
||||
return self.country_id
|
||||
return self.env.user.company_id.country_id
|
||||
|
||||
def _phone_get_always_international(self):
|
||||
if 'company_id' in self and self.country_id:
|
||||
if 'company_id' in self and self.company_id:
|
||||
return self.company_id.phone_international_format == 'prefix'
|
||||
return self.env.user.company_id.phone_international_format == 'prefix'
|
||||
|
||||
|
||||
@@ -227,6 +227,12 @@ class PosOrder(models.Model):
|
||||
return InvoiceLine.sudo().create(inv_line)
|
||||
|
||||
def _create_account_move_line(self, session=None, move=None):
|
||||
def _flatten_tax_and_children(taxes):
|
||||
children = self.env['account.tax']
|
||||
for tax in taxes:
|
||||
children |= _flatten_tax_and_children(tax.children_tax_ids)
|
||||
return taxes + children
|
||||
|
||||
# Tricky, via the workflow, we only have one id in the ids variable
|
||||
"""Create a account move line of order grouped by products or not."""
|
||||
IrProperty = self.env['ir.property']
|
||||
@@ -303,6 +309,9 @@ class PosOrder(models.Model):
|
||||
name = name + ' (' + line.notice + ')'
|
||||
|
||||
# Create a move for the line for the order line
|
||||
# Just like for invoices, a group of taxes must be present on this base line
|
||||
# As well as its children
|
||||
base_line_tax_ids = _flatten_tax_and_children(line.tax_ids_after_fiscal_position).filtered(lambda tax: tax.type_tax_use in ['sale', 'none'])
|
||||
insert_data('product', {
|
||||
'name': name,
|
||||
'quantity': line.qty,
|
||||
@@ -311,7 +320,7 @@ class PosOrder(models.Model):
|
||||
'analytic_account_id': self._prepare_analytic_account(line),
|
||||
'credit': ((amount > 0) and amount) or 0.0,
|
||||
'debit': ((amount < 0) and -amount) or 0.0,
|
||||
'tax_ids': [(6, 0, line.tax_ids_after_fiscal_position.ids)],
|
||||
'tax_ids': [(6, 0, base_line_tax_ids.ids)],
|
||||
'partner_id': partner_id
|
||||
})
|
||||
|
||||
|
||||
@@ -1646,19 +1646,15 @@ class TestSinglePicking(TestStockCommon):
|
||||
|
||||
class TestStockUOM(TestStockCommon):
|
||||
def setUp(self):
|
||||
with registry().cursor() as cr:
|
||||
env = api.Environment(cr, 1, {})
|
||||
dp = env.ref('product.decimal_product_uom')
|
||||
self.old_digits = dp.digits
|
||||
dp.digits = 7
|
||||
super(TestStockUOM, self).setUp()
|
||||
dp = self.env.ref('product.decimal_product_uom')
|
||||
dp.digits = 7
|
||||
|
||||
def tearDown(self):
|
||||
super(TestStockUOM, self).tearDown()
|
||||
with self.registry.cursor() as cr:
|
||||
env = api.Environment(cr, 1, {})
|
||||
dp = env.ref('product.decimal_product_uom')
|
||||
dp.digits = self.old_digits
|
||||
# Trick: invoke the method 'precision_get' with the current environment.
|
||||
# This fills in the cache of the method with the right value. If we
|
||||
# don't do that, the registry will access the corresponding precision
|
||||
# with a new cursor (LazyCursor), and get a different value!
|
||||
self.assertEqual(dp.precision_get(dp.name), 7)
|
||||
|
||||
def test_pickings_transfer_with_different_uom_and_back_orders(self):
|
||||
""" Picking transfer with diffrent unit of meassure. """
|
||||
|
||||
@@ -30,6 +30,7 @@ var BasicRenderer = AbstractRenderer.extend({
|
||||
this.activeActions = params.activeActions;
|
||||
this.viewType = params.viewType;
|
||||
this.mode = params.mode || 'readonly';
|
||||
this.widgets = [];
|
||||
},
|
||||
/**
|
||||
* This method has two responsabilities: find every invalid fields in the
|
||||
@@ -95,6 +96,9 @@ var BasicRenderer = AbstractRenderer.extend({
|
||||
return this._render().then(_.constant([]));
|
||||
}
|
||||
|
||||
// reset all widgets (from the <widget> tag) if any:
|
||||
_.invoke(this.widgets, 'updateState', state);
|
||||
|
||||
var defs = [];
|
||||
|
||||
// Reset all the field widgets that are marked as changed and the ones
|
||||
@@ -613,6 +617,8 @@ var BasicRenderer = AbstractRenderer.extend({
|
||||
var Widget = widgetRegistry.get(node.attrs.name);
|
||||
var widget = new Widget(this, record);
|
||||
|
||||
this.widgets.push(widget);
|
||||
|
||||
// Prepare widget rendering and save the related deferred
|
||||
var def = widget._widgetRenderAndInsert(function () {});
|
||||
if (def.state() === 'pending') {
|
||||
|
||||
@@ -71,6 +71,7 @@ var ListRenderer = BasicRenderer.extend({
|
||||
*/
|
||||
updateState: function (state, params) {
|
||||
this._processColumns(params.columnInvisibleFields || {});
|
||||
this.selection = [];
|
||||
return this._super.apply(this, arguments);
|
||||
},
|
||||
|
||||
@@ -202,9 +203,11 @@ var ListRenderer = BasicRenderer.extend({
|
||||
var field = self.state.fields[column.attrs.name];
|
||||
var value = aggregateValues[column.attrs.name].value;
|
||||
var help = aggregateValues[column.attrs.name].help;
|
||||
var formattedValue = field_utils.format[field.type](value, field, {
|
||||
escape: true,
|
||||
});
|
||||
var formatFunc = field_utils.format[column.attrs.widget];
|
||||
if (!formatFunc) {
|
||||
formatFunc = field_utils.format[field.type];
|
||||
}
|
||||
var formattedValue = formatFunc(value, field, {escape: true});
|
||||
$cell.addClass('o_list_number').attr('title', help).html(formattedValue);
|
||||
}
|
||||
return $cell;
|
||||
|
||||
@@ -6232,6 +6232,41 @@ QUnit.module('Views', {
|
||||
delete widgetRegistry.map.test;
|
||||
});
|
||||
|
||||
QUnit.test('basic support for widgets', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var MyWidget = Widget.extend({
|
||||
init: function (parent, dataPoint) {
|
||||
this.data = dataPoint.data;
|
||||
},
|
||||
start: function () {
|
||||
this.$el.text(this.data.foo + "!");
|
||||
},
|
||||
updateState: function (dataPoint) {
|
||||
this.$el.text(dataPoint.data.foo + "!");
|
||||
},
|
||||
});
|
||||
widgetRegistry.add('test', MyWidget);
|
||||
|
||||
var form = createView({
|
||||
View: FormView,
|
||||
model: 'partner',
|
||||
data: this.data,
|
||||
arch: '<form string="Partners">' +
|
||||
'<field name="foo"/>' +
|
||||
'<widget name="test"/>' +
|
||||
'</form>',
|
||||
});
|
||||
|
||||
form.$('input[name="foo"]').val("I am alive").trigger('input');
|
||||
assert.strictEqual(form.$('.o_widget').text(), 'I am alive!',
|
||||
"widget should have been updated");
|
||||
|
||||
form.destroy();
|
||||
delete widgetRegistry.map.test;
|
||||
});
|
||||
|
||||
|
||||
QUnit.test('bounce edit button in readonly mode', function (assert) {
|
||||
assert.expect(3);
|
||||
|
||||
|
||||
@@ -582,6 +582,40 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('selection is reset on reload', function (assert) {
|
||||
assert.expect(5);
|
||||
|
||||
var list = createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: '<tree>' +
|
||||
'<field name="foo"/>' +
|
||||
'<field name="int_field" sum="Sum"/>' +
|
||||
'</tree>',
|
||||
});
|
||||
|
||||
assert.strictEqual(list.$('tfoot td:nth(2)').text(), '32',
|
||||
"total should be 32 (no record selected)");
|
||||
|
||||
// select first record
|
||||
var $firstRowSelector = list.$('tbody .o_list_record_selector input').first();
|
||||
$firstRowSelector.click();
|
||||
assert.ok($firstRowSelector.is(':checked'), "first row should be selected");
|
||||
assert.strictEqual(list.$('tfoot td:nth(2)').text(), '10',
|
||||
"total should be 10 (first record selected)");
|
||||
|
||||
// reload
|
||||
list.reload();
|
||||
$firstRowSelector = list.$('tbody .o_list_record_selector input').first();
|
||||
assert.notOk($firstRowSelector.is(':checked'),
|
||||
"first row should no longer be selected");
|
||||
assert.strictEqual(list.$('tfoot td:nth(2)').text(), '32',
|
||||
"total should be 32 (no more record selected)");
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('aggregates are computed correctly', function (assert) {
|
||||
assert.expect(4);
|
||||
|
||||
@@ -660,6 +694,25 @@ QUnit.module('Views', {
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('aggregates are formatted according to field widget', function (assert) {
|
||||
assert.expect(1);
|
||||
|
||||
var list = createView({
|
||||
View: ListView,
|
||||
model: 'foo',
|
||||
data: this.data,
|
||||
arch: '<tree>' +
|
||||
'<field name="foo"/>' +
|
||||
'<field name="qux" widget="float_time" sum="Sum"/>' +
|
||||
'</tree>',
|
||||
});
|
||||
|
||||
assert.strictEqual(list.$('tfoot td:nth(2)').text(), '19:24',
|
||||
"total should be formatted as a float_time");
|
||||
|
||||
list.destroy();
|
||||
});
|
||||
|
||||
QUnit.test('groups can be sorted on aggregates', function (assert) {
|
||||
assert.expect(10);
|
||||
|
||||
|
||||
@@ -742,7 +742,7 @@ var ViewEditor = Widget.extend({
|
||||
|
||||
var text = data.text || '';
|
||||
if (!isSelected) {
|
||||
text = Array($elem.data('level') + 1).join('-') + ' ' + text;
|
||||
text = Array(($elem.data('level') || 0) + 1).join('-') + ' ' + text;
|
||||
}
|
||||
var $div = $('<div/>', {
|
||||
text: text,
|
||||
|
||||
@@ -4,8 +4,6 @@
|
||||
from odoo.addons.website_form.controllers.main import WebsiteForm
|
||||
from odoo.http import request, route
|
||||
|
||||
import json
|
||||
|
||||
|
||||
class WebsiteForm(WebsiteForm):
|
||||
|
||||
@@ -32,17 +30,13 @@ class WebsiteForm(WebsiteForm):
|
||||
else:
|
||||
record = data.get('record', {})
|
||||
phone_fields = self._get_phone_fields_to_validate()
|
||||
country = self._get_country()
|
||||
invalid_fields = {}
|
||||
country = request.env['res.country'].browse(record.get('country_id'))
|
||||
contact_country = country.exists() and country or self._get_country()
|
||||
for phone_field in phone_fields:
|
||||
if not record.get(phone_field):
|
||||
continue
|
||||
number = record[phone_field]
|
||||
try:
|
||||
request.env[model_name].phone_format(number, country)
|
||||
except Exception as error:
|
||||
invalid_fields[phone_field] = error.args[0]
|
||||
if invalid_fields:
|
||||
return json.dumps({'error_fields': invalid_fields})
|
||||
fmt_number = request.env[model_name].phone_format(number, contact_country)
|
||||
request.params.update({phone_field: fmt_number})
|
||||
|
||||
return super(WebsiteForm, self).website_form(model_name, **kwargs)
|
||||
|
||||
Reference in New Issue
Block a user