[FIX] stock{,_dropshipping}: set last delivery partner on lot

If `stock_dropshipping` is installed, the "Transfer To" field of a lot
does not work with standard flows

To reproduce the issue:
1. Create a tracked-by-sn product
2. Update its quantity with 1 x SN
3. Deliver SN to a partner
4. Open the list view of lots/serial numbers and enable the column
   "Transfer To"

Error: The field "Transfer To" for SN is empty, it should be the partner

The field `last_delivery_partner_id` is a computed one and the compute
method calls `_find_delivery_ids_by_lot` to get all relevant
information. In this method, we search the SMLs based on a domain
provided by `_get_delivery_ids_by_lot_domain`. If `stock_dropshipping`
is not installed, the method will return a legit domain:
https://github.com/odoo/odoo/blob/7adc661be1eb426a90842160b2e062446d3ccc03/addons/stock/models/stock_lot.py#L191-L196
However, if the dropshipping module is installed, an override creates
the same domain (directly in the override, without any call to `super`)
and adds a `OR` condition:
https://github.com/odoo/odoo/blob/7adc661be1eb426a90842160b2e062446d3ccc03/addons/stock_dropshipping/models/stock.py#L62-L70
But it contains an error: the `AND` operator is missing, it should be
```py '&', ('location_dest_id.usage', '=', 'customer'),
('location_id.usage', '=', 'supplier') ``` As a result, for an SM to be
found, its source location usage has to be `supplier`. This is the
reason why, in the above use case, the lot does not have any
`last_delivery_partner_id`: we did not find such an SML.

OPW-3386247

closes odoo/odoo#128558

X-original-commit: 8ecc177478f0ffc8ba9cfc65f47386363bd6cb4a
Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
Adrien Widart (awt)
2023-07-15 13:05:53 +02:00
committed by William Henrotin
parent 9616c9940d
commit 8a310ae2e4
3 changed files with 62 additions and 15 deletions
+12 -5
View File
@@ -6,6 +6,7 @@ from re import findall as regex_findall, split as regex_split
from odoo import _, api, fields, models
from odoo.exceptions import UserError, ValidationError
from odoo.osv import expression
class StockLot(models.Model):
@@ -200,17 +201,23 @@ class StockLot(models.Model):
})
return action
def _get_delivery_ids_by_lot_domain(self):
@api.model
def _get_outgoing_domain(self):
return [
('lot_id', 'in', self.ids),
('state', '=', 'done'),
'|', ('picking_code', '=', 'outgoing'), ('produce_line_ids', '!=', False),
'|',
('picking_code', '=', 'outgoing'),
('produce_line_ids', '!=', False),
]
def _find_delivery_ids_by_lot(self, lot_path=None, delivery_by_lot=None):
if lot_path is None:
lot_path = set()
domain = self._get_delivery_ids_by_lot_domain()
domain = [
('lot_id', 'in', self.ids),
('state', '=', 'done'),
]
domain_restriction = self._get_outgoing_domain()
domain = expression.AND([domain, domain_restriction])
move_lines = self.env['stock.move.line'].search(domain)
moves_by_lot = {
lot_id: {'producing_lines': set(), 'barren_lines': set()}
+43 -1
View File
@@ -2,7 +2,7 @@
from odoo.addons.stock.tests.common import TestStockCommon
from odoo.exceptions import ValidationError
from odoo.tests import Form
from odoo.tests import Form, tagged
from odoo.tools import mute_logger, float_round
from odoo import fields
@@ -2597,3 +2597,45 @@ class TestStockFlow(TestStockCommon):
# trigger SQL constraints
self.PickingObj.flush_model()
self.assertEqual(self.PickingObj.search_count([('name', '=', picking_2.name)]), 1)
@tagged('-at_install', 'post_install')
class TestStockFlowPostInstall(TestStockCommon):
def test_last_delivery_partner_field_on_lot(self):
stock_location = self.env['stock.location'].browse(self.stock_location)
partner = self.env['res.partner'].create({'name': 'Super Partner'})
product = self.env['product.product'].create({
'name': 'Super Product',
'type': 'product',
'tracking': 'serial',
})
sn = self.env['stock.lot'].create({
'name': 'super_sn',
'product_id': product.id,
'company_id': self.env.company.id,
})
self.env['stock.quant']._update_available_quantity(product, stock_location, 1, lot_id=sn)
delivery = self.env['stock.picking'].create({
'partner_id': partner.id,
'picking_type_id': self.picking_type_out,
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
'move_ids': [(0, 0, {
'name': product.name,
'product_id': product.id,
'product_uom': product.uom_id.id,
'product_uom_qty': 1.0,
'location_id': self.stock_location,
'location_dest_id': self.customer_location,
})],
})
delivery.action_confirm()
delivery.action_assign()
delivery.move_ids.move_line_ids.qty_done = 1
delivery.button_validate()
self.assertEqual(sn.last_delivery_partner_id, partner)
+7 -9
View File
@@ -2,6 +2,7 @@
# Part of Odoo. See LICENSE file for full copyright and licensing details.
from odoo import api, models, fields
from odoo.osv import expression
class StockRule(models.Model):
@@ -70,12 +71,9 @@ class StockLot(models.Model):
if last_delivery.is_dropship:
lot.last_delivery_partner_id = last_delivery.sale_id.partner_id
def _get_delivery_ids_by_lot_domain(self):
return [
('lot_id', 'in', self.ids),
('state', '=', 'done'),
'|',
'|', ('picking_code', '=', 'outgoing'), ('produce_line_ids', '!=', False),
# dropship transfers have an incoming picking_code but should be considered as well
('location_dest_id.usage', '=', 'customer'), ('location_id.usage', '=', 'supplier')
]
def _get_outgoing_domain(self):
res = super()._get_outgoing_domain()
return expression.OR([res, [
('location_dest_id.usage', '=', 'customer'),
('location_id.usage', '=', 'supplier'),
]])