[MIG] sale_sourced_by_line: to Odoo 13.0

This commit is contained in:
Jared Kipe
2020-10-31 08:48:59 -07:00
parent 36e31ae0e3
commit b139cc1c16
3 changed files with 113 additions and 15 deletions

View File

@@ -1,7 +1,7 @@
{
'name': 'Sale Sourced by Line',
'summary': 'Multiple warehouse source locations for Sale order',
'version': '12.0.1.0.0',
'version': '13.0.1.0.0',
'author': "Hibou Corp.,Odoo Community Association (OCA)",
'category': 'Warehouse',
'license': 'AGPL-3',

View File

@@ -1,3 +1,4 @@
from collections import defaultdict
from odoo import api, fields, models
@@ -11,10 +12,12 @@ class SaleOrder(models.Model):
class SaleOrderLine(models.Model):
_inherit = 'sale.order.line'
warehouse_id = fields.Many2one('stock.warehouse', string='Warehouse')
# In 13, this field exists, but isn't stored and is computed during
# computation for available inventory (set to order's warehouse)
warehouse_id = fields.Many2one('stock.warehouse', string='Warehouse',
compute=None, store=True)
date_planned = fields.Datetime('Planned Date')
@api.multi
def _prepare_procurement_values(self, group_id=False):
vals = super(SaleOrderLine, self)._prepare_procurement_values(group_id=group_id)
if self.warehouse_id:
@@ -24,3 +27,58 @@ class SaleOrderLine(models.Model):
elif self.order_id.date_planned:
vals.update({'date_planned': self.order_id.date_planned})
return vals
# Needs modifications to not actually set a warehouse on the line as it is now stored
@api.depends('product_id', 'customer_lead', 'product_uom_qty', 'product_uom', 'order_id.warehouse_id', 'order_id.commitment_date')
def _compute_qty_at_date(self):
""" Compute the quantity forecasted of product at delivery date. There are
two cases:
1. The quotation has a commitment_date, we take it as delivery date
2. The quotation hasn't commitment_date, we compute the estimated delivery
date based on lead time"""
qty_processed_per_product = defaultdict(lambda: 0)
grouped_lines = defaultdict(lambda: self.env['sale.order.line'])
# We first loop over the SO lines to group them by warehouse and schedule
# date in order to batch the read of the quantities computed field.
for line in self:
if not (line.product_id and line.display_qty_widget):
continue
# use warehouse from line or order
warehouse = line.warehouse_id or line.order_id.warehouse_id
# line.warehouse_id = line.order_id.warehouse_id
if line.order_id.commitment_date:
date = line.order_id.commitment_date
else:
date = line._expected_date()
grouped_lines[(warehouse, date)] |= line
treated = self.browse()
for (warehouse, scheduled_date), lines in grouped_lines.items():
product_qties = lines.mapped('product_id').with_context(to_date=scheduled_date, warehouse=warehouse).read([
'qty_available',
'free_qty',
'virtual_available',
])
qties_per_product = {
product['id']: (product['qty_available'], product['free_qty'], product['virtual_available'])
for product in product_qties
}
for line in lines:
line.scheduled_date = scheduled_date
qty_available_today, free_qty_today, virtual_available_at_date = qties_per_product[line.product_id.id]
line.qty_available_today = qty_available_today - qty_processed_per_product[line.product_id.id]
line.free_qty_today = free_qty_today - qty_processed_per_product[line.product_id.id]
line.virtual_available_at_date = virtual_available_at_date - qty_processed_per_product[line.product_id.id]
if line.product_uom and line.product_id.uom_id and line.product_uom != line.product_id.uom_id:
line.qty_available_today = line.product_id.uom_id._compute_quantity(line.qty_available_today, line.product_uom)
line.free_qty_today = line.product_id.uom_id._compute_quantity(line.free_qty_today, line.product_uom)
line.virtual_available_at_date = line.product_id.uom_id._compute_quantity(line.virtual_available_at_date, line.product_uom)
qty_processed_per_product[line.product_id.id] += line.product_uom_qty
treated |= lines
remaining = (self - treated)
remaining.virtual_available_at_date = False
remaining.scheduled_date = False
remaining.free_qty_today = False
remaining.qty_available_today = False
# don't unset warehouse as it may be set by hand
# remaining.warehouse_id = False

View File

@@ -3,21 +3,61 @@ from odoo.tests import common
class TestSaleSources(common.TransactionCase):
def test_plan_two_warehouses(self):
partner = self.env.ref('base.res_partner_2')
product_1 = self.env.ref('product.product_product_24_product_template')
product_2 = self.env.ref('product.product_product_16_product_template')
wh_1 = self.env.ref('stock.stock_warehouse_shop0')
wh_2 = self.env.ref('stock.warehouse0')
def setUp(self):
super(TestSaleSources, self).setUp()
self.partner = self.env.ref('base.res_partner_2')
self.product_1 = self.env['product.product'].create({
'type': 'consu',
'name': 'Test Product 1',
})
self.product_2 = self.env['product.product'].create({
'type': 'consu',
'name': 'Test Product 2',
})
self.wh_1 = self.env.ref('stock.warehouse0')
self.wh_2 = self.env['stock.warehouse'].create({
'name': 'Test WH2',
'code': 'TWH2',
})
def test_plan_one_warehouse(self):
so = self.env['sale.order'].create({
'warehouse_id': wh_1.id,
'partner_id': partner.id,
'warehouse_id': self.wh_1.id,
'partner_id': self.partner.id,
'date_planned': '2018-01-01',
'order_line': [(0, 0, {'product_id': product_1.product_variant_id.id}),
(0, 0, {'product_id': product_2.product_variant_id.id, 'date_planned': '2018-02-01', 'warehouse_id': wh_2.id})]
'order_line': [(0, 0, {
'product_id': self.product_1.id,
'product_uom_qty': 1.0,
'product_uom': self.product_1.uom_id.id,
'price_unit': 10.0,
}),
(0, 0, {
'product_id': self.product_2.id,
'product_uom_qty': 1.0,
'product_uom': self.product_2.uom_id.id,
'price_unit': 10.0,
})]
})
so.action_confirm()
self.assertTrue(so.state in ('sale', 'done'))
self.assertEqual(len(so.picking_ids), 1)
self.assertEqual(len(so.picking_ids.filtered(lambda p: p.picking_type_id.warehouse_id == self.wh_1)), 1)
self.assertEqual(len(so.picking_ids.filtered(lambda p: p.picking_type_id.warehouse_id == self.wh_2)), 0)
def test_plan_two_warehouses(self):
so = self.env['sale.order'].create({
'warehouse_id': self.wh_1.id,
'partner_id': self.partner.id,
'date_planned': '2018-01-01',
'order_line': [(0, 0, {'product_id': self.product_1.id}),
(0, 0, {'product_id': self.product_2.id,
'date_planned': '2018-02-01', 'warehouse_id': self.wh_2.id})]
})
# in 13 default computation, this would result in a failure
self.assertTrue(so.order_line.filtered(lambda l: l.warehouse_id))
so.action_confirm()
self.assertTrue(so.state in ('sale', 'done'))
self.assertEqual(len(so.picking_ids), 2)
self.assertEqual(len(so.picking_ids.filtered(lambda p: p.picking_type_id.warehouse_id == wh_1)), 1)
self.assertEqual(len(so.picking_ids.filtered(lambda p: p.picking_type_id.warehouse_id == wh_2)), 1)
self.assertEqual(len(so.picking_ids.filtered(lambda p: p.picking_type_id.warehouse_id == self.wh_1)), 1)
self.assertEqual(len(so.picking_ids.filtered(lambda p: p.picking_type_id.warehouse_id == self.wh_2)), 1)