diff options
| author | Christophe Simonis <chs@odoo.com> | 2018-08-06 13:44:01 +0200 |
|---|---|---|
| committer | Christophe Simonis <chs@odoo.com> | 2018-08-06 13:44:01 +0200 |
| commit | 427f717d1885aacdeebaa0ba5d8638829dfb88ff (patch) | |
| tree | ab5a56cb306319a46011c532d6e8a7a4b74a7c04 /addons | |
| parent | fa618fcdd96885e8d1c95e4b00aa99840a58e140 (diff) | |
| parent | 932b22994169fe6d00b1be23656949a94ac46ef0 (diff) | |
[MERGE] forward port branch saas-11.2 up to 932b2299416
Diffstat (limited to 'addons')
| -rw-r--r-- | addons/account/models/account_payment.py | 15 | ||||
| -rw-r--r-- | addons/account_asset/models/account_asset.py | 4 | ||||
| -rw-r--r-- | addons/barcodes/README.rst | 2 | ||||
| -rw-r--r-- | addons/board/static/src/js/board_view.js | 2 | ||||
| -rw-r--r-- | addons/calendar/models/mail_activity.py | 2 | ||||
| -rw-r--r-- | addons/crm/models/crm_team.py | 24 | ||||
| -rw-r--r-- | addons/mass_mailing_event/models/__init__.py | 1 | ||||
| -rw-r--r-- | addons/mass_mailing_event/models/mass_mailing.py | 12 | ||||
| -rw-r--r-- | addons/product/views/product_views.xml | 10 | ||||
| -rw-r--r-- | addons/purchase/models/stock.py | 4 | ||||
| -rw-r--r-- | addons/sale_stock/tests/test_sale_stock.py | 4 | ||||
| -rw-r--r-- | addons/stock/models/procurement.py | 13 | ||||
| -rw-r--r-- | addons/stock/models/stock_move.py | 6 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/kanban/kanban_column_progressbar.js | 6 | ||||
| -rw-r--r-- | addons/web/static/src/js/views/pivot/pivot_model.js | 4 | ||||
| -rw-r--r-- | addons/website_sale_digital/controllers/main.py | 2 |
16 files changed, 80 insertions, 31 deletions
diff --git a/addons/account/models/account_payment.py b/addons/account/models/account_payment.py index ebfa4de4e5d..d782b91fee7 100644 --- a/addons/account/models/account_payment.py +++ b/addons/account/models/account_payment.py @@ -185,14 +185,15 @@ class account_abstract_payment(models.AbstractModel): :param currency: If not specified, search a default currency on wizard/journal. :return: The total amount to pay the invoices. ''' - # Get the payment currency - if not currency: - currency = self.currency_id or self.journal_id.currency_id or self.journal_id.company_id.currency_id # Get the payment invoices if not invoices: invoices = self.invoice_ids + # Get the payment currency + if not currency: + currency = self.currency_id or self.journal_id.currency_id or self.journal_id.company_id.currency_id or invoices and invoices[0].currency_id + # Avoid currency rounding issues by summing the amounts according to the company_currency_id before total = 0.0 groups = groupby(invoices, lambda i: i.currency_id) @@ -204,6 +205,14 @@ class account_abstract_payment(models.AbstractModel): total += payment_currency.with_context(date=self.payment_date).compute(amount_total, currency) 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 + class account_register_payments(models.TransientModel): _name = "account.register.payments" diff --git a/addons/account_asset/models/account_asset.py b/addons/account_asset/models/account_asset.py index 440185d475f..85c2c659119 100644 --- a/addons/account_asset/models/account_asset.py +++ b/addons/account_asset/models/account_asset.py @@ -351,7 +351,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): diff --git a/addons/barcodes/README.rst b/addons/barcodes/README.rst index 696ab62fbc5..62739b10fe4 100644 --- a/addons/barcodes/README.rst +++ b/addons/barcodes/README.rst @@ -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 diff --git a/addons/board/static/src/js/board_view.js b/addons/board/static/src/js/board_view.js index aa0613e9785..b2d57903a3d 100644 --- a/addons/board/static/src/js/board_view.js +++ b/addons/board/static/src/js/board_view.js @@ -248,7 +248,7 @@ var BoardRenderer = FormRenderer.extend({ } 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]; diff --git a/addons/calendar/models/mail_activity.py b/addons/calendar/models/mail_activity.py index 3efcea70a3b..0741658a087 100644 --- a/addons/calendar/models/mail_activity.py +++ b/addons/calendar/models/mail_activity.py @@ -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 diff --git a/addons/crm/models/crm_team.py b/addons/crm/models/crm_team.py index e7ed3a61e08..f24f253d230 100644 --- a/addons/crm/models/crm_team.py +++ b/addons/crm/models/crm_team.py @@ -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 diff --git a/addons/mass_mailing_event/models/__init__.py b/addons/mass_mailing_event/models/__init__.py index 80862024115..85b632eb8a3 100644 --- a/addons/mass_mailing_event/models/__init__.py +++ b/addons/mass_mailing_event/models/__init__.py @@ -2,3 +2,4 @@ # Part of Odoo. See LICENSE file for full copyright and licensing details. from . import event +from . import mass_mailing diff --git a/addons/mass_mailing_event/models/mass_mailing.py b/addons/mass_mailing_event/models/mass_mailing.py new file mode 100644 index 00000000000..a9849ad8deb --- /dev/null +++ b/addons/mass_mailing_event/models/mass_mailing.py @@ -0,0 +1,12 @@ +from odoo import models, api + + +class MassMailingCampaign(models.Model): + _inherit = "mail.mass_mailing" + + @api.onchange('mailing_model_id', 'contact_list_ids') + def _onchange_model_and_list(self): + result = super(MassMailingCampaign, self)._onchange_model_and_list() + if self.mailing_model_name == 'event.registration' and self.mailing_domain == '[]': + self.mailing_domain = self.env.context.get('default_mailing_domain', '[]') + return result diff --git a/addons/product/views/product_views.xml b/addons/product/views/product_views.xml index c6c498927bd..246bd1d282c 100644 --- a/addons/product/views/product_views.xml +++ b/addons/product/views/product_views.xml @@ -73,6 +73,11 @@ </div> </group> </group> + <group name="description_internal"> + <group string="Description for Internal" colspan="4"> + <field name="description" nolabel="1" placeholder="This note is only for internal purposes."/> + </group> + </group> </page> <page string="Sales" attrs="{'invisible':[('sale_ok','=',False)]}" name="sales"> <div name="pricelist_item" groups="product.group_product_pricelist"> @@ -109,11 +114,6 @@ <field name="packaging_ids" nolabel="1" context="{'default_product_id': product_variant_id,'tree_view_ref':'product.product_packaging_tree_view', 'form_view_ref':'product.product_packaging_form_view'}"/> </group> </page> - <group name="description_internal"> - <group string="Description for Internal"> - <field name="description" nolabel="1" placeholder="This note is only for internal purposes."/> - </group> - </group> </notebook> </sheet> <div class="oe_chatter"> diff --git a/addons/purchase/models/stock.py b/addons/purchase/models/stock.py index f1f98cdaa71..69b85c7b899 100644 --- a/addons/purchase/models/stock.py +++ b/addons/purchase/models/stock.py @@ -77,6 +77,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() diff --git a/addons/sale_stock/tests/test_sale_stock.py b/addons/sale_stock/tests/test_sale_stock.py index 399a6be021c..23cff0c7f8e 100644 --- a/addons/sale_stock/tests/test_sale_stock.py +++ b/addons/sale_stock/tests/test_sale_stock.py @@ -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): diff --git a/addons/stock/models/procurement.py b/addons/stock/models/procurement.py index fd08b362949..64929fa0084 100644 --- a/addons/stock/models/procurement.py +++ b/addons/stock/models/procurement.py @@ -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]) diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index 48295f8b35e..88aede3ecf3 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -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 diff --git a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js index b597ccf1c60..7e1f16c9fb0 100644 --- a/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js +++ b/addons/web/static/src/js/views/kanban/kanban_column_progressbar.js @@ -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; diff --git a/addons/web/static/src/js/views/pivot/pivot_model.js b/addons/web/static/src/js/views/pivot/pivot_model.js index b45f7a9ffdf..54f469bbc19 100644 --- a/addons/web/static/src/js/views/pivot/pivot_model.js +++ b/addons/web/static/src/js/views/pivot/pivot_model.js @@ -541,7 +541,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 measures = _.map(this.data.measures, function(measure) { if (self.fields[measure].type === 'many2one') { @@ -624,7 +624,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; diff --git a/addons/website_sale_digital/controllers/main.py b/addons/website_sale_digital/controllers/main.py index c53f27d7336..39d0492260a 100644 --- a/addons/website_sale_digital/controllers/main.py +++ b/addons/website_sale_digital/controllers/main.py @@ -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', ) |
