[MERGE] forward port branch 11.0 up to b29e053436

This commit is contained in:
Christophe Simonis
2018-08-06 11:46:10 +02:00
15 changed files with 81 additions and 26 deletions
+10 -2
View File
@@ -114,18 +114,26 @@ class account_register_payments(models.TransientModel):
@api.model
def _compute_payment_amount(self, invoice_ids):
payment_currency = self.currency_id or self.journal_id.currency_id or self.journal_id.company_id.currency_id
payment_currency = self.currency_id or self.journal_id.currency_id or self.journal_id.company_id.currency_id or invoice_ids and invoice_ids[0].currency_id
total = 0
for inv in invoice_ids:
if inv.currency_id == payment_currency:
total += MAP_INVOICE_TYPE_PAYMENT_SIGN[inv.type] * inv.residual_company_signed
total += MAP_INVOICE_TYPE_PAYMENT_SIGN[inv.type] * inv.residual_signed
else:
amount_residual = inv.company_currency_id.with_context(date=self.payment_date).compute(
inv.residual_company_signed, payment_currency)
total += MAP_INVOICE_TYPE_PAYMENT_SIGN[inv.type] * amount_residual
return total
@api.onchange('journal_id')
def _onchange_journal(self):
res = super(account_register_payments, self)._onchange_journal()
active_ids = self._context.get('active_ids')
invoices = self.env['account.invoice'].browse(active_ids)
self.amount = abs(self._compute_payment_amount(invoices))
return res
@api.model
def default_get(self, fields):
rec = super(account_register_payments, self).default_get(fields)
+3 -1
View File
@@ -340,7 +340,9 @@ class AccountAssetAsset(models.Model):
def set_to_close(self):
move_ids = self._get_disposal_moves()
if move_ids:
self._return_disposal_view(move_ids)
return self._return_disposal_view(move_ids)
# Fallback, as if we just clicked on the smartbutton
return self.open_entries()
@api.multi
def set_to_draft(self):
+1 -1
View File
@@ -106,7 +106,7 @@ The purpose of this component is to listen to keypresses to detect barcodes, the
on core.bus inside a 'barcode_event'.
All keypress events are buffered until there is no more keypress during 50ms or a carriage return / tab is
inputted (because most barcode scanners use this as a suffix).
If the buffered keys looks like a barcode (match the the regexp /.{3,}[\n\r\t]*), an event is triggered :
If the buffered keys looks like a barcode, an event is triggered :
core.bus.trigger('barcode_scanned', barcode);
Otherwise, the keypresses are 'resent'. However, for security reasons, a keypress event programmatically
crafted doesn't trigger native browser behaviors. For this reason, BarcodeEvents doesn't intercept keypresses
+1 -1
View File
@@ -255,7 +255,7 @@ FormRenderer.include({
}
var view = _.find(action.views, function (descr) {
return descr[1] === params.viewType;
});
}) || [false, params.viewType];
return self.loadViews(action.res_model, context, [view])
.then(function (viewsInfo) {
var viewInfo = viewsInfo[params.viewType];
+1 -1
View File
@@ -24,7 +24,7 @@ class MailActivity(models.Model):
'default_res_id': self.env.context.get('default_res_id'),
'default_res_model': self.env.context.get('default_res_model'),
'default_name': self.summary,
'default_description': self.note and tools.html2plaintext(self.note) or '',
'default_description': self.note and tools.html2plaintext(self.note).strip() or '',
'default_activity_ids': [(6, 0, self.ids)],
}
return action
+16 -8
View File
@@ -149,14 +149,22 @@ class Team(models.Model):
tree_view_id = self.env.ref('crm.crm_case_tree_view_oppor').id
form_view_id = self.env.ref('crm.crm_case_form_view_oppor').id
kanb_view_id = self.env.ref('crm.crm_case_kanban_view_leads').id
action['views'] = [
[kanb_view_id, 'kanban'],
[tree_view_id, 'tree'],
[form_view_id, 'form'],
[False, 'graph'],
[False, 'calendar'],
[False, 'pivot']
]
mode_string = action.get('view_mode', '')
view_mode = mode_string.split(',') if mode_string else ['kanban', 'tree', 'form', 'graph', 'calendar', 'pivot']
dict_views = {
'kanban': kanb_view_id,
'tree': tree_view_id,
'form': form_view_id,
'graph': False,
'calendar': False,
'pivot': False,
}
# Sort the views according to the view mode of the action
# which can be modified via studio, or technical menu for that matter
action['views'] = [[dict_views.get(view_type, False), view_type] for view_type in view_mode]
action['context'] = action_context
return action
+4
View File
@@ -60,6 +60,10 @@ class StockMove(models.Model):
vals['purchase_line_id'] = self.purchase_line_id.id
return vals
def _clean_merged(self):
super(StockMove, self)._clean_merged()
self.write({'created_purchase_line_id': False})
def _action_done(self):
res = super(StockMove, self)._action_done()
self.mapped('purchase_line_id').sudo()._update_received_qty()
+2 -2
View File
@@ -178,14 +178,14 @@ class TestSaleStock(TestSale):
# Check invoice
self.assertEqual(self.so.invoice_status, 'to invoice', 'Sale Stock: so invoice_status should be "to invoice" instead of "%s" after picking return' % self.so.invoice_status)
self.assertAlmostEqual(self.so.order_line[0].qty_delivered, 3.0, 'Sale Stock: delivered quantity should be 3.0 instead of "%s" after picking return' % self.so.order_line[0].qty_delivered)
self.assertAlmostEqual(self.so.order_line[0].qty_delivered, 3.0, msg='Sale Stock: delivered quantity should be 3.0 instead of "%s" after picking return' % self.so.order_line[0].qty_delivered)
# let's do an invoice with refunds
adv_wiz = self.env['sale.advance.payment.inv'].with_context(active_ids=[self.so.id]).create({
'advance_payment_method': 'all',
})
adv_wiz.with_context(open_invoices=True).create_invoices()
self.inv_2 = self.so.invoice_ids.filtered(lambda r: r.state == 'draft')
self.assertAlmostEqual(self.inv_2.invoice_line_ids[0].quantity, 2.0, 'Sale Stock: refund quantity on the invoice should be 2.0 instead of "%s".' % self.inv_2.invoice_line_ids[0].quantity)
self.assertAlmostEqual(self.inv_2.invoice_line_ids[0].quantity, 2.0, msg='Sale Stock: refund quantity on the invoice should be 2.0 instead of "%s".' % self.inv_2.invoice_line_ids[0].quantity)
self.assertEqual(self.so.invoice_status, 'no', 'Sale Stock: so invoice_status should be "no" instead of "%s" after invoicing the return' % self.so.invoice_status)
def test_03_sale_stock_delivery_partial(self):
+11 -2
View File
@@ -1,7 +1,7 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from collections import defaultdict
from collections import OrderedDict
from datetime import datetime
from dateutil.relativedelta import relativedelta
from odoo.tools.misc import split_every
@@ -318,9 +318,18 @@ class ProcurementGroup(models.Model):
orderpoints_noprefetch = orderpoints_noprefetch[1000:]
# Calculate groups that can be executed together
location_data = defaultdict(lambda: dict(products=self.env['product.product'], orderpoints=self.env['stock.warehouse.orderpoint'], groups=list()))
location_data = OrderedDict()
def makedefault():
return {
'products': self.env['product.product'],
'orderpoints': self.env['stock.warehouse.orderpoint'],
'groups': []
}
for orderpoint in orderpoints:
key = self._procurement_from_orderpoint_get_grouping_key([orderpoint.id])
location_data[key] = makedefault()
location_data[key]['products'] += orderpoint.product_id
location_data[key]['orderpoints'] += orderpoint
location_data[key]['groups'] = self._procurement_from_orderpoint_get_groups([orderpoint.id])
+5 -1
View File
@@ -561,6 +561,10 @@ class StockMove(models.Model):
move.product_uom.id, move.restrict_partner_id.id, move.scrapped, move.origin_returned_move_id.id
]
def _clean_merged(self):
"""Cleanup hook used when merging moves"""
self.write({'propagate': False})
def _merge_moves(self, merge_into=False):
""" This method will, for each move in `self`, go up in their linked picking and try to
find in their existing moves a candidate into which we can merge the move.
@@ -598,7 +602,7 @@ class StockMove(models.Model):
if moves_to_unlink:
# We are using propagate to False in order to not cancel destination moves merged in moves[0]
moves_to_unlink.write({'propagate': False})
moves_to_unlink._clean_merged()
moves_to_unlink._action_cancel()
moves_to_unlink.sudo().unlink()
return (self | self.env['stock.move'].concat(*moves_to_merge)) - moves_to_unlink
@@ -142,6 +142,7 @@ var KanbanColumnProgressBar = Widget.extend({
// Display and animate the progress bars
var barNumber = 0;
var barMinWidth = 6; // In %
_.each(self.colors, function (val, key) {
var $bar = self.$bars[val];
var count = self.subgroupCounts && self.subgroupCounts[key] || 0;
@@ -168,16 +169,15 @@ var KanbanColumnProgressBar = Widget.extend({
$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;
var maxWidth = 100 - barMinWidth * barNumber;
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', '');
}
});
this.$('.progress-bar.o_bar_has_records').css('min-width', barMinWidth + '%');
// Display and animate the counter number
var start = this.prevTotalCounterValue;
@@ -524,7 +524,7 @@ var PivotModel = AbstractModel.extend({
_loadData: function () {
var self = this;
var groupBys = [];
var rowGroupBys = this.data.groupedBy.length ? this.data.groupedBy : this.initialRowGroupBys;
var rowGroupBys = !_.isEmpty(this.data.groupedBy) ? this.data.groupedBy : this.initialRowGroupBys;
var colGroupBys = this.data.colGroupBys;
var fields = [].concat(rowGroupBys, colGroupBys, this.data.measures);
@@ -600,7 +600,7 @@ var PivotModel = AbstractModel.extend({
});
var index = 0;
var rowGroupBys = this.data.groupedBy.length ? this.data.groupedBy : this.initialRowGroupBys;
var rowGroupBys = !_.isEmpty(this.data.groupedBy) ? this.data.groupedBy : this.initialRowGroupBys;
var colGroupBys = this.data.colGroupBys;
var datapt, row, col, attrs, cell_value;
var main_row_header, main_col_header;
@@ -44,7 +44,7 @@ class WebsiteSaleDigital(CustomerPortal):
product_id = product.id
template = product.product_tmpl_id
att = Attachment.search_read(
domain=['|', '&', ('res_model', '=', product._name), ('res_id', '=', product_id), '&', ('res_model', '=', template._name), '&', ('res_id', '=', template.id), ('product_downloadable', '=', True)],
domain=['|', '&', ('res_model', '=', product._name), ('res_id', '=', product_id), '&', ('res_model', '=', template._name), ('res_id', '=', template.id), ('product_downloadable', '=', True)],
fields=['name', 'write_date'],
order='write_date desc',
)
@@ -0,0 +1,17 @@
Switzerland, 2018-07-31
International Business Hub agrees to the terms of the Odoo Corporate Contributor License
Agreement v1.0.
I declare that I am authorized and able to make this agreement and sign this
declaration.
Signed,
Sandro Pignataro pignatarosandro@gmail.com https://github.com/Pigna74
List of contributors:
Guido Notari guido.notari@gmail.com https://github.com/gnotari
Matteo Bilotta byloth@gmail.com https://github.com/Byloth
+4 -1
View File
@@ -71,7 +71,10 @@ def _initialize_db(id, db_name, demo, lang, user_password, login='admin', countr
if country_code:
countries = env['res.country'].search([('code', 'ilike', country_code)])
if countries:
env['res.company'].browse(1).country_id = countries[0]
comp_local = {'country_id': countries[0].id}
if countries[0].currency_id:
comp_local['currency_id'] = countries[0].currency_id.id
env['res.company'].browse(1).write(comp_local)
# update admin's password and lang and login
values = {'password': user_password, 'lang': lang}