[11.0][MIG] mrp_mto_with_stock

This commit is contained in:
Bhavesh Odedra
2018-02-16 22:40:25 +05:30
parent d8b06747b6
commit dab59bcc21
13 changed files with 203 additions and 224 deletions

View File

@@ -29,6 +29,7 @@ To configure this module, you need to:
standard behavior.
If you want to use the second mode, based on forecast quantity
#. Go to the warehouse you want to follow this behaviour.
#. In the view form go to the tab *Warehouse Configuration* and set the
*MRP MTO with forecast stock*. You still need to configure the products
@@ -44,7 +45,7 @@ To use this module, you need to:
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/129/10.0
:target: https://runbot.odoo-community.org/runbot/129/11.0
Bug Tracker
===========
@@ -68,6 +69,7 @@ Contributors
* John Walsh <John.Walsh@interclean.com>
* Lois Rilo <lois.rilo@eficent.com>
* Florian da Costa <florian.dacosta@akretion.com>
* Bhavesh Odedra <bodedra@opensourceintegrators.com>
Maintainer
----------

View File

@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# Copyright 2015 John Walsh
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import models

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# Copyright 2015 John Walsh
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -10,11 +9,11 @@
"author": "John Walsh, Eficent, Odoo Community Association (OCA)",
"website": "https://odoo-community.org/",
"category": "Manufacturing",
"version": "10.0.1.0.0",
"version": "11.0.1.0.0",
"license": "AGPL-3",
"application": False,
"installable": True,
"depends": ["mrp"],
"depends": ["stock", "sale", "purchase", "mrp"],
"data": [
'views/product_template_view.xml',
'views/stock_warehouse.xml',

View File

@@ -1,128 +1,123 @@
<?xml version="1.0" encoding="UTF-8"?>
<?xml version="1.0"?>
<!--
Copyright (C) 2017 - Today: GRAP (http://www.grap.coop)
@author Sylvain LE GAL (https://twitter.com/legalsylvain)
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl.html).
-->
<odoo> <data noupdate="1">
<odoo noupdate="1">
<record id="product_product_manufacture_1" model="product.product">
<field name="name">TOP</field>
<field name="categ_id" ref="product.product_category_3"/>
<field name="standard_price">600.00</field>
<field name="list_price">400.00</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description">TODO</field>
<field name="default_code">MANUF</field>
<field name="route_ids" eval="[(6, 0, [ref('stock.route_warehouse0_mto'), ref('mrp.route_warehouse0_manufacture')])]"/>
</record>
<record id="product_product_manufacture_1" model="product.product">
<field name="name">TOP</field>
<field name="categ_id" ref="product.product_category_3"/>
<field name="standard_price">600.00</field>
<field name="list_price">400.00</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description">TODO</field>
<field name="default_code">MANUF</field>
<field name="route_ids" eval="[(6, 0, [ref('stock.route_warehouse0_mto'), ref('mrp.route_warehouse0_manufacture')])]"/>
</record>
<record id="product_product_manufacture_1_1" model="product.product">
<field name="name">Subproduct 1</field>
<field name="categ_id" ref="product.product_category_3"/>
<field name="standard_price">300.00</field>
<field name="list_price">100.00</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description">TODO</field>
<field name="default_code">MANUF 1-1</field>
<field name="route_ids" eval="[(6, 0, [ref('mrp.route_warehouse0_manufacture')])]"/>
<field name="mrp_mts_mto_location_ids" eval="[(6, 0, [ref('stock.stock_location_stock')])]"/>
</record>
<record id="product_product_manufacture_1_1" model="product.product">
<field name="name">Subproduct 1</field>
<field name="categ_id" ref="product.product_category_3"/>
<field name="standard_price">300.00</field>
<field name="list_price">100.00</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description">TODO</field>
<field name="default_code">MANUF 1-1</field>
<field name="route_ids" eval="[(6, 0, [ref('mrp.route_warehouse0_manufacture')])]"/>
<field name="mrp_mts_mto_location_ids" eval="[(6, 0, [ref('stock.stock_location_stock')])]"/>
</record>
<record id="product_product_manufacture_1_2" model="product.product">
<field name="name">Subproduct 2</field>
<field name="categ_id" ref="product.product_category_3"/>
<field name="standard_price">100.00</field>
<field name="list_price">30.00</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description">TODO</field>
<field name="default_code">MANUF 1-2</field>
<field name="route_ids" eval="[(6, 0, [ref('mrp.route_warehouse0_manufacture')])]"/>
<field name="mrp_mts_mto_location_ids" eval="[(6, 0, [ref('stock.stock_location_stock')])]"/>
</record>
<record id="product_product_manufacture_1_2" model="product.product">
<field name="name">Subproduct 2</field>
<field name="categ_id" ref="product.product_category_3"/>
<field name="standard_price">100.00</field>
<field name="list_price">30.00</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description">TODO</field>
<field name="default_code">MANUF 1-2</field>
<field name="route_ids" eval="[(6, 0, [ref('mrp.route_warehouse0_manufacture')])]"/>
<field name="mrp_mts_mto_location_ids" eval="[(6, 0, [ref('stock.stock_location_stock')])]"/>
</record>
<record id="product_product_manufacture_1_1_1" model="product.product">
<field name="name">Subproduct 1-1</field>
<field name="categ_id" ref="product.product_category_3"/>
<field name="standard_price">10.00</field>
<field name="list_price">3.00</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description">TODO</field>
<field name="default_code">MANUF 1-1-1</field>
</record>
<record id="product_product_manufacture_1_1_1" model="product.product">
<field name="name">Subproduct 1-1</field>
<field name="categ_id" ref="product.product_category_3"/>
<field name="standard_price">10.00</field>
<field name="list_price">3.00</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description">TODO</field>
<field name="default_code">MANUF 1-1-1</field>
</record>
<record id="product_product_manufacture_1_2_1" model="product.product">
<field name="name">Subproduct 2-1</field>
<field name="categ_id" ref="product.product_category_3"/>
<field name="standard_price">10.00</field>
<field name="list_price">3.00</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description">TODO</field>
<field name="default_code">MANUF 1-2-1</field>
</record>
<record id="mrp_bom_manuf_1" model="mrp.bom">
<field name="product_tmpl_id" ref="product_product_manufacture_1_product_template"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">10</field>
</record>
<record id="product_product_manufacture_1_2_1" model="product.product">
<field name="name">Subproduct 2-1</field>
<field name="categ_id" ref="product.product_category_3"/>
<field name="standard_price">10.00</field>
<field name="list_price">3.00</field>
<field name="type">product</field>
<field name="uom_id" ref="product.product_uom_unit"/>
<field name="uom_po_id" ref="product.product_uom_unit"/>
<field name="description">TODO</field>
<field name="default_code">MANUF 1-2-1</field>
</record>
<record id="mrp_bom_line_manuf_1_1" model="mrp.bom.line">
<field name="product_id" ref="product_product_manufacture_1_1"/>
<field name="product_qty">5</field>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">1</field>
<field name="bom_id" ref="mrp_bom_manuf_1"/>
</record>
<record id="mrp_bom_line_manuf_1_2" model="mrp.bom.line">
<field name="product_id" ref="product_product_manufacture_1_2"/>
<field name="product_qty">2</field>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">1</field>
<field name="bom_id" ref="mrp_bom_manuf_1"/>
</record>
<record id="mrp_bom_manuf_1" model="mrp.bom">
<field name="product_tmpl_id" ref="product_product_manufacture_1_product_template"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">10</field>
</record>
<record id="mrp_bom_manuf_1_1" model="mrp.bom">
<field name="product_tmpl_id" ref="product_product_manufacture_1_1_product_template"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">10</field>
</record>
<record id="mrp_bom_line_manuf_1_1" model="mrp.bom.line">
<field name="product_id" ref="product_product_manufacture_1_1"/>
<field name="product_qty">5</field>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">1</field>
<field name="bom_id" ref="mrp_bom_manuf_1"/>
</record>
<record id="mrp_bom_line_manuf_1_1_1" model="mrp.bom.line">
<field name="product_id" ref="product_product_manufacture_1_1_1"/>
<field name="product_qty">2</field>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">1</field>
<field name="bom_id" ref="mrp_bom_manuf_1_1"/>
</record>
<record id="mrp_bom_line_manuf_1_2" model="mrp.bom.line">
<field name="product_id" ref="product_product_manufacture_1_2"/>
<field name="product_qty">2</field>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">1</field>
<field name="bom_id" ref="mrp_bom_manuf_1"/>
</record>
<record id="mrp_bom_manuf_1_2" model="mrp.bom">
<field name="product_tmpl_id" ref="product_product_manufacture_1_2_product_template"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">10</field>
</record>
<record id="mrp_bom_manuf_1_1" model="mrp.bom">
<field name="product_tmpl_id" ref="product_product_manufacture_1_1_product_template"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">10</field>
</record>
<record id="mrp_bom_line_manuf_1_1_1" model="mrp.bom.line">
<field name="product_id" ref="product_product_manufacture_1_1_1"/>
<field name="product_qty">2</field>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">1</field>
<field name="bom_id" ref="mrp_bom_manuf_1_1"/>
</record>
<record id="mrp_bom_manuf_1_2" model="mrp.bom">
<field name="product_tmpl_id" ref="product_product_manufacture_1_2_product_template"/>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">10</field>
</record>
<record id="mrp_bom_line_manuf_1_2_1" model="mrp.bom.line">
<field name="product_id" ref="product_product_manufacture_1_2_1"/>
<field name="product_qty">4</field>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">1</field>
<field name="bom_id" ref="mrp_bom_manuf_1_2"/>
</record>
</data> </odoo>
<record id="mrp_bom_line_manuf_1_2_1" model="mrp.bom.line">
<field name="product_id" ref="product_product_manufacture_1_2_1"/>
<field name="product_qty">4</field>
<field name="product_uom_id" ref="product.product_uom_unit"/>
<field name="sequence">1</field>
<field name="bom_id" ref="mrp_bom_manuf_1_2"/>
</record>
</odoo>

View File

@@ -1,6 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# Copyright 2015 John Walsh
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import mrp_production

View File

@@ -1,9 +1,9 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# Copyright 2015 John Walsh
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from odoo import api, models
from odoo.exceptions import UserError
import logging
_logger = logging.getLogger(__name__)
@@ -11,10 +11,9 @@ _logger = logging.getLogger(__name__)
class MrpProduction(models.Model):
_inherit = 'mrp.production'
@api.multi
def _adjust_procure_method(self):
# Si location => By pass method...
super(MrpProduction, self)._adjust_procure_method()
def _get_procurement_group_data(self, move):
return {'partner_id': move.partner_id.id,
'name': '{0}:{1}'.format(self.name, move.product_id.name)}
@api.multi
def action_assign(self):
@@ -26,78 +25,76 @@ class MrpProduction(models.Model):
res = super(MrpProduction, self).action_assign()
# try to create procurements:
move_obj = self.env['stock.move']
procurement_obj = self.env['procurement.group']
for production in self:
warehouse = production.location_src_id.get_warehouse()
mto_with_no_move_dest_id = warehouse.mrp_mto_mts_forecast_qty
for move in self.move_raw_ids:
if (move.state == 'confirmed' and move.location_id in
move.product_id.mrp_mts_mto_location_ids and not
mto_with_no_move_dest_id):
domain = [('product_id', '=', move.product_id.id),
('move_dest_id', '=', move.id)]
if move.group_id:
domain.append(('group_id', '=', move.group_id.id))
procurement = self.env['procurement.order'].search(domain)
group = new_move = procurement = False
qty_to_procure = 0.0
if move.state in ('partially_available', 'confirmed') \
and move.location_id in \
move.product_id.mrp_mts_mto_location_ids \
and not mto_with_no_move_dest_id:
# Search procurement group which has created from here
group_name = '{0}:{1}'.format(
production.name, move.product_id.name)
procurement = procurement_obj.search(
[('name', '=', group_name)])
if not procurement:
# We have to split the move because we can't have
# a part of the move that have ancestors and not the
# other else it won't ever be reserved.
qty_to_procure = (move.remaining_qty -
move.reserved_availability)
qty_to_procure = (
move.product_uom_qty - move.reserved_availability)
if qty_to_procure < move.product_uom_qty:
move.do_unreserve()
new_move_id = move.split(
move._do_unreserve()
new_move_id = move._split(
qty_to_procure,
restrict_lot_id=move.restrict_lot_id,
restrict_partner_id=move.restrict_partner_id)
new_move = move_obj.browse(
new_move_id)
move.action_assign()
new_move = move_obj.browse(new_move_id)
move._action_assign()
else:
new_move = move
proc_dict = self._prepare_mto_procurement(
new_move, qty_to_procure,
mto_with_no_move_dest_id)
self.env['procurement.order'].create(proc_dict)
if (move.state == 'confirmed' and move.location_id in
move.product_id.mrp_mts_mto_location_ids and
move.procure_method == 'make_to_stock' and
mto_with_no_move_dest_id):
pg_data = production._get_procurement_group_data(
new_move)
group = procurement_obj.create(pg_data)
if move.state in ('partially_available', 'confirmed') \
and move.procure_method == 'make_to_stock' \
and mto_with_no_move_dest_id and \
move.location_id in \
move.product_id.mrp_mts_mto_location_ids:
qty_to_procure = production.get_mto_qty_to_procure(move)
if qty_to_procure > 0.0:
proc_dict = self._prepare_mto_procurement(
move, qty_to_procure, mto_with_no_move_dest_id)
proc_dict.pop('move_dest_id', None)
self.env['procurement.order'].create(proc_dict)
pg_data = production._get_procurement_group_data(move)
group = procurement_obj.create(pg_data)
new_move = move
if group:
production.run_procurement(new_move, group, qty_to_procure)
return res
def _prepare_mto_procurement(self, move, qty, mto_with_no_move_dest_id):
"""Prepares a procurement for a MTO product."""
origin = ((move.group_id and move.group_id.name + ":") or "") + \
((move.name and move.name + ":") or "") + 'MTO -> Production'
group_id = move.group_id and move.group_id.id or False
route_ids = self.env.ref('stock.route_warehouse0_mto')
warehouse_id = (move.warehouse_id.id or (move.picking_type_id and
move.picking_type_id.warehouse_id.id or False))
vals = {
'name': move.name + ':' + str(move.id),
'origin': origin,
'company_id': move.company_id and move.company_id.id or False,
'date_planned': move.date,
'product_id': move.product_id.id,
'product_qty': qty,
'product_uom': move.product_uom.id,
'location_id': move.location_id.id,
'group_id': group_id,
'route_ids': [(6, 0, route_ids.ids)],
'warehouse_id': warehouse_id,
'priority': move.priority,
}
if not mto_with_no_move_dest_id:
vals['move_dest_id'] = move.id
return vals
@api.multi
def run_procurement(self, move, group, qty):
self.ensure_one()
errors = []
values = move._prepare_procurement_values()
origin = ((group and group.name + ":") or "") + 'MTO -> Production'
values['route_ids'] = move.product_id.route_ids
try:
self.env['procurement.group'].run(
move.product_id,
qty,
move.product_uom,
move.location_id,
origin,
origin,
values
)
except UserError as error:
errors.append(error.name)
if errors:
raise UserError('\n'.join(errors))
return True
@api.multi
def get_mto_qty_to_procure(self, move):

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Akretion
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.2 KiB

View File

@@ -1,5 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
from . import test_mrp_mto_with_stock

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).
@@ -10,6 +9,7 @@ class TestMrpMtoWithStock(TransactionCase):
def setUp(self, *args, **kwargs):
super(TestMrpMtoWithStock, self).setUp(*args, **kwargs)
self.production_model = self.env['mrp.production']
self.procurement_model = self.env['procurement.group']
self.bom_model = self.env['mrp.bom']
self.stock_location_stock = self.env.ref('stock.stock_location_stock')
self.manufacture_route = self.env.ref(
@@ -67,20 +67,12 @@ class TestMrpMtoWithStock(TransactionCase):
self.production.action_assign()
self.assertEqual(self.production.availability, 'partially_available')
self.assertEquals(self.subproduct1.virtual_available, 0)
procurement_subproduct1 = self.env['procurement.order'].search(
[('product_id', '=', self.subproduct1.id),
('group_id', '=', self.production.procurement_group_id.id)])
self.assertEquals(len(procurement_subproduct1), 1)
self.assertEquals(procurement_subproduct1.product_qty, 3)
production_sub1 = procurement_subproduct1.production_id
production_sub1 = self.production_model.search(
[('origin', 'ilike', self.production.name)])
self.assertEqual(production_sub1.state, 'confirmed')
self.assertEquals(len(production_sub1), 1)
self.assertEqual(production_sub1.product_qty, 3)
self._update_product_qty(self.subproduct1, self.stock_location_stock,
7)
@@ -88,20 +80,18 @@ class TestMrpMtoWithStock(TransactionCase):
self.production2 = self.production_model.create(
self._get_production_vals())
self.production2.action_assign()
procurement_subproduct1_2 = self.env['procurement.order'].search(
[('product_id', '=', self.subproduct1.id),
('group_id', '=', self.production2.procurement_group_id.id)])
self.assertEquals(len(procurement_subproduct1_2), 0)
p = self.production_model.search(
[('origin', 'ilike', self.production2.name)])
self.assertEquals(len(p), 0)
self.assertEquals(self.production2.availability, 'assigned')
self.production2.do_unreserve()
self.assertEquals(self.subproduct1.virtual_available, 0)
self.production.action_assign()
# We check if first MO is able to assign it self even if it has
# previously generate procurements, it would not be the case in the
# other mode (without mrp_mto_mts_reservable_stock on warehouse)
self.assertEquals(self.production.availability, 'assigned')
self.assertEquals(self.production.availability, 'partially_available')
self.assertEquals(self.subproduct1.virtual_available, 0)
@@ -126,33 +116,39 @@ class TestMrpMtoWithStock(TransactionCase):
# Create MO and check it create sub assemblie MO.
self.production.action_assign()
self.assertEqual(self.production.state, 'confirmed')
mo = self.production_model.search(
[('origin', 'ilike', self.production.name)])
self.assertEqual(mo.product_qty, 3)
procurement_sub1 = self.env['procurement.order'].search(
[('product_id', '=', self.subproduct1.id),
('move_dest_id', 'in', self.production.move_raw_ids.ids)])
self.assertEquals(len(procurement_sub1), 1)
mo.action_assign()
self.assertEqual(mo.availability, 'assigned')
wizard_obj = self.env['mrp.product.produce']
default_fields = ['lot_id', 'product_id', 'product_uom_id',
'product_tracking', 'consume_line_ids',
'production_id', 'product_qty', 'serial']
wizard_vals = wizard_obj.with_context(active_id=mo.id).\
default_get(default_fields)
wizard = wizard_obj.create(wizard_vals)
wizard.do_produce()
self.assertEqual(len(mo), 1)
mo.button_mark_done()
self.assertEqual(mo.availability, 'assigned')
self.assertEquals(self.subproduct1.qty_available, 5)
procurement_sub2 = self.env['procurement.order'].search(
[('product_id', '=', self.subproduct2.id),
('move_dest_id', 'in', self.production.move_raw_ids.ids)])
self.assertEquals(len(procurement_sub2), 0)
production_sub1 = procurement_sub1.production_id
self.assertEqual(production_sub1.product_qty, 3)
production_sub1.action_assign()
self.assertEqual(production_sub1.availability, 'assigned')
self.production.action_assign()
self.assertEqual(self.production.state, 'confirmed')
wizard_obj = self.env['mrp.product.produce']
default_fields = ['lot_id', 'product_id', 'product_uom_id',
'product_tracking', 'consume_line_ids',
'production_id', 'product_qty', 'serial']
wizard_vals = wizard_obj.with_context(active_id=production_sub1.id).\
wizard_vals = wizard_obj.with_context(active_id=self.production.id).\
default_get(default_fields)
wizard = wizard_obj.create(wizard_vals)
wizard.do_produce()
self.assertTrue(production_sub1.check_to_done)
self.assertEquals(self.subproduct1.qty_available, 2)
production_sub1.button_mark_done()
self.assertEquals(self.subproduct1.qty_available, 5)
self.assertEqual(self.production.availability, 'assigned')
self.assertTrue(self.production.check_to_done)
self.production.button_mark_done()
self.assertEqual(self.production.state, 'done')
self.assertEquals(self.subproduct2.qty_available, 2)

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0"?>
<!-- Copyright 2017 Eficent Business and IT Consulting Services S.L.
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->

View File

@@ -1,4 +1,4 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0"?>
<!-- Copyright 2017 Akretion
License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->