[IMP] stock: warehouse levels on replenishment
Show the stock in different warehouses in the replenishment info view if a route to resupply from these warehouses is available. Task: 2797326 Community PR: https://github.com/odoo/odoo/pull/87143 closes odoo/odoo#87143 Signed-off-by: Arnold Moyaux <arm@odoo.com>
This commit is contained in:
@@ -35,9 +35,11 @@
|
||||
<field name="model">stock.replenishment.info</field>
|
||||
<field name="inherit_id" ref="stock.view_stock_replenishment_info"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//footer" position="before">
|
||||
<field name="supplierinfo_id" invisible="1"/>
|
||||
<field name="supplierinfo_ids" readonly="1" context="{'tree_view_ref': 'purchase_stock.product_supplierinfo_replenishment_tree_view'}"/>
|
||||
<xpath expr="//page" position="before">
|
||||
<page string="Vendors">
|
||||
<field name="supplierinfo_id" invisible="1"/>
|
||||
<field name="supplierinfo_ids" readonly="1" context="{'tree_view_ref': 'purchase_stock.product_supplierinfo_replenishment_tree_view'}"/>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -90,3 +90,4 @@ access_stock_request_count,stock.request.count,model_stock_request_count,stock.g
|
||||
access_stock_replenishment_info,stock.replenishment.info,model_stock_replenishment_info,stock.group_stock_manager,1,1,1,0
|
||||
access_stock_picking_label_type_user,picking.label.type.user,model_picking_label_type,stock.group_stock_user,1,1,1,0
|
||||
access_stock_lot_label_layout_user,lot.label.layout.user,model_lot_label_layout,stock.group_stock_user,1,1,1,0
|
||||
access_stock_replenish_option,stock.replenishment.option,model_stock_replenishment_option,stock.group_stock_user,1,1,1,0
|
||||
|
||||
|
@@ -188,6 +188,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="sequence" string="Sequence" groups="base.group_no_one"/>
|
||||
<field name="supplied_wh_id" groups="base.group_no_one"/>
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
</group>
|
||||
|
||||
@@ -4,7 +4,7 @@
|
||||
from json import dumps
|
||||
from datetime import datetime, time
|
||||
|
||||
from odoo import api, fields, models, SUPERUSER_ID
|
||||
from odoo import api, fields, models, SUPERUSER_ID, _
|
||||
from odoo.osv.expression import AND
|
||||
from odoo.tools import get_month, subtract, format_date
|
||||
|
||||
@@ -20,6 +20,17 @@ class StockReplenishmentInfo(models.TransientModel):
|
||||
json_lead_days = fields.Char(compute='_compute_json_lead_days')
|
||||
json_replenishment_history = fields.Char(compute='_compute_json_replenishment_history')
|
||||
|
||||
warehouseinfo_ids = fields.One2many(related='orderpoint_id.warehouse_id.resupply_route_ids')
|
||||
wh_replenishment_option_ids = fields.One2many('stock.replenishment.option', 'replenishment_info_id', compute='_compute_wh_replenishment_options')
|
||||
|
||||
@api.depends('orderpoint_id')
|
||||
def _compute_wh_replenishment_options(self):
|
||||
for replenishment_info in self:
|
||||
replenishment_info.wh_replenishment_option_ids = self.env['stock.replenishment.option'].create([
|
||||
{'product_id': replenishment_info.product_id.id, 'route_id': route_id.id, 'replenishment_info_id': replenishment_info.id}
|
||||
for route_id in replenishment_info.warehouseinfo_ids
|
||||
])
|
||||
|
||||
@api.depends('orderpoint_id')
|
||||
def _compute_json_lead_days(self):
|
||||
self.json_lead_days = False
|
||||
@@ -78,3 +89,63 @@ class StockReplenishmentInfo(models.TransientModel):
|
||||
'template': 'stock.replenishmentHistory',
|
||||
'replenishment_history': replenishment_history
|
||||
})
|
||||
|
||||
|
||||
class StockReplenishmentOption(models.TransientModel):
|
||||
_name = 'stock.replenishment.option'
|
||||
_description = 'Stock warehouse replenishment option'
|
||||
|
||||
route_id = fields.Many2one('stock.route')
|
||||
product_id = fields.Many2one('product.product')
|
||||
replenishment_info_id = fields.Many2one('stock.replenishment.info')
|
||||
|
||||
location_id = fields.Many2one('stock.location', related='warehouse_id.lot_stock_id')
|
||||
warehouse_id = fields.Many2one('stock.warehouse', related='route_id.supplier_wh_id')
|
||||
uom = fields.Char(related='product_id.uom_name')
|
||||
qty_to_order = fields.Float(related='replenishment_info_id.qty_to_order')
|
||||
|
||||
free_qty = fields.Float(compute='_compute_free_qty')
|
||||
lead_time = fields.Char(compute='_compute_lead_time')
|
||||
|
||||
warning_message = fields.Char(compute='_compute_warning_message')
|
||||
|
||||
@api.depends('product_id', 'route_id')
|
||||
def _compute_free_qty(self):
|
||||
for record in self:
|
||||
record.free_qty = record.product_id.with_context(location=record.location_id.id).free_qty
|
||||
|
||||
@api.depends('replenishment_info_id')
|
||||
def _compute_lead_time(self):
|
||||
for record in self:
|
||||
lead_time = record.route_id.rule_ids._get_lead_days(record.product_id)[0]
|
||||
record.lead_time = str(lead_time) + " days"
|
||||
|
||||
@api.depends('warehouse_id', 'free_qty', 'uom', 'qty_to_order')
|
||||
def _compute_warning_message(self):
|
||||
for record in self:
|
||||
self.warning_message = _('{0} can only provide {1} {2}, while the quantity to order is {3} {2}.').format(
|
||||
record.warehouse_id.name,
|
||||
record.free_qty,
|
||||
record.uom,
|
||||
record.qty_to_order
|
||||
)
|
||||
|
||||
def select_route(self):
|
||||
if self.free_qty < self.qty_to_order:
|
||||
return {
|
||||
"type": "ir.actions.act_window",
|
||||
"res_model": "stock.replenishment.option",
|
||||
"res_id": self.id,
|
||||
"views": [[self.env.ref('stock.replenishment_option_warning_view').id, "form"]],
|
||||
"target": "new",
|
||||
"name": _("Quantity available too low")
|
||||
}
|
||||
return self.order_all()
|
||||
|
||||
def order_avbl(self):
|
||||
self.replenishment_info_id.orderpoint_id.qty_to_order = self.free_qty
|
||||
return self.order_all()
|
||||
|
||||
def order_all(self):
|
||||
self.replenishment_info_id.orderpoint_id.route_id = self.route_id
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
|
||||
@@ -15,6 +15,12 @@
|
||||
<field nolabel="1" name="json_replenishment_history" widget="json_widget"/>
|
||||
</group>
|
||||
</div>
|
||||
<notebook>
|
||||
<field name="warehouseinfo_ids" invisible="1"/>
|
||||
<page string="Warehouses" attrs="{'invisible' : [('warehouseinfo_ids', '=', [])]}">
|
||||
<field name="wh_replenishment_option_ids"/>
|
||||
</page>
|
||||
</notebook>
|
||||
<footer>
|
||||
<button string="Close" class="btn-default" special="cancel" data-hotkey="z"/>
|
||||
</footer>
|
||||
@@ -31,4 +37,43 @@
|
||||
<field name="context">{'default_orderpoint_id': active_id}</field>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
|
||||
<record id="replenishment_option_tree_view" model="ir.ui.view">
|
||||
<field name="name">stock.replenishment.option.tree.view</field>
|
||||
<field name="model">stock.replenishment.option</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="qty_to_order" invisible="1"/>
|
||||
<field name="warehouse_id" string="Warehouse"/>
|
||||
<field name="location_id" string="Warehouse Location"/>
|
||||
<field name="free_qty" decoration-danger="free_qty < qty_to_order" string="Available Quantity"/>
|
||||
<field name="uom" string="UoM"/>
|
||||
<field name="route_id"/>
|
||||
<field name="lead_time"/>
|
||||
<button name="select_route" string="Select Route" type="object" class="btn btn-link"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="replenishment_option_warning_view" model="ir.ui.view">
|
||||
<field name="name">stock.replenishment.warning.view</field>
|
||||
<field name="model">stock.replenishment.option</field>
|
||||
<field name="priority">100</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<div>
|
||||
<field name="warning_message"/>
|
||||
</div>
|
||||
<footer>
|
||||
<button name="order_avbl" type="object" class="btn-primary">
|
||||
Order <field name="free_qty"/>
|
||||
</button>
|
||||
<button name="order_all" type="object">
|
||||
Order <field name="qty_to_order"/>
|
||||
</button>
|
||||
<button string="Cancel" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
|
||||
Reference in New Issue
Block a user