[IMP] stock_reserve: black, isort, prettier

This commit is contained in:
Carlos Roca
2021-07-23 12:23:01 +02:00
committed by Víctor Martínez
parent 03c1aa983e
commit f7df08dc6a
10 changed files with 407 additions and 384 deletions

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
@@ -19,25 +18,25 @@
#
##############################################################################
{'name': 'Stock Reservation',
'summary': 'Stock reservations on products',
'version': '10.0.1.0.0',
'author': "Camptocamp,Odoo Community Association (OCA)",
'category': 'Warehouse',
'license': 'AGPL-3',
'complexity': 'normal',
'images': [],
'website': "http://www.camptocamp.com",
'depends': ['stock',
],
'demo': [],
'data': ['view/stock_reserve.xml',
'view/product.xml',
'data/stock_data.xml',
'security/ir.model.access.csv',
],
'auto_install': False,
'test': ['test/stock_reserve.yml',
],
'installable': True,
}
{
"name": "Stock Reservation",
"summary": "Stock reservations on products",
"version": "10.0.1.0.0",
"author": "Camptocamp,Odoo Community Association (OCA)",
"category": "Warehouse",
"license": "AGPL-3",
"complexity": "normal",
"images": [],
"website": "http://www.camptocamp.com",
"depends": ["stock",],
"demo": [],
"data": [
"view/stock_reserve.xml",
"view/product.xml",
"data/stock_data.xml",
"security/ir.model.access.csv",
],
"auto_install": False,
"test": ["test/stock_reserve.yml",],
"installable": True,
}

View File

@@ -1,26 +1,29 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<data noupdate="1">
<record id="stock_location_reservation" model="stock.location">
<field name="name">Reservation Stock</field>
<field name="location_id" ref="stock.stock_location_locations"/>
</record>
<!-- Release the stock.reservation when the validity date has
<data noupdate="1">
<record id="stock_location_reservation" model="stock.location">
<field name="name">Reservation Stock</field>
<field name="location_id" ref="stock.stock_location_locations" />
</record>
<!-- Release the stock.reservation when the validity date has
passed -->
<record forcecreate="True" id="ir_cron_release_stock_reservation" model="ir.cron">
<field name="name">Release the stock reservation having a passed validity date</field>
<field eval="True" name="active" />
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
<field name="model">stock.reservation</field>
<field name="function">release_validity_exceeded</field>
<field name="args">()</field>
</record>
</data>
<record
forcecreate="True"
id="ir_cron_release_stock_reservation"
model="ir.cron"
>
<field
name="name"
>Release the stock reservation having a passed validity date</field>
<field eval="True" name="active" />
<field name="user_id" ref="base.user_root" />
<field name="interval_number">1</field>
<field name="interval_type">days</field>
<field name="numbercall">-1</field>
<field eval="False" name="doall" />
<field name="model">stock.reservation</field>
<field name="function">release_validity_exceeded</field>
<field name="args">()</field>
</record>
</data>
</odoo>

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
# Author: Leonardo Pistone
# Copyright 2015 Camptocamp SA
#
@@ -18,8 +17,9 @@
def migrate(cr, installed_version):
"""Update a wrong location that is no_update in XML."""
if installed_version == '8.0.0.1':
cr.execute('''
if installed_version == "8.0.0.1":
cr.execute(
"""
UPDATE stock_location
SET location_id = (
SELECT res_id
@@ -39,4 +39,5 @@ def migrate(cr, installed_version):
WHERE name = 'stock_location_company'
AND module = 'stock'
);
''')
"""
)

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
@@ -19,59 +18,62 @@
#
##############################################################################
from odoo import models, fields, api
from odoo import api, fields, models
class ProductTemplate(models.Model):
_inherit = 'product.template'
_inherit = "product.template"
reservation_count = fields.Float(
compute='_compute_reservation_count',
string='# Sales')
compute="_compute_reservation_count", string="# Sales"
)
@api.multi
def _compute_reservation_count(self):
for product in self:
product.reservation_count = sum(
product.product_variant_ids.mapped('reservation_count'))
product.product_variant_ids.mapped("reservation_count")
)
@api.multi
def action_view_reservations(self):
self.ensure_one()
ref = 'stock_reserve.action_stock_reservation_tree'
product_ids = self.mapped('product_variant_ids.id')
ref = "stock_reserve.action_stock_reservation_tree"
product_ids = self.mapped("product_variant_ids.id")
action_dict = self.env.ref(ref).read()[0]
action_dict['domain'] = [('product_id', 'in', product_ids)]
action_dict['context'] = {
'search_default_draft': 1,
'search_default_reserved': 1
}
action_dict["domain"] = [("product_id", "in", product_ids)]
action_dict["context"] = {
"search_default_draft": 1,
"search_default_reserved": 1,
}
return action_dict
class ProductProduct(models.Model):
_inherit = 'product.product'
_inherit = "product.product"
reservation_count = fields.Float(
compute='_compute_reservation_count',
string='# Sales')
compute="_compute_reservation_count", string="# Sales"
)
@api.multi
def _compute_reservation_count(self):
for product in self:
domain = [('product_id', '=', product.id),
('state', 'in', ['draft', 'assigned'])]
reservations = self.env['stock.reservation'].search(domain)
product.reservation_count = sum(reservations.mapped('product_qty'))
domain = [
("product_id", "=", product.id),
("state", "in", ["draft", "assigned"]),
]
reservations = self.env["stock.reservation"].search(domain)
product.reservation_count = sum(reservations.mapped("product_qty"))
@api.multi
def action_view_reservations(self):
self.ensure_one()
ref = 'stock_reserve.action_stock_reservation_tree'
ref = "stock_reserve.action_stock_reservation_tree"
action_dict = self.env.ref(ref).read()[0]
action_dict['domain'] = [('product_id', '=', self.id)]
action_dict['context'] = {
'search_default_draft': 1,
'search_default_reserved': 1
}
action_dict["domain"] = [("product_id", "=", self.id)]
action_dict["context"] = {
"search_default_draft": 1,
"search_default_reserved": 1,
}
return action_dict

View File

@@ -1,4 +1,3 @@
# -*- coding: utf-8 -*-
##############################################################################
#
# Author: Guewen Baconnier
@@ -19,7 +18,7 @@
#
##############################################################################
from odoo import models, fields, api
from odoo import api, fields, models
from odoo.exceptions import except_orm
from odoo.tools.translate import _
@@ -46,18 +45,20 @@ class StockReservation(models.Model):
* date_validity (once passed, the reservation will be released)
* note
"""
_name = 'stock.reservation'
_description = 'Stock Reservation'
_inherits = {'stock.move': 'move_id'}
_name = "stock.reservation"
_description = "Stock Reservation"
_inherits = {"stock.move": "move_id"}
move_id = fields.Many2one(
'stock.move',
'Reservation Move',
"stock.move",
"Reservation Move",
required=True,
readonly=True,
ondelete='cascade',
index=True)
date_validity = fields.Date('Validity Date')
ondelete="cascade",
index=True,
)
date_validity = fields.Date("Validity Date")
@api.model
def default_get(self, fields_list):
@@ -74,14 +75,13 @@ class StockReservation(models.Model):
# if there is 'location_id' field requested, ensure that
# picking_type_id is also requested, because it is required
# to compute location_id
if ('location_id' in fields_list and
'picking_type_id' not in fields_list):
fields_list = fields_list + ['picking_type_id']
if "location_id" in fields_list and "picking_type_id" not in fields_list:
fields_list = fields_list + ["picking_type_id"]
res = super(StockReservation, self).default_get(fields_list)
if 'product_qty' in res:
del res['product_qty']
if "product_qty" in res:
del res["product_qty"]
# At this point picking_type_id and location_id
# should be computed in default way:
@@ -93,19 +93,20 @@ class StockReservation(models.Model):
#
# If picking_type_id is present and location_id is not, try to find
# default value for location_id
if not res.get('picking_type_id', None):
res['picking_type_id'] = self._default_picking_type_id()
if not res.get("picking_type_id", None):
res["picking_type_id"] = self._default_picking_type_id()
picking_type_id = res.get('picking_type_id')
if picking_type_id and not res.get('location_id', False):
picking = self.env['stock.picking'].new(
{'picking_type_id': picking_type_id})
picking_type_id = res.get("picking_type_id")
if picking_type_id and not res.get("location_id", False):
picking = self.env["stock.picking"].new(
{"picking_type_id": picking_type_id}
)
picking.onchange_picking_type()
res['location_id'] = picking.location_id.id
if 'location_dest_id' in fields_list:
res['location_dest_id'] = self._default_location_dest_id()
if 'product_uom_qty' in fields_list:
res['product_uom_qty'] = 1.0
res["location_id"] = picking.location_id.id
if "location_dest_id" in fields_list:
res["location_dest_id"] = self._default_location_dest_id()
if "product_uom_qty" in fields_list:
res["product_uom_qty"] = 1.0
return res
@api.model
@@ -115,7 +116,7 @@ class StockReservation(models.Model):
"""
try:
location = self.env.ref(ref, raise_if_not_found=True)
location.check_access_rule('read')
location.check_access_rule("read")
location_id = location.id
except (except_orm, ValueError):
location_id = False
@@ -123,12 +124,12 @@ class StockReservation(models.Model):
@api.model
def _default_picking_type_id(self):
ref = 'stock.picking_type_out'
ref = "stock.picking_type_out"
return self.env.ref(ref, raise_if_not_found=False).id
@api.model
def _default_location_dest_id(self):
ref = 'stock_reserve.stock_location_reservation'
ref = "stock_reserve.stock_location_reservation"
return self.get_location_from_ref(ref)
@api.multi
@@ -138,9 +139,9 @@ class StockReservation(models.Model):
The reservation is done using the default UOM of the product.
A date until which the product is reserved can be specified.
"""
self.write({'date_expected': fields.Datetime.now()})
self.mapped('move_id').action_confirm()
self.mapped('move_id.picking_id').action_assign()
self.write({"date_expected": fields.Datetime.now()})
self.mapped("move_id").action_confirm()
self.mapped("move_id.picking_id").action_assign()
return True
@api.multi
@@ -148,16 +149,18 @@ class StockReservation(models.Model):
"""
Release moves from reservation
"""
self.mapped('move_id').action_cancel()
self.mapped("move_id").action_cancel()
return True
@api.model
def release_validity_exceeded(self, ids=None):
""" Release all the reservation having an exceeded validity date """
domain = [('date_validity', '<', fields.date.today()),
('state', '=', 'assigned')]
domain = [
("date_validity", "<", fields.date.today()),
("state", "=", "assigned"),
]
if ids:
domain.append(('id', 'in', ids))
domain.append(("id", "in", ids))
self.search(domain).release()
return True
@@ -167,18 +170,19 @@ class StockReservation(models.Model):
self.release()
return super(StockReservation, self).unlink()
@api.onchange('product_id')
@api.onchange("product_id")
def _onchange_product_id(self):
""" set product_uom and name from product onchange """
# save value before reading of self.move_id as this last one erase
# product_id value
move = self.move_id or self.env['stock.move'].new(
{'product_id': self.product_id})
move = self.move_id or self.env["stock.move"].new(
{"product_id": self.product_id}
)
move.onchange_product_id()
self.name = move.name
self.product_uom = move.product_uom
@api.onchange('product_uom_qty')
@api.onchange("product_uom_qty")
def _onchange_quantity(self):
""" On change of product quantity avoid negative quantities """
if not self.product_id or self.product_uom_qty <= 0.0:
@@ -187,13 +191,12 @@ class StockReservation(models.Model):
@api.multi
def open_move(self):
self.ensure_one()
action = self.env.ref('stock.stock_move_action')
action = self.env.ref("stock.stock_move_action")
action_dict = action.read()[0]
action_dict['name'] = _('Reservation Move')
action_dict["name"] = _("Reservation Move")
# open directly in the form view
view_id = self.env.ref('stock.view_move_form').id
view_id = self.env.ref("stock.view_move_form").id
action_dict.update(
views=[(view_id, 'form')],
res_id=self.move_id.id,
)
views=[(view_id, "form")], res_id=self.move_id.id,
)
return action_dict

View File

@@ -1,16 +1,12 @@
-
I force recomputation of stock.location parent left/right
-
!python {model: stock.location}:
- I force recomputation of stock.location parent left/right
- ? !python {model: stock.location}
# we need this because when running the tests at install time as is done on
# Travis, the hook performing this operation for the new stock reservation
# location is run after the test execution. This causes the stock level
# computation to be wrong at the time the tests are run.
self._parent_store_compute()
-
I create a product to test the stock reservation
-
!record {model: product.product, id: product_sorbet}:
: self._parent_store_compute()
- I create a product to test the stock reservation
- !record {model: product.product, id: product_sorbet}:
default_code: 001SORBET
name: Sorbet
type: product
@@ -19,137 +15,96 @@
standard_price: 70.0
uom_id: product.product_uom_kgm
uom_po_id: product.product_uom_kgm
-
I create a stock orderpoint for the product
-
!record {model: stock.warehouse.orderpoint, id: sorbet_orderpoint}:
- I create a stock orderpoint for the product
- !record {model: stock.warehouse.orderpoint, id: sorbet_orderpoint}:
warehouse_id: stock.warehouse0
location_id: stock.stock_location_stock
product_id: product_sorbet
product_uom: product.product_uom_kgm
product_min_qty: 4.0
product_max_qty: 15.0
-
I update the current stock of the Sorbet with 10 kgm
-
!record {model: stock.change.product.qty, id: change_qty}:
- I update the current stock of the Sorbet with 10 kgm
- !record {model: stock.change.product.qty, id: change_qty}:
new_quantity: 10
product_id: product_sorbet
-
!python {model: stock.change.product.qty}: |
- !python {model: stock.change.product.qty}: |
self.browse(ref('change_qty')).change_product_qty()
-
I check Virtual stock of Sorbet after update stock.
-
!python {model: product.product, id: product_sorbet}: |
- I check Virtual stock of Sorbet after update stock.
- !python {model: product.product, id: product_sorbet}: |
assert self.virtual_available == 10, "Stock is not updated."
-
I create a stock reservation for 6 kgm
-
!record {model: stock.reservation, id: reserv_sorbet1}:
- I create a stock reservation for 6 kgm
- !record {model: stock.reservation, id: reserv_sorbet1}:
product_id: product_sorbet
product_uom_qty: 6.0
product_uom: product.product_uom_kgm
name: reserve 6 kg of sorbet for test
-
I confirm the reservation
-
!python {model: stock.reservation}: |
- I confirm the reservation
- !python {model: stock.reservation}: |
self.browse(ref('reserv_sorbet1')).reserve()
-
I create a stock reservation for 500g
-
!record {model: stock.reservation, id: reserv_sorbet2}:
- I create a stock reservation for 500g
- !record {model: stock.reservation, id: reserv_sorbet2}:
product_id: product_sorbet
product_uom_qty: 500
product_uom: product.product_uom_gram
name: reserve 500g of sorbet for test
-
I confirm the reservation
-
!python {model: stock.reservation, id: reserv_sorbet2}: |
- I confirm the reservation
- !python {model: stock.reservation, id: reserv_sorbet2}: |
self.reserve()
-
I check the reserved amount of the product and the template
-
!python {model: product.product, id: product_sorbet}: |
- I check the reserved amount of the product and the template
- !python {model: product.product, id: product_sorbet}: |
assert 6.5 == self.reservation_count
assert 6.5 == self.product_tmpl_id.reservation_count
-
Then the reservation should be assigned and have reserved a quant
-
!python {model: stock.reservation, id: reserv_sorbet2}: |
- Then the reservation should be assigned and have reserved a quant
- !python {model: stock.reservation, id: reserv_sorbet2}: |
assert 'assigned' == self.state
assert 1 == len(self.reserved_quant_ids)
-
I check Virtual stock of Sorbet after update reservation
-
!python {model: product.product, id: product_sorbet}: |
- I check Virtual stock of Sorbet after update reservation
- !python {model: product.product, id: product_sorbet}: |
assert 3.5 == self.virtual_available
-
I run the scheduler
-
!python {model: procurement.order}: |
- I run the scheduler
- !python {model: procurement.order}: |
self.run_scheduler()
-
The procurement linked to the orderpoint must be in exception (no routes configured)
-
!python {model: stock.warehouse.orderpoint}: |
- The procurement linked to the orderpoint must be in exception (no routes configured)
- !python {model: stock.warehouse.orderpoint}: |
orderpoint = self.browse(ref('stock_reserve.sorbet_orderpoint'))
assert orderpoint.procurement_ids[0].state == 'exception', 'procurement must be in exception as there is no rule for procurement'
import math
assert orderpoint.procurement_ids[0].product_qty == math.ceil(15 - 3.5), 'wrong product qty ordered'
-
I release the reservation
-
!python {model: stock.reservation}: |
- I release the reservation
- !python {model: stock.reservation}: |
self.browse(ref('reserv_sorbet1')).release()
-
I check Virtual stock of Sorbet after update reservation
-
!python {model: product.product}: |
- I check Virtual stock of Sorbet after update reservation
- !python {model: product.product}: |
product = self.browse(ref('stock_reserve.product_sorbet'))
assert product.virtual_available == 9.5, "Stock is not updated."
-
I set the validity of the second reservation to yesterday
-
!python {model: stock.reservation}: |
- I set the validity of the second reservation to yesterday
- !python {model: stock.reservation}: |
import datetime
from odoo.tools import DEFAULT_SERVER_DATE_FORMAT
yesterday = datetime.date.today() - datetime.timedelta(days=1)
yesterday = yesterday.strftime(DEFAULT_SERVER_DATE_FORMAT)
self.browse(ref('reserv_sorbet2')).write({'date_validity': yesterday})
-
I call the function releasing expired reservations
-
!python {model: stock.reservation}: |
- I call the function releasing expired reservations
- !python {model: stock.reservation}: |
self.release_validity_exceeded()
-
I check Virtual stock of Sorbet after update reservation
-
!python {model: product.product}: |
- I check Virtual stock of Sorbet after update reservation
- !python {model: product.product}: |
product = self.browse(ref('stock_reserve.product_sorbet'))
product.refresh()
assert product.virtual_available == 10.0, "Stock is not updated."
-
I create a stock reservation for 3 kgm
-
!record {model: stock.reservation, id: reserv_sorbet3}:
- I create a stock reservation for 3 kgm
- !record {model: stock.reservation, id: reserv_sorbet3}:
product_id: product_sorbet
product_uom_qty: 3.0
product_uom: product.product_uom_kgm
name: reserve 3 kg of sorbet for test (release on unlink)
-
I confirm the reservation
-
!python {model: stock.reservation}: |
- I confirm the reservation
- !python {model: stock.reservation}: |
self.browse(ref('reserv_sorbet3')).reserve()
-
I press the open_move button on reservation and test result
-
!python {model: stock.reservation}: |
- I press the open_move button on reservation and test result
- !python {model: stock.reservation}: |
reserv = self.browse(ref('reserv_sorbet3'))
move = reserv.move_id
action_dict = reserv.open_move()
@@ -158,10 +113,8 @@
assert action_dict['id'] == ref('stock.stock_move_action'), "action not correct"
assert action_dict['views'][0][0] == ref('stock.view_move_form'), "action view not correct"
-
I press button 'action_view_reservations' on product variant and test result
-
!python {model: product.product}: |
- I press button 'action_view_reservations' on product variant and test result
- !python {model: product.product}: |
product = self.browse(ref('product_sorbet'))
action_dict = product.action_view_reservations()
assert action_dict['res_model'] == 'stock.reservation', "action model is not 'stock.move'"
@@ -171,10 +124,8 @@
assert action_dict['context']['search_default_draft'] == 1, "wrong context"
assert action_dict['context']['search_default_reserved'] == 1, "wrong context"
-
I press button 'action_view_reservations' on product template and test result
-
!python {model: product.template}: |
- I press button 'action_view_reservations' on product template and test result
- !python {model: product.template}: |
product = self.env['product.product'].browse(ref('product_sorbet'))
product_tmpl = product.product_tmpl_id
product_ids = product_tmpl.mapped('product_variant_ids.id')
@@ -188,10 +139,8 @@
assert action_dict['context']['search_default_draft'] == 1, "wrong context"
assert action_dict['context']['search_default_reserved'] == 1, "wrong context"
-
I unlink the reservation
-
!python {model: stock.reservation}: |
- I unlink the reservation
- !python {model: stock.reservation}: |
reserv = self.browse(ref('reserv_sorbet3'))
move = reserv.move_id
reserv.unlink()

View File

@@ -1,31 +1,47 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record model="ir.ui.view" id="product_template_form_view_reservation_button">
<field name="name">product.template.reservation.button</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_only_form_view"/>
<record model="ir.ui.view" id="product_template_form_view_reservation_button">
<field name="name">product.template.reservation.button</field>
<field name="model">product.template</field>
<field name="inherit_id" ref="product.product_template_only_form_view" />
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button class="oe_inline oe_stat_button" name="action_view_reservations"
type="object" attrs="{'invisible':[('type', '!=', 'product')]}" icon="fa-lock">
<field string="Stock Reservations" name="reservation_count" widget="statinfo" />
</button>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="product_product_form_view_reservation_button">
<field name="name">product.template.reservation.button</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_normal_form_view"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button class="oe_inline oe_stat_button" name="action_view_reservations"
type="object" attrs="{'invisible':[('type', '!=', 'product')]}" icon="fa-lock">
<field string="Stock Reservations" name="reservation_count" widget="statinfo" />
</button>
</xpath>
</field>
</record>
<xpath expr="//div[@name='button_box']" position="inside">
<button
class="oe_inline oe_stat_button"
name="action_view_reservations"
type="object"
attrs="{'invisible':[('type', '!=', 'product')]}"
icon="fa-lock"
>
<field
string="Stock Reservations"
name="reservation_count"
widget="statinfo"
/>
</button>
</xpath>
</field>
</record>
<record model="ir.ui.view" id="product_product_form_view_reservation_button">
<field name="name">product.template.reservation.button</field>
<field name="model">product.product</field>
<field name="inherit_id" ref="product.product_normal_form_view" />
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button
class="oe_inline oe_stat_button"
name="action_view_reservations"
type="object"
attrs="{'invisible':[('type', '!=', 'product')]}"
icon="fa-lock"
>
<field
string="Stock Reservations"
name="reservation_count"
widget="statinfo"
/>
</button>
</xpath>
</field>
</record>
</odoo>

View File

@@ -1,140 +1,192 @@
<?xml version="1.0" encoding="utf-8"?>
<?xml version="1.0" encoding="utf-8" ?>
<odoo>
<record id="view_stock_reservation_form" model="ir.ui.view">
<field name="name">stock.reservation.form</field>
<field name="model">stock.reservation</field>
<field name="arch" type="xml">
<form string="Stock Reservations" version="7.0">
<header>
<button name="reserve" type="object"
<record id="view_stock_reservation_form" model="ir.ui.view">
<field name="name">stock.reservation.form</field>
<field name="model">stock.reservation</field>
<field name="arch" type="xml">
<form string="Stock Reservations" version="7.0">
<header>
<button
name="reserve"
type="object"
string="Reserve"
class="oe_highlight"
states="draft"
/>
<button
name="release"
type="object"
string="Release"
class="oe_highlight"
states="assigned,confirmed,done"
/>
<button
name="open_move"
type="object"
string="View Reservation Move"
/>
<field
name="state"
widget="statusbar"
statusbar_visible="draft,assigned"
/>
</header>
<sheet>
<group>
<group name="main_grp" string="Details">
<field name="product_id" />
<label for="product_uom_qty" />
<div>
<field name="product_uom_qty" class="oe_inline" />
<field
name="product_uom"
groups="product.group_uom"
class="oe_inline"
/>
</div>
<field name="name" />
<field name="date_validity" />
<field name="create_date" groups="base.group_no_one" />
<field
name="company_id"
groups="base.group_multi_company"
widget="selection"
/>
<field
name="restrict_partner_id"
groups="stock.group_tracking_owner"
/>
</group>
<group
name="location"
string="Locations"
groups="stock.group_locations"
>
<field name="location_id" />
<field name="location_dest_id" />
</group>
<group name="note" string="Notes">
<field name="note" nolabel="1" />
</group>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_stock_reservation_tree" model="ir.ui.view">
<field name="name">stock.reservation.tree</field>
<field name="model">stock.reservation</field>
<field name="arch" type="xml">
<tree
string="Stock Reservations"
version="7.0"
colors="blue:state == 'draft';grey:state == 'cancel'"
>
<field name="name" />
<field name="product_id" />
<field name="move_id" />
<field name="product_uom_qty" sum="Total" />
<field name="product_uom" />
<field name="date_validity" />
<field name="restrict_partner_id" groups="stock.group_tracking_owner" />
<field name="location_id" />
<field name="state" />
<button
name="reserve"
type="object"
string="Reserve"
class="oe_highlight"
states="draft"/>
<button name="release" type="object"
icon="terp-locked"
states="draft"
/>
<button
name="release"
type="object"
string="Release"
class="oe_highlight"
states="assigned,confirmed,done"/>
<button name="open_move" type="object"
string="View Reservation Move"/>
<field name="state" widget="statusbar"
statusbar_visible="draft,assigned"/>
</header>
<sheet>
<group>
<group name="main_grp" string="Details">
<field name="product_id" />
<label for="product_uom_qty" />
<div>
<field name="product_uom_qty" class="oe_inline"/>
<field name="product_uom"
groups="product.group_uom" class="oe_inline"/>
</div>
<field name="name"/>
<field name="date_validity" />
<field name="create_date" groups="base.group_no_one"/>
<field name="company_id"
groups="base.group_multi_company"
widget="selection"/>
<field name="restrict_partner_id" groups="stock.group_tracking_owner"/>
</group>
<group name="location" string="Locations"
groups="stock.group_locations">
<field name="location_id"/>
<field name="location_dest_id"/>
</group>
<group name="note" string="Notes">
<field name="note" nolabel="1"/>
</group>
icon="gtk-undo"
states="assigned,confirmed,done"
/>
</tree>
</field>
</record>
<record id="view_stock_reservation_search" model="ir.ui.view">
<field name="name">stock.reservation.search</field>
<field name="model">stock.reservation</field>
<field name="arch" type="xml">
<search string="Stock Reservations" version="7.0">
<filter
name="draft"
string="Draft"
domain="[('state', '=', 'draft')]"
help="Not already reserved"
/>
<filter
name="reserved"
string="Reserved"
domain="[('state', '=', 'assigned')]"
help="Moves are reserved."
/>
<filter
name="cancel"
string="Released"
domain="[('state', '=', 'cancel')]"
help="Reservations have been released."
/>
<field name="name" />
<field name="product_id" />
<field name="move_id" />
<field name="restrict_partner_id" groups="stock.group_tracking_owner" />
<group expand="0" string="Group By...">
<filter
string="Status"
name="groupby_state"
domain="[]"
context="{'group_by': 'state'}"
/>
<filter
string="Product"
domain="[]"
name="groupby_product"
context="{'group_by': 'product_id'}"
/>
<filter
string="Product UoM"
domain="[]"
name="groupby_product_uom"
context="{'group_by': 'product_uom'}"
/>
<filter
string="Source Location"
domain="[]"
name="groupby_location"
context="{'group_by': 'location_id'}"
/>
</group>
</sheet>
</form>
</field>
</record>
<record id="view_stock_reservation_tree" model="ir.ui.view">
<field name="name">stock.reservation.tree</field>
<field name="model">stock.reservation</field>
<field name="arch" type="xml">
<tree string="Stock Reservations" version="7.0"
colors="blue:state == 'draft';grey:state == 'cancel'" >
<field name="name" />
<field name="product_id" />
<field name="move_id" />
<field name="product_uom_qty" sum="Total" />
<field name="product_uom" />
<field name="date_validity" />
<field name="restrict_partner_id" groups="stock.group_tracking_owner"/>
<field name="location_id" />
<field name="state"/>
<button name="reserve" type="object"
string="Reserve"
icon="terp-locked"
states="draft"/>
<button name="release" type="object"
string="Release"
icon="gtk-undo"
states="assigned,confirmed,done"/>
</tree>
</field>
</record>
<record id="view_stock_reservation_search" model="ir.ui.view">
<field name="name">stock.reservation.search</field>
<field name="model">stock.reservation</field>
<field name="arch" type="xml">
<search string="Stock Reservations" version="7.0">
<filter name="draft" string="Draft"
domain="[('state', '=', 'draft')]"
help="Not already reserved"/>
<filter name="reserved" string="Reserved"
domain="[('state', '=', 'assigned')]"
help="Moves are reserved."/>
<filter name="cancel" string="Released"
domain="[('state', '=', 'cancel')]"
help="Reservations have been released."/>
<field name="name" />
<field name="product_id" />
<field name="move_id" />
<field name="restrict_partner_id" groups="stock.group_tracking_owner"/>
<group expand="0" string="Group By...">
<filter string="Status"
name="groupby_state"
domain="[]" context="{'group_by': 'state'}"/>
<filter string="Product" domain="[]"
name="groupby_product"
context="{'group_by': 'product_id'}"/>
<filter string="Product UoM" domain="[]"
name="groupby_product_uom"
context="{'group_by': 'product_uom'}"/>
<filter string="Source Location" domain="[]"
name="groupby_location"
context="{'group_by': 'location_id'}"/>
</group>
</search>
</field>
</record>
<record id="action_stock_reservation_tree" model="ir.actions.act_window">
<field name="name">Stock Reservations</field>
<field name="res_model">stock.reservation</field>
<field name="type">ir.actions.act_window</field>
<field name="view_id" ref="view_stock_reservation_tree"/>
<field name="search_view_id" ref="view_stock_reservation_search"/>
<field name="context">{'search_default_draft': 1,
</search>
</field>
</record>
<record id="action_stock_reservation_tree" model="ir.actions.act_window">
<field name="name">Stock Reservations</field>
<field name="res_model">stock.reservation</field>
<field name="type">ir.actions.act_window</field>
<field name="view_id" ref="view_stock_reservation_tree" />
<field name="search_view_id" ref="view_stock_reservation_search" />
<field name="context">{'search_default_draft': 1,
'search_default_reserved': 1,
'search_default_groupby_product': 1}</field>
<field name="help" type="html">
<p class="oe_view_nocontent_create">
<field name="help" type="html">
<p class="oe_view_nocontent_create">
Click to create a stock reservation.
</p><p>
</p>
<p>
This menu allow you to prepare and reserve some quantities
of products.
</p>
</field>
</record>
<menuitem action="action_stock_reservation_tree"
id="menu_action_stock_reservation"
parent="stock.menu_stock_inventory_control"
sequence="30"/>
</field>
</record>
<menuitem
action="action_stock_reservation_tree"
id="menu_action_stock_reservation"
parent="stock.menu_stock_inventory_control"
sequence="30"
/>
</odoo>