From 70e43b18e0c114bc4649a2c0761a5063602cd056 Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Wed, 6 Jan 2016 15:53:16 +0100 Subject: [PATCH 1/8] [FIX] point_of_sale: use tax_ids on the pos orderline, not the product We have taxes on pos.order.line and we have taxes on the product of the `pos.order.line`. There was no real consensus in the POS about which taxes to use. As long as they're the same it doesn't cause issues, but if someone where to change the taxes on a product which is used in an open `pos.session` things will start going wrong. When closing the pos.session amount_total of the `pos.order` in question will not equal tax `account.move.lines` + product `account.move.lines`. The reason for it is that we use the taxes on the `pos.order.line` for the tax account.move.lines, whereas amount_total used the taxes on product. This fixes the problem by always using the tax set on `pos.order.line`. This tax should be set only once through `_order_line_fields` during orderline creation. After that it shouldn't change. Therefore `pos.sessions` won't be affected by changes to taxes of products anymore. opw-660765 --- addons/point_of_sale/point_of_sale.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/addons/point_of_sale/point_of_sale.py b/addons/point_of_sale/point_of_sale.py index 5821fe1b140..f092e9a87bd 100644 --- a/addons/point_of_sale/point_of_sale.py +++ b/addons/point_of_sale/point_of_sale.py @@ -648,7 +648,7 @@ class pos_order(osv.osv): _order = "id desc" def _amount_line_tax(self, cr, uid, line, fiscal_position_id, context=None): - taxes = line.product_id.taxes_id.filtered(lambda t: t.company_id.id == line.order_id.company_id.id) + taxes = line.tax_ids.filtered(lambda t: t.company_id.id == line.order_id.company_id.id) if fiscal_position_id: taxes = fiscal_position_id.map_tax(taxes) price = line.price_unit * (1 - (line.discount or 0.0) / 100.0) @@ -1402,7 +1402,7 @@ class pos_order_line(osv.osv): account_tax_obj = self.pool.get('account.tax') for line in self.browse(cr, uid, ids, context=context): cur = line.order_id.pricelist_id.currency_id - taxes = [ tax for tax in line.product_id.taxes_id if tax.company_id.id == line.order_id.company_id.id ] + taxes = [ tax for tax in line.tax_ids if tax.company_id.id == line.order_id.company_id.id ] fiscal_position_id = line.order_id.fiscal_position_id if fiscal_position_id: taxes = fiscal_position_id.map_tax(taxes) From 17bb5fd374b32e7ef98d042f6042d925bcfc3feb Mon Sep 17 00:00:00 2001 From: Joren Van Onder Date: Wed, 6 Jan 2016 16:55:59 +0100 Subject: [PATCH 2/8] [FIX] point_of_sale: fix forward port related issues Fix 697739d, 682e660, da9275a and 697739d which where forward-ported in 8b4f052a3872b397bbe252e353b1d18d273ec8ff. --- addons/point_of_sale/static/src/js/gui.js | 5 +++-- addons/point_of_sale/static/src/js/popups.js | 2 +- addons/point_of_sale/static/src/js/screens.js | 2 +- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/addons/point_of_sale/static/src/js/gui.js b/addons/point_of_sale/static/src/js/gui.js index 1885d2ef13e..5e8c8bf71d1 100644 --- a/addons/point_of_sale/static/src/js/gui.js +++ b/addons/point_of_sale/static/src/js/gui.js @@ -8,6 +8,7 @@ odoo.define('point_of_sale.gui', function (require) { var core = require('web.core'); var Model = require('web.DataModel'); +var formats = require('web.formats'); var _t = core._t; @@ -411,8 +412,8 @@ var Gui = core.Class.extend({ numpad_input: function(buffer, input, options) { var newbuf = buffer.slice(0); options = options || {}; - var newbuf_float = instance.web.parse_value(newbuf, {type: "float"}, 0); - var decimal_point = instance.web._t.database.parameters.decimal_point; + var newbuf_float = formats.parse_value(newbuf, {type: "float"}, 0); + var decimal_point = _t.database.parameters.decimal_point; if (input === decimal_point) { if (options.firstinput) { diff --git a/addons/point_of_sale/static/src/js/popups.js b/addons/point_of_sale/static/src/js/popups.js index 16dc7413865..17a3fd6ac7c 100644 --- a/addons/point_of_sale/static/src/js/popups.js +++ b/addons/point_of_sale/static/src/js/popups.js @@ -205,7 +205,7 @@ var NumberPopupWidget = PopupWidget.extend({ this._super(options); this.inputbuffer = '' + (options.value || ''); - this.decimal_separator = instance.web._t.database.parameters.decimal_point; + this.decimal_separator = _t.database.parameters.decimal_point; this.renderElement(); this.firstinput = true; }, diff --git a/addons/point_of_sale/static/src/js/screens.js b/addons/point_of_sale/static/src/js/screens.js index 273f6764643..4626f3b4ff3 100644 --- a/addons/point_of_sale/static/src/js/screens.js +++ b/addons/point_of_sale/static/src/js/screens.js @@ -1706,7 +1706,7 @@ var PaymentScreenWidget = ScreenWidget.extend({ 'title': tip ? _t('Change Tip') : _t('Add Tip'), 'value': self.format_currency_no_symbol(value), 'confirm': function(value) { - order.set_tip(instance.web.parse_value(value, {type: "float"}, 0)); + order.set_tip(formats.parse_value(value, {type: "float"}, 0)); self.order_changes(); self.render_paymentlines(); } From da03d9700347ca4b6564237dd62e5dd76b1bea14 Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Wed, 6 Jan 2016 15:38:01 +0100 Subject: [PATCH 3/8] [IMP] account: test_product_id_change Forward port of c4fb2c2 in new api --- addons/account/tests/__init__.py | 1 + .../account/tests/test_product_id_change.py | 119 ++++++++++++------ 2 files changed, 81 insertions(+), 39 deletions(-) diff --git a/addons/account/tests/__init__.py b/addons/account/tests/__init__.py index e4a6224852d..01e519c02cf 100644 --- a/addons/account/tests/__init__.py +++ b/addons/account/tests/__init__.py @@ -12,6 +12,7 @@ from . import test_chart_of_account from . import test_fiscal_position from . import test_manual_reconciliation from . import test_payment +from . import test_product_id_change from . import test_reconciliation from . import test_search from . import test_tax diff --git a/addons/account/tests/test_product_id_change.py b/addons/account/tests/test_product_id_change.py index 1bd5154f4ba..a2008b64bc7 100644 --- a/addons/account/tests/test_product_id_change.py +++ b/addons/account/tests/test_product_id_change.py @@ -1,50 +1,91 @@ -from openerp.tests.common import TransactionCase +from openerp.addons.account.tests.account_test_classes import AccountingTestCase +import time -class TestProductIdChange(TransactionCase): +class TestProductIdChange(AccountingTestCase): """Test that when an included tax is mapped by a fiscal position, the included tax must be subtracted to the price of the product. """ def setUp(self): super(TestProductIdChange, self).setUp() - self.fiscal_position_model = self.registry('account.fiscal.position') - self.fiscal_position_tax_model = self.registry('account.fiscal.position.tax') - self.tax_model = self.registry('account.tax') - self.pricelist_model = self.registry('product.pricelist') - self.res_partner_model = self.registry('res.partner') - self.product_tmpl_model = self.registry('product.template') - self.product_model = self.registry('product.product') - self.invoice_line_model = self.registry('account.invoice.line') + self.invoice_model = self.env['account.invoice'] + self.fiscal_position_model = self.env['account.fiscal.position'] + self.fiscal_position_tax_model = self.env['account.fiscal.position.tax'] + self.tax_model = self.env['account.tax'] + self.pricelist_model = self.env['product.pricelist'] + self.res_partner_model = self.env['res.partner'] + self.product_tmpl_model = self.env['product.template'] + self.product_model = self.env['product.product'] + self.invoice_line_model = self.env['account.invoice.line'] + self.account_receivable = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_receivable').id)], limit=1) + self.account_revenue = self.env['account.account'].search([('user_type_id', '=', self.env.ref('account.data_account_type_revenue').id)], limit=1) def test_product_id_change(self): - cr, uid = self.cr, self.uid - partner_id = self.res_partner_model.create(cr, uid, dict(name="George")) - tax_include_id = self.tax_model.create(cr, uid, dict(name="Include tax", - type='percent', - amount='0.21', - price_include=True)) - tax_exclude_id = self.tax_model.create(cr, uid, dict(name="Exclude tax", - type='percent', - amount='0.00')) - product_tmpl_id = self.product_tmpl_model.create(cr, uid, dict(name="Voiture", - list_price='121', - standard_price='121', - taxes_id=[(6, 0, [tax_include_id])], - supplier_taxes_id=[(6, 0, [tax_include_id])])) - product_id = self.product_model.create(cr, uid, dict(product_tmpl_id=product_tmpl_id)) - product = self.product_model.browse(cr, uid, [product_id]) - fp_id = self.fiscal_position_model.create(cr, uid, dict(name="fiscal position", - sequence=1)) - fp_tax_id = self.fiscal_position_tax_model.create(cr, uid, dict(position_id=fp_id, - tax_src_id=tax_include_id, - tax_dest_id=tax_exclude_id)) + partner = self.res_partner_model.create(dict(name="George")) + tax_include_sale = self.tax_model.create(dict(name="Include tax", + type_tax_use='sale', + amount='21.00', + price_include=True)) + tax_include_purchase = self.tax_model.create(dict(name="Include tax", + type_tax_use='purchase', + amount='21.00', + price_include=True)) + tax_exclude_sale = self.tax_model.create(dict(name="Exclude tax", + type_tax_use='sale', + amount='0.00')) + tax_exclude_purchase = self.tax_model.create(dict(name="Exclude tax", + type_tax_use='purchase', + amount='0.00')) + product_tmpl = self.product_tmpl_model.create(dict(name="Voiture", + list_price='121', + standard_price='121', + taxes_id=[(6, 0, [tax_include_sale.id])], + supplier_taxes_id=[(6, 0, [tax_include_purchase.id])])) + product = self.product_model.create(dict(product_tmpl_id=product_tmpl.id)) + fp = self.fiscal_position_model.create(dict(name="fiscal position", sequence=1)) + fp_tax_sale = self.fiscal_position_tax_model.create(dict(position_id=fp.id, + tax_src_id=tax_include_sale.id, + tax_dest_id=tax_exclude_sale.id)) + fp_tax_purchase = self.fiscal_position_tax_model.create(dict(position_id=fp.id, + tax_src_id=tax_include_purchase.id, + tax_dest_id=tax_exclude_purchase.id)) - res = self.invoice_line_model.product_id_change(cr, uid, [], product.id, product.uom_id.id, - qty=1, type='out_invoice', partner_id=partner_id, - fposition_id=fp_id) - self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price") + out_invoice = self.invoice_model.create({ + 'partner_id': partner.id, + 'reference_type': 'none', + 'name': 'invoice to client', + 'account_id': self.account_receivable.id, + 'type': 'out_invoice', + 'date_invoice': time.strftime('%Y') + '-06-26', + 'fiscal_position_id': fp.id, + }) + out_line = self.invoice_line_model.create({ + 'product_id': product.id, + 'quantity': 1, + 'price_unit': 121.0, + 'invoice_id': out_invoice.id, + 'name': 'something out', + 'account_id': self.account_revenue.id, + }) - res = self.invoice_line_model.product_id_change(cr, uid, [], product.id, product.uom_id.id, - qty=1, type='in_invoice', partner_id=partner_id, - fposition_id=fp_id) - self.assertEquals(100, res['value']['price_unit'], "The included tax must be subtracted to the price") + in_invoice = self.invoice_model.create({ + 'partner_id': partner.id, + 'reference_type': 'none', + 'name': 'invoice to supplier', + 'account_id': self.account_receivable.id, + 'type': 'in_invoice', + 'date_invoice': time.strftime('%Y') + '-06-26', + 'fiscal_position_id': fp.id, + }) + in_line = self.invoice_line_model.create({ + 'product_id': product.id, + 'quantity': 1, + 'price_unit': 121.0, + 'invoice_id': in_invoice.id, + 'name': 'something in', + 'account_id': self.account_revenue.id, + }) + out_line._onchange_product_id() + self.assertEquals(100, out_line.price_unit, "The included tax must be subtracted to the price") + in_line._onchange_product_id() + self.assertEquals(100, in_line.price_unit, "The included tax must be subtracted to the price") From 7fcce928f3621af5dd68eee8062ab5821dcf2697 Mon Sep 17 00:00:00 2001 From: Christophe Matthieu Date: Tue, 5 Jan 2016 15:10:48 +0100 Subject: [PATCH 4/8] [FIX] web_editor: allow custom template for html_frame field --- addons/web_editor/static/src/js/backend.js | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/addons/web_editor/static/src/js/backend.js b/addons/web_editor/static/src/js/backend.js index 3d3b6cb27ee..eca913e1309 100644 --- a/addons/web_editor/static/src/js/backend.js +++ b/addons/web_editor/static/src/js/backend.js @@ -194,7 +194,7 @@ var FieldTextHtml = widget.extend({ return def; }, get_url: function (_attr) { - var src = this.options.editor_url ? this.options.editor_url+"?" : "/web_editor/field/html?"; + var src = this.options.editor_url || "/web_editor/field/html"; var datarecord = this.view.get_fields_values(); var attr = { @@ -211,6 +211,9 @@ var FieldTextHtml = widget.extend({ if (this.options.snippets) { attr.snippets = this.options.snippets; } + if (this.options.template) { + attr.template = this.options.template; + } if (!this.get("effective_readonly")) { attr.enable_editor = 1; } @@ -227,6 +230,10 @@ var FieldTextHtml = widget.extend({ attr[k] = _attr[k]; } + if (src.indexOf('?') === -1) { + src += "?"; + } + for (var k in attr) { if (attr[k] !== null) { src += "&"+k+"="+(_.isBoolean(attr[k]) ? +attr[k] : attr[k]); From 0b9fbc67bbbb91d10b3ed7aaf6f7327628e59c36 Mon Sep 17 00:00:00 2001 From: Denis Ledoux Date: Thu, 7 Jan 2016 10:24:54 +0100 Subject: [PATCH 5/8] [FIX] purchase: prevent write on the related `stock.location` `default_location_dest_id_usage` on `purchase.order` is used only for an attrs domain on the field `dest_address_id` in the purchase order form. There is therefore no worries to set it as readonly, it won't break the feature he has been added for. Besides, this will prevent the useless write of the same field value on the related `stock.location` when saving the purchase order. This is important to prevent the useless write on `stock.location`, as users might have the rights to create/edit purchase orders without having the write access to the stock locations. opw-660736 --- addons/purchase/purchase.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/purchase/purchase.py b/addons/purchase/purchase.py index 8e9adb74f32..247a932329a 100644 --- a/addons/purchase/purchase.py +++ b/addons/purchase/purchase.py @@ -150,7 +150,7 @@ class PurchaseOrder(models.Model): picking_type_id = fields.Many2one('stock.picking.type', 'Deliver To', states=READONLY_STATES, required=True, default=_default_picking_type,\ help="This will determine picking type of incoming shipment") default_location_dest_id_usage = fields.Selection(related='picking_type_id.default_location_dest_id.usage', string='Destination Location Type',\ - help="Technical field used to display the Drop Ship Address") + help="Technical field used to display the Drop Ship Address", readonly=True) group_id = fields.Many2one('procurement.group', string="Procurement Group") @api.model From 8e1057316f3d6a75dc60e25614159462e552b826 Mon Sep 17 00:00:00 2001 From: Stephen Medina Date: Tue, 20 Oct 2015 17:53:44 -0700 Subject: [PATCH 6/8] [ADD] doc: mention how to include static files Does not explicitly mention how static files are loaded. This will confuse anyone who is using the documentation as a guide and not going through the pet store example code. Feel free to edit however, as long as it is mentioned somewhere. fixes #9170 --- doc/cla/individual/stephen144.md | 11 +++++++++++ doc/howtos/web.rst | 4 +++- 2 files changed, 14 insertions(+), 1 deletion(-) create mode 100644 doc/cla/individual/stephen144.md diff --git a/doc/cla/individual/stephen144.md b/doc/cla/individual/stephen144.md new file mode 100644 index 00000000000..1caf0b28b4f --- /dev/null +++ b/doc/cla/individual/stephen144.md @@ -0,0 +1,11 @@ +United States of America, 2015-10-22 + +I hereby agree to the terms of the Odoo Individual Contributor License +Agreement v1.0. + +I declare that I am authorized and able to make this agreement and sign this +declaration. + +Signed, + +Stephen Medina stephen@lilmail.xyz https://github.com/stephen144 diff --git a/doc/howtos/web.rst b/doc/howtos/web.rst index a2641cbfdef..d58091e964e 100644 --- a/doc/howtos/web.rst +++ b/doc/howtos/web.rst @@ -78,7 +78,7 @@ not be fetched by browsers. The ``src/css``, ``src/js`` and ``src/xml`` sub-folders are conventional and not strictly necessary. ``oepetstore/static/css/petstore.css`` - currently empty, will hold the CSS_ for pet store content + Currently empty, will hold the CSS_ for pet store content ``oepetstore/static/xml/petstore.xml`` Mostly empty, will hold :ref:`reference/qweb` templates ``oepetstore/static/js/petstore.js`` @@ -103,6 +103,8 @@ sub-folders are conventional and not strictly necessary. Which only prints a small message in the browser's console. +The files in the ``static`` folder, need to be defined within the module in order for them to be loaded correctly. Everything in ``src/xml`` is defined in ``__openerp__.py`` while the contents of ``src/css`` and ``src/js`` are defined in ``petstore.xml``, or a similar file. + .. warning:: All JavaScript files are concatenated and :term:`minified` to improve From 61cf01b7a8d9bedb577af0cf64f20bbeeb8c031c Mon Sep 17 00:00:00 2001 From: Goffin Simon Date: Thu, 7 Jan 2016 15:56:38 +0100 Subject: [PATCH 7/8] [FIX] mail: mailing domain not set properly When selecting contacts from Contacts list views and clicking on action window "Partner Mass Mailing", the 'active_domain' must be filled in the wizard with the selecting contacts. In this way, the right mailing_domain will be set when creating the related mail.mass_mailing record (in addons/mass_mailing/wizard/mail_compose_message.py in function get_mail_values). opw:659383 --- addons/mail/wizard/mail_compose_message_view.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/addons/mail/wizard/mail_compose_message_view.xml b/addons/mail/wizard/mail_compose_message_view.xml index 54d8e599240..73429e48962 100644 --- a/addons/mail/wizard/mail_compose_message_view.xml +++ b/addons/mail/wizard/mail_compose_message_view.xml @@ -96,6 +96,7 @@ context="{ 'default_composition_mode': 'mass_mail', 'default_partner_to': '${object.id or \'\'}', + 'default_active_domain': [['id', 'in', context.get('active_ids', [])]], }"/> From 100d604cb0ebd6aa3f57c9809c6771b0b4b72a07 Mon Sep 17 00:00:00 2001 From: Christophe Simonis Date: Wed, 6 Jan 2016 18:56:37 +0100 Subject: [PATCH 8/8] [FIX] im_livechat: correct loader js code --- addons/im_livechat/controllers/main.py | 3 ++- addons/im_livechat/models/im_livechat_channel.py | 2 +- addons/im_livechat/views/im_livechat_channel_templates.xml | 4 ++-- 3 files changed, 5 insertions(+), 4 deletions(-) diff --git a/addons/im_livechat/controllers/main.py b/addons/im_livechat/controllers/main.py index 43e547e2fb1..30ae212c8b2 100644 --- a/addons/im_livechat/controllers/main.py +++ b/addons/im_livechat/controllers/main.py @@ -30,7 +30,8 @@ class LivechatController(http.Controller): username = kwargs.get("username", _("Visitor")) channel = request.env['im_livechat.channel'].sudo().browse(channel_id) info = request.env['im_livechat.channel'].get_livechat_info(channel.id, username=username) - return request.render('im_livechat.loader', {'info': info, 'web_session_required': True}) if info['available'] else False + js = request.render('im_livechat.loader', {'info': info, 'web_session_required': True}) + return request.make_response(js, headers=[('Content-Type', 'application/javascript')]) @http.route('/im_livechat/init', type='json', auth="public") def livechat_init(self, channel_id): diff --git a/addons/im_livechat/models/im_livechat_channel.py b/addons/im_livechat/models/im_livechat_channel.py index e15d4212a43..ac894a2c7ab 100644 --- a/addons/im_livechat/models/im_livechat_channel.py +++ b/addons/im_livechat/models/im_livechat_channel.py @@ -195,7 +195,7 @@ class ImLivechatChannel(models.Model): @api.model def get_livechat_info(self, channel_id, username='Visitor'): info = {} - info['available'] = len(self.browse(channel_id).get_available_users()) + info['available'] = len(self.browse(channel_id).get_available_users()) > 0 if info['available']: info['server_url'] = self.env['ir.config_parameter'].get_param('web.base.url') info['options'] = self.sudo().get_channel_infos(channel_id) diff --git a/addons/im_livechat/views/im_livechat_channel_templates.xml b/addons/im_livechat/views/im_livechat_channel_templates.xml index d97df04989e..0efd2310a14 100644 --- a/addons/im_livechat/views/im_livechat_channel_templates.xml +++ b/addons/im_livechat/views/im_livechat_channel_templates.xml @@ -143,7 +143,6 @@ - document.addEventListener("DOMContentLoaded", function(event) { odoo.define('web.session', function (require) { @@ -154,6 +153,7 @@ odoo.define('im_livechat.livesupport', function (require) { + var im_livechat = require('im_livechat.im_livechat'); var button = new im_livechat.LivechatButton( $('body'), @@ -162,9 +162,9 @@ ); button.appendTo($('body')); window.livechat_button = button; + }); }); -