[IMP] mrp, purchase_stock: visibility days and days to prepare MO
- Add the concept of 'Days to Prepare MO' in mrp, similar to 'Days to Purchase' but defined at the product level. Both concepts are merged into Days to Order at the orderpoint level, taking the value of Days to Purchase for orderpoints with a buy route and Days to Prepare MO for orderpoint with a manufacturing route. - Add the concept of 'Visibility Days' on orderpoints. The idea is to avoid to create through reordering rules multiple small orders for the same product on a small time frame but rather to order directly a bigger quantity. When Visibility Days are defined, the quantity of the orders created by a RR is not the quantity forecasted at Today + Lead times (quantity that triggered the order according to the RR), but the quantity forecasted at Today + Lead Times + Visibility days. The Visibility Days are different for purchase and manufacturing. Changing the route of the orderpoint will change its value. They can be defined at the company level and further fine-tuned on the orderpoint. In case of change of the parameters at the company level, only orderpoints without a specific value of Visibility Days will be changed. - Alignement between Manufacturing and Purchase Security Lead Time (previously the Manufacturing Security Lead time didn't impact the procurement date, instead the manufacturing time was made longer). closes odoo/odoo#86682 Task-id: 2738838 Pr: https://github.com/odoo/odoo/pull/86682 Related: odoo/upgrade#3415 Signed-off-by: William Henrotin (whe) <whe@odoo.com>
This commit is contained in:
@@ -658,7 +658,7 @@ class MrpProduction(models.Model):
|
||||
for production in self:
|
||||
if not production.date_planned_start or production.is_planned:
|
||||
continue
|
||||
days_delay = production.product_id.produce_delay + production.company_id.manufacturing_lead
|
||||
days_delay = production.product_id.produce_delay
|
||||
date_planned_finished = production.date_planned_start + relativedelta(days=days_delay)
|
||||
if date_planned_finished == production.date_planned_start:
|
||||
date_planned_finished = date_planned_finished + relativedelta(hours=1)
|
||||
@@ -904,7 +904,6 @@ class MrpProduction(models.Model):
|
||||
|
||||
def _get_date_planned_finished(self):
|
||||
date_planned_finished = self.date_planned_start + relativedelta(days=self.product_id.produce_delay)
|
||||
date_planned_finished = date_planned_finished + relativedelta(days=self.company_id.manufacturing_lead)
|
||||
if date_planned_finished == self.date_planned_start:
|
||||
date_planned_finished = date_planned_finished + relativedelta(hours=1)
|
||||
return date_planned_finished
|
||||
|
||||
@@ -33,6 +33,10 @@ class ProductTemplate(models.Model):
|
||||
'Manufacturing Lead Time', default=0.0,
|
||||
help="Average lead time in days to manufacture this product. In the case of multi-level BOM, the manufacturing lead times of the components will be added. In case the product is subcontracted, this can be used to determine the date at which components should be sent to the subcontractor.")
|
||||
is_kits = fields.Boolean(compute='_compute_is_kits', compute_sudo=False)
|
||||
days_to_prepare_mo = fields.Float(
|
||||
string="Days to prepare Manufacturing Order", default=0.0,
|
||||
help="Create and confirm Manufacturing Orders these many days in advance, to have enough time to replenish components or manufacture semi-finished products.\n"
|
||||
"Note that this does not affect the MO scheduled date, which still respects the just-in-time mechanism.")
|
||||
|
||||
def _compute_bom_count(self):
|
||||
for product in self:
|
||||
|
||||
@@ -2,6 +2,7 @@
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from collections import defaultdict
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from odoo import api, Command, fields, models
|
||||
from odoo.osv import expression
|
||||
from odoo.tools import float_compare, float_round, float_is_zero, OrderedSet
|
||||
@@ -547,3 +548,9 @@ class StockMove(models.Model):
|
||||
res = super()._prepare_procurement_values()
|
||||
res['bom_line_id'] = self.bom_line_id.id
|
||||
return res
|
||||
|
||||
def _get_mto_procurement_date(self):
|
||||
date = super()._get_mto_procurement_date()
|
||||
if 'manufacture' in self.product_id._get_rules_from_location(self.location_id).mapped('action'):
|
||||
date -= relativedelta(days=self.company_id.manufacturing_lead)
|
||||
return date
|
||||
|
||||
@@ -4,6 +4,7 @@
|
||||
from odoo import _, api, fields, models
|
||||
from odoo.tools.float_utils import float_is_zero
|
||||
from odoo.osv.expression import AND
|
||||
from dateutil.relativedelta import relativedelta
|
||||
|
||||
|
||||
class StockWarehouseOrderpoint(models.Model):
|
||||
@@ -13,6 +14,7 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
bom_id = fields.Many2one(
|
||||
'mrp.bom', string='Bill of Materials', check_company=True,
|
||||
domain="[('type', '=', 'normal'), '&', '|', ('company_id', '=', company_id), ('company_id', '=', False), '|', ('product_id', '=', product_id), '&', ('product_id', '=', False), ('product_tmpl_id', '=', product_tmpl_id)]")
|
||||
manufacturing_visibility_days = fields.Float(default=0.0, help="Visibility Days applied on the manufacturing routes.")
|
||||
|
||||
def _get_replenishment_order_notification(self):
|
||||
self.ensure_one()
|
||||
@@ -45,6 +47,27 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
for orderpoint in self:
|
||||
orderpoint.show_bom = orderpoint.route_id.id in manufacture_route
|
||||
|
||||
def _compute_visibility_days(self):
|
||||
res = super()._compute_visibility_days()
|
||||
for orderpoint in self:
|
||||
if 'manufacture' in orderpoint.rule_ids.mapped('action'):
|
||||
orderpoint.visibility_days = orderpoint.manufacturing_visibility_days
|
||||
return res
|
||||
|
||||
def _set_visibility_days(self):
|
||||
res = super()._set_visibility_days()
|
||||
for orderpoint in self:
|
||||
if 'manufacture' in orderpoint.rule_ids.mapped('action'):
|
||||
orderpoint.manufacturing_visibility_days = orderpoint.visibility_days
|
||||
return res
|
||||
|
||||
def _compute_days_to_order(self):
|
||||
res = super()._compute_days_to_order()
|
||||
for orderpoint in self:
|
||||
if 'manufacture' in orderpoint.rule_ids.mapped('action'):
|
||||
orderpoint.days_to_order = orderpoint.product_id.days_to_prepare_mo
|
||||
return res
|
||||
|
||||
def _quantity_in_progress(self):
|
||||
bom_kits = self.env['mrp.bom']._bom_find(self.product_id, bom_type='phantom')
|
||||
bom_kit_orderpoints = {
|
||||
@@ -109,6 +132,12 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
orderpoint_wh_bom.route_id = route_id[0].id
|
||||
return super()._set_default_route_id()
|
||||
|
||||
def _get_orderpoint_procurement_date(self):
|
||||
date = super()._get_orderpoint_procurement_date()
|
||||
if any(rule.action == 'manufacture' for rule in self.rule_ids):
|
||||
date -= relativedelta(days=self.company_id.manufacturing_lead)
|
||||
return date
|
||||
|
||||
def _prepare_procurement_values(self, date=False, group=False):
|
||||
values = super()._prepare_procurement_values(date=date, group=group)
|
||||
values['bom_id'] = self.bom_id
|
||||
|
||||
@@ -109,7 +109,7 @@ class StockRule(models.Model):
|
||||
|
||||
def _prepare_mo_vals(self, product_id, product_qty, product_uom, location_dest_id, name, origin, company_id, values, bom):
|
||||
date_planned = self._get_date_planned(product_id, company_id, values)
|
||||
date_deadline = values.get('date_deadline') or date_planned + relativedelta(days=company_id.manufacturing_lead) + relativedelta(days=product_id.produce_delay)
|
||||
date_deadline = values.get('date_deadline') or date_planned + relativedelta(days=product_id.produce_delay)
|
||||
mo_values = {
|
||||
'origin': origin,
|
||||
'product_id': product_id.id,
|
||||
@@ -144,7 +144,6 @@ class StockRule(models.Model):
|
||||
def _get_date_planned(self, product_id, company_id, values):
|
||||
format_date_planned = fields.Datetime.from_string(values['date_planned'])
|
||||
date_planned = format_date_planned - relativedelta(days=product_id.produce_delay)
|
||||
date_planned = date_planned - relativedelta(days=company_id.manufacturing_lead)
|
||||
if date_planned == format_date_planned:
|
||||
date_planned = date_planned - relativedelta(hours=1)
|
||||
return date_planned
|
||||
|
||||
@@ -12,6 +12,10 @@
|
||||
<div attrs="{'invisible':[('type','=','service')]}">
|
||||
<field name="produce_delay" class="oe_inline"/> days
|
||||
</div>
|
||||
<label for="days_to_prepare_mo" attrs="{'invisible':[('type','=','service')]}"/>
|
||||
<div attrs="{'invisible':[('type','=','service')]}">
|
||||
<field name="days_to_prepare_mo" class="oe_inline"/> days
|
||||
</div>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='product_variant_count']" position="after">
|
||||
<field name="is_kits" invisible="1"/>
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||
|
||||
from dateutil.relativedelta import relativedelta
|
||||
from odoo import _, models
|
||||
from odoo.tools.float_utils import float_is_zero
|
||||
from odoo.exceptions import UserError
|
||||
@@ -30,3 +31,9 @@ class StockMove(models.Model):
|
||||
if float_is_zero(valuation_total_qty, precision_rounding=related_aml.product_uom_id.rounding or related_aml.product_id.uom_id.rounding):
|
||||
raise UserError(_('Odoo is not able to generate the anglo saxon entries. The total valuation of %s is zero.') % related_aml.product_id.display_name)
|
||||
return valuation_price_unit_total, valuation_total_qty
|
||||
|
||||
def _get_mto_procurement_date(self):
|
||||
date = super()._get_mto_procurement_date()
|
||||
if 'buy' in self.product_id._get_rules_from_location(self.location_id).mapped('action'):
|
||||
date -= relativedelta(days=self.company_id.po_lead)
|
||||
return date
|
||||
|
||||
@@ -4,8 +4,8 @@
|
||||
from . import account_invoice
|
||||
from . import product
|
||||
from . import purchase
|
||||
from . import res_company
|
||||
from . import res_config_settings
|
||||
from . import res_partner
|
||||
from . import res_company
|
||||
from . import stock
|
||||
from . import stock_rule
|
||||
|
||||
@@ -10,7 +10,6 @@ class ResConfigSettings(models.TransientModel):
|
||||
module_stock_dropshipping = fields.Boolean("Dropshipping")
|
||||
days_to_purchase = fields.Float(
|
||||
related='company_id.days_to_purchase', readonly=False)
|
||||
|
||||
is_installed_sale = fields.Boolean(string="Is the Sale Module Installed")
|
||||
|
||||
def get_values(self):
|
||||
|
||||
@@ -215,6 +215,7 @@ class Orderpoint(models.Model):
|
||||
'product.supplierinfo', string='Product Supplier', check_company=True,
|
||||
domain="['|', ('product_id', '=', product_id), '&', ('product_id', '=', False), ('product_tmpl_id', '=', product_tmpl_id)]")
|
||||
vendor_id = fields.Many2one(related='supplier_id.partner_id', string="Vendor", store=True)
|
||||
purchase_visibility_days = fields.Float(default=0.0, help="Visibility Days applied on the purchase routes.")
|
||||
|
||||
@api.depends('product_id.purchase_order_line_ids', 'product_id.purchase_order_line_ids.state')
|
||||
def _compute_qty(self):
|
||||
@@ -225,6 +226,26 @@ class Orderpoint(models.Model):
|
||||
def _compute_lead_days(self):
|
||||
return super()._compute_lead_days()
|
||||
|
||||
def _compute_visibility_days(self):
|
||||
res = super()._compute_visibility_days()
|
||||
for orderpoint in self:
|
||||
if 'buy' in orderpoint.rule_ids.mapped('action'):
|
||||
orderpoint.visibility_days = orderpoint.purchase_visibility_days
|
||||
return res
|
||||
|
||||
def _set_visibility_days(self):
|
||||
res = super()._set_visibility_days()
|
||||
for orderpoint in self:
|
||||
if 'buy' in orderpoint.rule_ids.mapped('action'):
|
||||
orderpoint.purchase_visibility_days = orderpoint.visibility_days
|
||||
return res
|
||||
|
||||
def _compute_days_to_order(self):
|
||||
res = super()._compute_days_to_order()
|
||||
for orderpoint in self:
|
||||
if 'buy' in orderpoint.rule_ids.mapped('action'):
|
||||
orderpoint.days_to_order = orderpoint.company_id.days_to_purchase
|
||||
return res
|
||||
@api.depends('route_id')
|
||||
def _compute_show_suppplier(self):
|
||||
buy_route = []
|
||||
|
||||
@@ -152,9 +152,8 @@ class StockRule(models.Model):
|
||||
self.env['purchase.order.line'].sudo().create(po_line_values)
|
||||
|
||||
def _get_lead_days(self, product, **values):
|
||||
"""Add the company security lead time, days to purchase and the supplier
|
||||
delay to the cumulative delay and cumulative description. The days to
|
||||
purchase and company lead time are always displayed for onboarding
|
||||
"""Add the company security lead time and the supplier delay to the cumulative delay
|
||||
and cumulative description. The company lead time is always displayed for onboarding
|
||||
purpose in order to indicate that those options are available.
|
||||
"""
|
||||
delay, delay_description = super()._get_lead_days(product, **values)
|
||||
@@ -170,10 +169,7 @@ class StockRule(models.Model):
|
||||
security_delay = buy_rule.picking_type_id.company_id.po_lead
|
||||
if not bypass_delay_description:
|
||||
delay_description.append((_('Purchase Security Lead Time'), _('+ %d day(s)', security_delay)))
|
||||
days_to_purchase = buy_rule.company_id.days_to_purchase
|
||||
if not bypass_delay_description:
|
||||
delay_description.append((_('Days to Purchase'), _('+ %d day(s)', days_to_purchase)))
|
||||
return delay + supplier_delay + security_delay + days_to_purchase, delay_description
|
||||
return delay + supplier_delay + security_delay, delay_description
|
||||
|
||||
@api.model
|
||||
def _get_procurements_to_merge_groupby(self, procurement):
|
||||
|
||||
@@ -296,6 +296,7 @@ class TestPurchaseLeadTime(PurchaseTestCommon):
|
||||
orderpoint_form = Form(self.env['stock.warehouse.orderpoint'])
|
||||
orderpoint_form.product_id = product
|
||||
orderpoint_form.product_min_qty = 0.0
|
||||
orderpoint_form.visibility_days = 1.0
|
||||
orderpoint = orderpoint_form.save()
|
||||
|
||||
orderpoint_form = Form(self.env['stock.warehouse.orderpoint'].with_company(company2))
|
||||
@@ -320,12 +321,12 @@ class TestPurchaseLeadTime(PurchaseTestCommon):
|
||||
po_line = self.env['purchase.order.line'].search([('product_id', '=', product.id)])
|
||||
self.assertEqual(fields.Date.to_date(po_line.order_id.date_order), fields.Date.today() + timedelta(days=2))
|
||||
self.assertEqual(len(po_line), 1)
|
||||
self.assertEqual(po_line.product_uom_qty, 20.0)
|
||||
self.assertEqual(po_line.product_uom_qty, 25.0)
|
||||
self.assertEqual(len(po_line.order_id), 1)
|
||||
orderpoint_form = Form(orderpoint)
|
||||
orderpoint_form.save()
|
||||
|
||||
self.mock_date.today.return_value = fields.Date.today() + timedelta(days=1)
|
||||
self.mock_date.today.return_value = fields.Date.today() + timedelta(days=2)
|
||||
orderpoint._compute_qty()
|
||||
self.env['procurement.group'].run_scheduler()
|
||||
po_line = self.env['purchase.order.line'].search([('product_id', '=', product.id)])
|
||||
|
||||
@@ -1283,7 +1283,7 @@ class StockMove(models.Model):
|
||||
product_id = self.product_id.with_context(lang=self._get_lang())
|
||||
return {
|
||||
'product_description_variants': self.description_picking and self.description_picking.replace(product_id._get_description(self.picking_type_id), ''),
|
||||
'date_planned': self.date,
|
||||
'date_planned': self._get_mto_procurement_date(),
|
||||
'date_deadline': self.date_deadline,
|
||||
'move_dest_ids': self,
|
||||
'group_id': group_id,
|
||||
@@ -1294,6 +1294,9 @@ class StockMove(models.Model):
|
||||
'product_packaging_id': self.product_packaging_id,
|
||||
}
|
||||
|
||||
def _get_mto_procurement_date(self):
|
||||
return self.date
|
||||
|
||||
def _prepare_move_line_vals(self, quantity=None, reserved_quant=None):
|
||||
self.ensure_one()
|
||||
vals = {
|
||||
|
||||
@@ -97,6 +97,12 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
qty_forecast = fields.Float('Forecast', readonly=True, compute='_compute_qty')
|
||||
qty_to_order = fields.Float('To Order', compute='_compute_qty_to_order', store=True, readonly=False)
|
||||
|
||||
days_to_order = fields.Float(compute='_compute_days_to_order', help="Numbers of days in advance that replenishments demands are created.")
|
||||
visibility_days = fields.Float(
|
||||
compute='_compute_visibility_days', inverse='_set_visibility_days', readonly=False,
|
||||
help="Consider product forecast these many days in the future upon product replenishment, set to 0 for just-in-time.\n"
|
||||
"The value depends on the type of the route (Buy or Manufacture)")
|
||||
|
||||
_sql_constraints = [
|
||||
('qty_multiple_check', 'CHECK( qty_multiple >= 0 )', 'Qty Multiple must be greater than or equal to zero.'),
|
||||
('product_location_check', 'unique (product_id, location_id, company_id)', 'A replenishment rule already exists for this product on this location.'),
|
||||
@@ -134,6 +140,17 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
continue
|
||||
orderpoint.rule_ids = orderpoint.product_id._get_rules_from_location(orderpoint.location_id, route_ids=orderpoint.route_id)
|
||||
|
||||
@api.depends('route_id', 'product_id')
|
||||
def _compute_visibility_days(self):
|
||||
self.visibility_days = 0
|
||||
|
||||
def _set_visibility_days(self):
|
||||
return True
|
||||
|
||||
@api.depends('route_id', 'product_id')
|
||||
def _compute_days_to_order(self):
|
||||
self.days_to_order = 0
|
||||
|
||||
@api.constrains('product_id')
|
||||
def _check_product_uom(self):
|
||||
''' Check if the UoM has the same category as the product standard UoM '''
|
||||
@@ -251,7 +268,7 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
orderpoint.qty_on_hand = products_qty[orderpoint.product_id.id]['qty_available']
|
||||
orderpoint.qty_forecast = products_qty[orderpoint.product_id.id]['virtual_available'] + products_qty_in_progress[orderpoint.id]
|
||||
|
||||
@api.depends('qty_multiple', 'qty_forecast', 'product_min_qty', 'product_max_qty')
|
||||
@api.depends('qty_multiple', 'qty_forecast', 'product_min_qty', 'product_max_qty', 'visibility_days')
|
||||
def _compute_qty_to_order(self):
|
||||
for orderpoint in self:
|
||||
if not orderpoint.product_id or not orderpoint.location_id:
|
||||
@@ -260,8 +277,10 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
qty_to_order = 0.0
|
||||
rounding = orderpoint.product_uom.rounding
|
||||
if float_compare(orderpoint.qty_forecast, orderpoint.product_min_qty, precision_rounding=rounding) < 0:
|
||||
qty_to_order = max(orderpoint.product_min_qty, orderpoint.product_max_qty) - orderpoint.qty_forecast
|
||||
|
||||
# We want to know how much we should order to also satisfy the needs that gonna appear in the next (visibility) days
|
||||
product_context = orderpoint._get_product_context(visibility_days=orderpoint.visibility_days)
|
||||
qty_forecast_with_visibility = orderpoint.product_id.with_context(product_context).read(['virtual_available'])[0]['virtual_available'] + orderpoint._quantity_in_progress()[orderpoint.id]
|
||||
qty_to_order = max(orderpoint.product_min_qty, orderpoint.product_max_qty) - qty_forecast_with_visibility
|
||||
remainder = orderpoint.qty_multiple > 0 and qty_to_order % orderpoint.qty_multiple or 0.0
|
||||
if float_compare(remainder, 0.0, precision_rounding=rounding) > 0:
|
||||
qty_to_order += orderpoint.qty_multiple - remainder
|
||||
@@ -291,14 +310,16 @@ class StockWarehouseOrderpoint(models.Model):
|
||||
|
||||
def _get_lead_days_values(self):
|
||||
self.ensure_one()
|
||||
return dict()
|
||||
return {
|
||||
'days_to_order': self.days_to_order,
|
||||
}
|
||||
|
||||
def _get_product_context(self):
|
||||
def _get_product_context(self, visibility_days=0):
|
||||
"""Used to call `virtual_available` when running an orderpoint."""
|
||||
self.ensure_one()
|
||||
return {
|
||||
'location': self.location_id.id,
|
||||
'to_date': datetime.combine(self.lead_days_date, time.max)
|
||||
'to_date': datetime.combine(self.lead_days_date + relativedelta.relativedelta(days=visibility_days), time.max)
|
||||
}
|
||||
|
||||
def _get_orderpoint_action(self):
|
||||
|
||||
@@ -350,6 +350,7 @@ class StockRule(models.Model):
|
||||
:rtype: tuple[int, list[str, str]]
|
||||
"""
|
||||
delay = sum(self.filtered(lambda r: r.action in ['pull', 'pull_push']).mapped('delay'))
|
||||
days_to_order = values.get('days_to_order', 0)
|
||||
if self.env.context.get('bypass_delay_description'):
|
||||
delay_description = []
|
||||
else:
|
||||
@@ -358,7 +359,8 @@ class StockRule(models.Model):
|
||||
for rule in self
|
||||
if rule.action in ['pull', 'pull_push'] and rule.delay
|
||||
]
|
||||
return delay, delay_description
|
||||
delay_description.append((_('Days to Order'), _('+ %d day(s)', days_to_order)))
|
||||
return delay + days_to_order, delay_description
|
||||
|
||||
|
||||
class ProcurementGroup(models.Model):
|
||||
|
||||
@@ -48,6 +48,7 @@
|
||||
<field name="qty_on_hand" force_save="1"/>
|
||||
<field name="qty_forecast" force_save="1"/>
|
||||
<button name="action_product_forecast_report" type="object" icon="fa-area-chart" title="Forecast Report" attrs="{'invisible': [('id', '=', False)]}"/>
|
||||
<field name="visibility_days" optional="hidden"/>
|
||||
<field name="route_id" options="{'no_create': True, 'no_open': True}"/>
|
||||
<button name="action_stock_replenishment_info" type="object" icon="fa-info-circle" title="Resplenishment Information" attrs="{'invisible': [('id', '=', False)]}"/>
|
||||
<field name="trigger" optional="hide"/>
|
||||
@@ -68,29 +69,6 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_warehouse_orderpoint_tree_editable_config" model="ir.ui.view">
|
||||
<field name="name">stock.warehouse.orderpoint.tree.editable.config</field>
|
||||
<field name="model">stock.warehouse.orderpoint</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="Reordering Rules" editable="bottom">
|
||||
<field name="active" invisible="1"/>
|
||||
<field name="warehouse_id" invisible="1"/>
|
||||
<field name="product_tmpl_id" invisible="1"/>
|
||||
<field name="product_id" invisible="context.get('default_product_id')" force_save="1"/>
|
||||
<field name="location_id" options="{'no_create': True}" groups="stock.group_stock_multi_locations"/>
|
||||
<field name="route_id" optional="hide"/>
|
||||
<field name="trigger" optional="hide"/>
|
||||
<field name="group_id" optional="hide" groups="stock.group_adv_location"/>
|
||||
<field name="product_min_qty" optional="show"/>
|
||||
<field name="product_max_qty" optional="show"/>
|
||||
<field name="qty_multiple" optional="show"/>
|
||||
<button name="stock.action_stock_replenishment_info" string="Forecast Description" type="action" icon="fa-area-chart" attrs="{'invisible': [('id', '=', False)]}"/>
|
||||
<field name="product_uom_name" string="UoM" groups="uom.group_uom"/>
|
||||
<field name="company_id" optional="hide" readonly="1" groups="base.group_multi_company"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="stock_reorder_report_search">
|
||||
<field name="name">stock.warehouse.orderpoint.reorder.search</field>
|
||||
<field name="model">stock.warehouse.orderpoint</field>
|
||||
@@ -182,6 +160,7 @@
|
||||
<field name="group_id" groups="stock.group_adv_location"/>
|
||||
</div>
|
||||
<field name="company_id" groups="base.group_multi_company" options="{'no_create': True}"/>
|
||||
<field name="visibility_days"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
@@ -212,7 +191,7 @@
|
||||
<field name="res_model">stock.warehouse.orderpoint</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="view_mode">tree,kanban,form</field>
|
||||
<field name="view_id" ref="view_warehouse_orderpoint_tree_editable_config"/>
|
||||
<field name="view_id" ref="view_warehouse_orderpoint_tree_editable"/>
|
||||
<field name="search_view_id" ref="warehouse_orderpoint_search"/>
|
||||
<field name="context">{'search_default_trigger': 'auto'}</field>
|
||||
<field name="help" type="html">
|
||||
|
||||
Reference in New Issue
Block a user