From d89f4d6ec26806389922351eb8e575754b3f60e0 Mon Sep 17 00:00:00 2001 From: "Atchuthan, Sodexis" Date: Thu, 24 May 2018 10:22:28 +0000 Subject: [PATCH 1/6] [FIX] stock: set picking_type_id to readonly except in draft state Before this commit, the customer is allowed to change picking type after the stock.picking record is moved from draft. But it doesn't make the changes in the stock moves and operations as the procurements are already created for initial demand. To avoid confusing the user, it can now only be modified in draft state. Authored by SodexisTeam opw 1848252 opw-1934814 closes odoo/odoo#30865 --- addons/stock/models/stock_picking.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index 3e3e99c931e..c1f5f98ba09 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -241,7 +241,8 @@ class Picking(models.Model): picking_type_id = fields.Many2one( 'stock.picking.type', 'Picking Type', required=True, - states={'done': [('readonly', True)], 'cancel': [('readonly', True)]}) + readonly=True, + states={'draft': [('readonly', False)]}) picking_type_code = fields.Selection([ ('incoming', 'Vendors'), ('outgoing', 'Customers'), From c7c938996f783cbb187697b9f36c8359b2c4733f Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 6 Feb 2019 10:24:09 +0000 Subject: [PATCH 2/6] [FIX] account: analytic cost - Set a cost of 12.34 for product P - Create manually a new analytic entry - Choose product P - Set desired quantity The analytic amount is set to 12.00. This is because `move_id` is empty, therefore `currency_id` is empty as well and `decimal_places` is zero opw-1924184 closes odoo/odoo#30869 --- addons/account/models/account_analytic_line.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/account/models/account_analytic_line.py b/addons/account/models/account_analytic_line.py index 20b44c04dbb..5f001ad34dd 100644 --- a/addons/account/models/account_analytic_line.py +++ b/addons/account/models/account_analytic_line.py @@ -44,7 +44,7 @@ class AccountAnalyticLine(models.Model): # Compute based on pricetype amount_unit = self.product_id.price_compute('standard_price', uom=unit)[self.product_id.id] amount = amount_unit * self.unit_amount or 0.0 - result = round(amount, self.currency_id.decimal_places) * -1 + result = round(amount, self.currency_id.decimal_places if self.currency_id else 2) * -1 self.amount = result self.general_account_id = account self.product_uom_id = unit From 845a6a9e08293a955127ec587397bbf7bec27116 Mon Sep 17 00:00:00 2001 From: Josse Colpaert Date: Fri, 1 Feb 2019 17:33:50 +0000 Subject: [PATCH 3/6] [FIX] stock: lot in multiple locations - Activate: 'Track lots or serial numbers' 'Manage several Warehouses, each one composed by several stock locations' 'Advanced routing of products using rules' - In the main warehouse, activate Pick + Ship - In Stock Locations, create 'WH/Stock/Shelf 3' and 'WH/Stock/Shelf 4' (1 and 2 already exist, use the same config) - Create a new product 'Foo', activate Tracking By Lots - On Foo, use 4 times the "Update Qty on Hand" (order is important): Add 1 on Shelf 2, create a lot Add 1 on Shelf 1, use the same lot Add 3 on Shelf 4, use the same lot Add 1 on Shelf 3, use the same lot - Create a SO, set a partner - Ensure that YourCompany is used as warehouse - Add several SO lines (order is important) a line with 1 product Foo a second line with 1 product Foo a third line with 4 products Foo - Confirm the SO, you now have 2 deliveries, 1 Pick, 1 Out - Open the Pick, all moves should be available, you should have: 4 operations: Shelf 2, quantity 1 Shelf 4, quantity 3 Shelf 1, quantity 1 Shelf 3, quantity 1 3 moves: A, quantity 1 B, quantity 1 C, quantity 4 - On each operation, select the lot created before and set the quantity to be fully done - Validate the Pick The moves end up like this: - Move A with qty 1: is done and linked with a quant of 1 - Move B with qty 1: is done and linked with no quant - Move C with qty 4: is done and linked with a quant of 1, a quant of 3, a quant of 1 (sum is 5) In the Out picking, the move linked with the source move (B) with no quant stays in "Waiting another move" even if the source move is done. This outgoing move will never be available. In the method `recompute_remaining_qty`, we loop on operations, and match them wih the moves. However, the operation with the largest quantity (Shelf 4, quantity 3) is processed before the move with the highest quantity (C, quantity 4). Therefore, when we later loop on move C, `qty_assign_cmp` is larger than zero, which sets `need_rereserve` and ultimately triggers `rereserve_quants` in `do_transfer`. A first part of the fix is to check for the location of the quants when matching moves and operations. This fixes the original issue, but inconsistencies can still arise since a quant which is taken partially. therefore, we make sure to never take more than the quantity on the link. opw-1932624 closes odoo/odoo#30857 --- addons/stock/models/stock_move.py | 14 ++++++++------ addons/stock/models/stock_picking.py | 2 +- 2 files changed, 9 insertions(+), 7 deletions(-) diff --git a/addons/stock/models/stock_move.py b/addons/stock/models/stock_move.py index c170d2cc5fa..43a51a03831 100644 --- a/addons/stock/models/stock_move.py +++ b/addons/stock/models/stock_move.py @@ -868,13 +868,15 @@ class StockMove(models.Model): false_quants += [reserved_quant] elif float_compare(lot_quantities.get(reserved_quant.lot_id.id, 0), 0, precision_rounding=rounding) > 0: if float_compare(lot_quantities[reserved_quant.lot_id.id], reserved_quant.qty, precision_rounding=rounding) >= 0: - lot_quantities[reserved_quant.lot_id.id] -= reserved_quant.qty - quants_taken += [(reserved_quant, reserved_quant.qty)] - qty_on_link -= reserved_quant.qty + qty_taken = min(reserved_quant.qty, qty_on_link) + lot_quantities[reserved_quant.lot_id.id] -= qty_taken + quants_taken += [(reserved_quant, qty_taken)] + qty_on_link -= qty_taken else: - quants_taken += [(reserved_quant, lot_quantities[reserved_quant.lot_id.id])] - lot_quantities[reserved_quant.lot_id.id] = 0 - qty_on_link -= lot_quantities[reserved_quant.lot_id.id] + qty_taken = min(qty_on_link, lot_quantities[reserved_quant.lot_id.id]) + quants_taken += [(reserved_quant, qty_taken)] + lot_quantities[reserved_quant.lot_id.id] -= qty_taken + qty_on_link -= qty_taken lot_move_qty[move.id] = qty_on_link remaining_move_qty[move.id] -= prout_move_qty[move] diff --git a/addons/stock/models/stock_picking.py b/addons/stock/models/stock_picking.py index c1f5f98ba09..3d381ac064c 100644 --- a/addons/stock/models/stock_picking.py +++ b/addons/stock/models/stock_picking.py @@ -737,7 +737,7 @@ class Picking(models.Model): flag = quant.package_id == ops.package_id else: flag = not quant.package_id.id - flag = flag and (ops.owner_id.id == quant.owner_id.id) + flag = flag and (ops.owner_id.id == quant.owner_id.id) and (ops.location_id.id == quant.location_id.id) if flag: if not lot_qty: max_qty_on_link = min(quant.qty, qty_to_assign) From fa97d6ab1573515e6485b169df1e1f6b709275de Mon Sep 17 00:00:00 2001 From: Nicolas Martinelli Date: Wed, 6 Feb 2019 14:11:50 +0000 Subject: [PATCH 4/6] [FIX] purchase: supplier on parent company - Create a product and set a contact as the vendor (for instance, Arthur Gomez from Asustek in the runbot) - Set a specific name and code for the supplier - Create a RFQ for this vendor (Arthur Gomez - the contact person) - Add the product, confirm the RFQ On the product, the company (Asustek) is automatically added as vendor, but there is no vendor name and code. opw-1929745 closes odoo/odoo#30891 --- addons/purchase/models/purchase.py | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/addons/purchase/models/purchase.py b/addons/purchase/models/purchase.py index 295c434c4e2..8f80e112b32 100644 --- a/addons/purchase/models/purchase.py +++ b/addons/purchase/models/purchase.py @@ -448,6 +448,16 @@ class PurchaseOrder(models.Model): 'currency_id': currency.id, 'delay': 0, } + # In case the order partner is a contact address, a new supplierinfo is created on + # the parent company. In this case, we keep the product name and code. + seller = line.product_id._select_seller( + partner_id=line.partner_id, + quantity=line.product_qty, + date=line.order_id.date_order and line.order_id.date_order[:10], + uom_id=line.product_uom) + if seller: + supplierinfo['product_name'] = seller.product_name + supplierinfo['product_code'] = seller.product_code vals = { 'seller_ids': [(0, 0, supplierinfo)], } From 0757ba3c639000edba89448a3a542a9f9c225538 Mon Sep 17 00:00:00 2001 From: RomainLibert Date: Thu, 7 Feb 2019 15:25:13 +0000 Subject: [PATCH 5/6] [FIX] fleet: fix _get_default_state method If fleet.vehicle_state_active is not found in the system then the method will raise an error, hence it won't allow creating any fleet.vehicle closes odoo/odoo#30925 --- addons/fleet/models/fleet.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/addons/fleet/models/fleet.py b/addons/fleet/models/fleet.py index 364b44fff16..538142ad2bb 100644 --- a/addons/fleet/models/fleet.py +++ b/addons/fleet/models/fleet.py @@ -143,7 +143,7 @@ class FleetVehicle(models.Model): def _get_default_state(self): state = self.env.ref('fleet.vehicle_state_active', raise_if_not_found=False) - return state and state.id or False + return state if state and state.id else False name = fields.Char(compute="_compute_vehicle_name", store=True) active = fields.Boolean(default=True) From be689c53c13330832510c8cef332ac862d4ed5e8 Mon Sep 17 00:00:00 2001 From: qsm-odoo Date: Wed, 6 Feb 2019 17:25:36 +0000 Subject: [PATCH 6/6] [FIX] web_editor: review drag and drop in the editor When dropping a snippet into a page, it is dropped in the drop-zone which is the nearest of the user cursor. When moving a snippet, that condition did not apply and the user was required to put the cursor at the exact location of the drop-zone. Also, for both drag and drop features, the drop zones which appeared were not displayed correctly for full width columns, which made dropping sometimes impossible when multiple col-*-12 were below each other. task-1937758 closes odoo/odoo#30899 --- .../static/src/js/snippets.editor.js | 36 ++++++++++++++++--- .../static/src/less/web_editor.ui.less | 4 +-- 2 files changed, 33 insertions(+), 7 deletions(-) diff --git a/addons/web_editor/static/src/js/snippets.editor.js b/addons/web_editor/static/src/js/snippets.editor.js index 97830d2ae8e..17c0c2ffb85 100644 --- a/addons/web_editor/static/src/js/snippets.editor.js +++ b/addons/web_editor/static/src/js/snippets.editor.js @@ -615,6 +615,10 @@ data.Class = Widget.extend({ var self = this; var zone_template = $("
"); + function isFullWidth($elem) { + return $elem.parent().width() === $elem.outerWidth(true); + } + if ($selector_children) { $selector_children.each(function () { var $zone = $(this); @@ -632,7 +636,10 @@ data.Class = Widget.extend({ 'display': 'inline-block' }); } else if (float === "left" || float === "right") { - $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.children().last().outerHeight()), 30)); + $drop.css('float', float); + if (!isFullWidth($zone)) { + $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.children().last().outerHeight()), 30)); + } } $drop = $drop.clone(); @@ -647,7 +654,10 @@ data.Class = Widget.extend({ 'display': 'inline-block' }); } else if (float === "left" || float === "right") { - $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.children().first().outerHeight()), 30)); + $drop.css('float', float); + if (!isFullWidth($zone)) { + $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.children().first().outerHeight()), 30)); + } } if (test) { $drop.css({'float': 'none', 'display': 'inline-block'}); @@ -668,14 +678,20 @@ data.Class = Widget.extend({ if($zone.prev('.oe_drop_zone:visible').length === 0) { $drop = zone_template.clone(); if (float === "left" || float === "right") { - $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.prev().outerHeight() || Infinity), 30)); + $drop.css('float', float); + if (!isFullWidth($zone)) { + $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.prev().outerHeight() || Infinity), 30)); + } } $zone.before($drop); } if($zone.next('.oe_drop_zone:visible').length === 0) { $drop = zone_template.clone(); if (float === "left" || float === "right") { - $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.next().outerHeight() || Infinity), 30)); + $drop.css('float', float); + if (!isFullWidth($zone)) { + $drop.addClass("oe_vertical").css('height', Math.max(Math.min($zone.outerHeight(), $zone.next().outerHeight() || Infinity), 30)); + } } $zone.after($drop); } @@ -862,6 +878,7 @@ data.Editor = Class.extend({ }, _drag_and_drop_start: function () { var self = this; + this.dropped = false; self.buildingBlock.editor_busy = true; self.size = { width: self.$target.width(), @@ -890,9 +907,18 @@ data.Editor = Class.extend({ self._drag_and_drop_after_insert_dropzone(); self._drag_and_drop_active_drop_zone($('.oe_drop_zone')); }, - _drag_and_drop_stop: function () { + _drag_and_drop_stop: function (ev, ui) { var self = this; + // TODO lot of this is duplicated code of the d&d feature of snippets + if (!this.dropped) { + var $el = $.nearest({x: ui.position.left, y: ui.position.top}, '.oe_drop_zone').first(); + if ($el.length) { + $el.after(this.$target); + this.dropped = true; + } + } + $(".oe_drop_zone").droppable('destroy').remove(); var prev = this.$target.first()[0].previousSibling; diff --git a/addons/web_editor/static/src/less/web_editor.ui.less b/addons/web_editor/static/src/less/web_editor.ui.less index 02094adf754..965a0ca820e 100644 --- a/addons/web_editor/static/src/less/web_editor.ui.less +++ b/addons/web_editor/static/src/less/web_editor.ui.less @@ -264,12 +264,12 @@ html[lang] > body.editor_enable [data-oe-translation-state] { } &.oe_vertical { - border: 2px dashed @odoo-brand-primary; + border: @odoo-dropzone-border; border-left: none; border-right: none; width: @odoo-dropzone-size; - float: left; + height: 100%; margin: 0 -@odoo-dropzone-size/2; &:after {