add stock_request in 11.0

This commit is contained in:
Jordi Ballester
2017-11-13 13:15:41 +01:00
committed by Jesús Alan Ramos Rodríguez
parent 5fad77ce43
commit 92fd123b59
14 changed files with 492 additions and 0 deletions

View File

@@ -0,0 +1,63 @@
.. image:: https://img.shields.io/badge/licence-LGPL--3-blue.svg
:target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html
:alt: License: LGPL-3
======================
Stock Request Purchase
======================
This module allows for users to be able to display purchase orders that have
been created as a consequence of Stock Requests.
Usage
=====
In case that the confirmation of the Stock Request results in an immediate
Purchase Order, the user will be able to display the PO's from the Stock
Request form view.
.. image:: https://odoo-community.org/website/image/ir.attachment/5784_f2813bd/datas
:alt: Try me on Runbot
:target: https://runbot.odoo-community.org/runbot/153/11.0
Known issues / Roadmap
======================
* When a Stock Request is cancelled, it does not cancel the quantity included
in the Purchase Order.
Bug Tracker
===========
Bugs are tracked on `GitHub Issues
<https://github.com/OCA/stock-logistics-warehouse/issues>`_. In case of
trouble, please check there if your issue has already been reported. If you
spotted it first, help us smash it by providing detailed and welcomed feedback.
Credits
=======
Contributors
------------
* Jordi Ballester <jordi.ballester@eficent.com>.
Maintainer
----------
.. image:: https://odoo-community.org/logo.png
:alt: Odoo Community Association
:target: https://odoo-community.org
This module is maintained by the OCA.
OCA, or the Odoo Community Association, is a nonprofit organization whose
mission is to support the collaborative development of Odoo features and
promote its widespread use.
To contribute to this module, please visit https://odoo-community.org.

View File

@@ -0,0 +1,2 @@
from . import models

View File

@@ -0,0 +1,24 @@
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
{
"name": "Stock Request Purchase",
"summary": "Internal request for stock",
"version": "11.0.1.0.0",
"license": "LGPL-3",
"website": "https://github.com/stock-logistics-warehouse",
"author": "Eficent, "
"Odoo Community Association (OCA)",
"category": "Warehouse Management",
"depends": [
"stock_request",
"purchase",
"purchase_procurement_run_buy_hook"
],
"data": [
"security/ir.model.access.csv",
"views/stock_request_views.xml",
"views/purchase_order_views.xml",
],
"installable": True,
}

View File

@@ -0,0 +1,5 @@
from . import purchase_order
from . import purchase_order_line
from . import procurement_rule
from . import stock_request

View File

@@ -0,0 +1,27 @@
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import models
class ProcurementRule(models.Model):
_inherit = 'procurement.rule'
def _prepare_purchase_order_line(self, product_id, product_qty,
product_uom, values, po, supplier):
vals = super(ProcurementRule, self)._prepare_purchase_order_line(
product_id, product_qty, product_uom, values, po, supplier)
if 'stock_request_id' in values:
vals['stock_request_ids'] = [(4, values['stock_request_id'])]
return vals
def _prepare_purchase_order_line_update(self, line,
procurement_uom_po_qty,
price_unit, values):
vals = super(ProcurementRule,
self)._prepare_purchase_order_line_update(
line, procurement_uom_po_qty, price_unit, values
)
if 'stock_request_id' in values:
vals['stock_request_ids'] = [(4, values['stock_request_id'])]
return vals

View File

@@ -0,0 +1,37 @@
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models
class PurchaseOrder(models.Model):
_inherit = 'purchase.order'
stock_request_ids = fields.Many2many(comodel_name='stock.request',
string='Stock Requests',
compute='_compute_stock_request_ids')
stock_request_count = fields.Integer('Stock Request #',
compute='_compute_stock_request_ids')
@api.depends('order_line')
def _compute_stock_request_ids(self):
for rec in self:
rec.stock_request_ids = rec.order_line.mapped('stock_request_ids')
rec.stock_request_count = len(rec.stock_request_ids)
def action_view_stock_request(self):
"""
:return dict: dictionary value for created view
"""
action = self.env.ref(
'stock_request.action_stock_request_form').read()[0]
requests = self.mapped('stock_request_ids')
if len(requests) > 1:
action['domain'] = [('id', 'in', requests.ids)]
elif requests:
action['views'] = [
(self.env.ref('stock_request.view_stock_request_form').id,
'form')]
action['res_id'] = requests.id
return action

View File

@@ -0,0 +1,23 @@
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models
class PurchaseOrderLine(models.Model):
_inherit = 'purchase.order.line'
stock_request_ids = fields.Many2many(comodel_name='stock.request',
string='Stock Requests', copy=False)
@api.multi
def _prepare_stock_moves(self, picking):
res = super(PurchaseOrderLine, self)._prepare_stock_moves(picking)
for re in res:
re['allocation_ids'] = [
(0, 0, {
'stock_request_id': request.id,
'requested_product_uom_qty': request.product_qty,
}) for request in self.stock_request_ids]
return res

View File

@@ -0,0 +1,38 @@
# Copyright 2017 Eficent Business and IT Consulting Services, S.L.
# License LGPL-3.0 or later (https://www.gnu.org/licenses/lgpl.html).
from odoo import api, fields, models
class StockRequest(models.Model):
_inherit = "stock.request"
purchase_ids = fields.One2many('purchase.order',
compute='_compute_purchase_ids',
string='Pickings', readonly=True)
purchase_count = fields.Integer(string='Purchase count',
compute='_compute_purchase_ids',
readonly=True)
purchase_line_ids = fields.Many2many('purchase.order.line',
string='Purchase Order Lines',
readonly=True, copy=False)
@api.depends('purchase_line_ids')
def _compute_purchase_ids(self):
for request in self.sudo():
request.purchase_ids = request.purchase_line_ids.mapped('order_id')
request.purchase_count = len(request.purchase_ids)
@api.multi
def action_view_purchase(self):
action = self.env.ref(
'purchase.purchase_order_action_generic').read()[0]
purchases = self.mapped('purchase_ids')
if len(purchases) > 1:
action['domain'] = [('id', 'in', purchases.ids)]
elif purchases:
action['views'] = [
(self.env.ref('purchase.purchase_order_form').id, 'form')]
action['res_id'] = purchases.id
return action

View File

@@ -0,0 +1,3 @@
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
access_stock_request_purchase_user,stock.request purchase user,stock_request.model_stock_request,purchase.group_purchase_user,1,0,0,0
access_stock_request_allocation_purchase_user,stock request allocation purchase user,stock_request.model_stock_request_allocation,purchase.group_purchase_user,1,0,0,0
1 id name model_id:id group_id:id perm_read perm_write perm_create perm_unlink
2 access_stock_request_purchase_user stock.request purchase user stock_request.model_stock_request purchase.group_purchase_user 1 0 0 0
3 access_stock_request_allocation_purchase_user stock request allocation purchase user stock_request.model_stock_request_allocation purchase.group_purchase_user 1 0 0 0

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.7 KiB

View File

@@ -0,0 +1,2 @@
from . import test_stock_request_purchase

View File

@@ -0,0 +1,199 @@
# Copyright 2017 Eficent Business and IT Consulting Services S.L.
# License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0).
from odoo.tests import common
class TestStockRequestPurchase(common.TransactionCase):
def setUp(self):
super(TestStockRequestPurchase, self).setUp()
# common models
self.stock_request = self.env['stock.request']
# refs
self.stock_request_user_group = \
self.env.ref('stock_request.group_stock_request_user')
self.stock_request_manager_group = \
self.env.ref('stock_request.group_stock_request_manager')
self.main_company = self.env.ref('base.main_company')
self.warehouse = self.env.ref('stock.warehouse0')
self.categ_unit = self.env.ref('product.product_uom_categ_unit')
# common data
self.company_2 = self.env['res.company'].create({
'name': 'Comp2',
})
self.wh2 = self.env['stock.warehouse'].search(
[('company_id', '=', self.company_2.id)], limit=1)
self.stock_request_user = self._create_user(
'stock_request_user',
[self.stock_request_user_group.id],
[self.main_company.id, self.company_2.id])
self.stock_request_manager = self._create_user(
'stock_request_manager',
[self.stock_request_manager_group.id],
[self.main_company.id, self.company_2.id])
self.route_buy = self.warehouse.buy_pull_id.route_id
self.supplier = self.env['res.partner'].create({
'name': 'Supplier',
'supplier': True,
})
self.product = self._create_product('SH', 'Shoes', False)
self.uom_dozen = self.env['product.uom'].create({
'name': 'Test-DozenA',
'category_id': self.categ_unit.id,
'factor_inv': 12,
'uom_type': 'bigger',
'rounding': 0.001})
def _create_user(self, name, group_ids, company_ids):
return self.env['res.users'].with_context(
{'no_reset_password': True}).create(
{'name': name,
'password': 'demo',
'login': name,
'email': '@'.join([name, '@test.com']),
'groups_id': [(6, 0, group_ids)],
'company_ids': [(6, 0, company_ids)]
})
def _create_product(self, default_code, name, company_id):
return self.env['product.product'].create({
'name': name,
'default_code': default_code,
'uom_id': self.env.ref('product.product_uom_unit').id,
'company_id': company_id,
'type': 'product',
'route_ids': [(6, 0, self.route_buy.ids)],
'seller_ids': [(0, 0, {'name': self.supplier.id, 'delay': 5})]
})
def test_create_request_01(self):
"""Single Stock request with buy rule"""
vals = {
'product_id': self.product.id,
'product_uom_id': self.product.uom_id.id,
'product_uom_qty': 5.0,
'company_id': self.main_company.id,
'warehouse_id': self.warehouse.id,
'location_id': self.warehouse.lot_stock_id.id,
}
stock_request = self.stock_request.sudo(
self.stock_request_user).create(vals)
stock_request.action_confirm()
self.assertEqual(stock_request.state, 'open')
stock_request.refresh()
self.assertEqual(len(stock_request.sudo().purchase_ids), 1)
self.assertEqual(len(stock_request.picking_ids), 0)
self.assertEqual(len(stock_request.move_ids), 0)
self.assertEqual(stock_request.qty_in_progress, 0.0)
purchase = stock_request.sudo().purchase_ids[0]
purchase.button_confirm()
picking = purchase.picking_ids[0]
picking.action_confirm()
self.assertEqual(stock_request.qty_in_progress, 5.0)
self.assertEqual(stock_request.qty_done, 0.0)
picking.action_assign()
packout1 = picking.move_line_ids[0]
packout1.qty_done = 5
picking.action_done()
self.assertEqual(stock_request.qty_in_progress, 0.0)
self.assertEqual(stock_request.qty_done,
stock_request.product_uom_qty)
self.assertEqual(stock_request.state, 'done')
def test_create_request_02(self):
"""Multiple Stock requests with buy rule"""
vals = {
'product_id': self.product.id,
'product_uom_id': self.product.uom_id.id,
'product_uom_qty': 5.0,
'company_id': self.main_company.id,
'warehouse_id': self.warehouse.id,
'location_id': self.warehouse.lot_stock_id.id,
}
stock_request_1 = self.stock_request.sudo(
self.stock_request_user).create(vals)
stock_request_2 = self.stock_request.sudo(
self.stock_request_manager).create(vals)
stock_request_1.action_confirm()
self.assertEqual(sum(stock_request_1.sudo().purchase_line_ids.mapped(
'product_qty')), 5)
stock_request_2.action_confirm()
self.assertEqual(sum(stock_request_2.sudo().purchase_line_ids.mapped(
'product_qty')), 10)
stock_request_1.refresh()
stock_request_2.refresh()
self.assertEqual(len(stock_request_1.sudo().purchase_ids), 1)
self.assertEqual(len(stock_request_2.sudo().purchase_ids), 1)
self.assertEqual(len(stock_request_1.sudo().purchase_ids), 1)
self.assertEqual(len(stock_request_2.sudo().purchase_line_ids), 1)
self.assertEqual(stock_request_1.sudo().purchase_ids,
stock_request_2.sudo().purchase_ids)
self.assertEqual(stock_request_1.sudo().purchase_line_ids,
stock_request_2.sudo().purchase_line_ids)
purchase = stock_request_1.sudo().purchase_ids[0]
purchase.button_confirm()
picking = purchase.picking_ids[0]
picking.action_confirm()
self.assertEqual(stock_request_1.qty_in_progress, 5.0)
self.assertEqual(stock_request_1.qty_done, 0.0)
self.assertEqual(stock_request_2.qty_in_progress, 5.0)
self.assertEqual(stock_request_2.qty_done, 0.0)
picking.action_assign()
packout1 = picking.move_line_ids[0]
packout1.qty_done = 10
picking.action_done()
self.assertEqual(stock_request_1.qty_in_progress, 0.0)
self.assertEqual(stock_request_1.qty_done,
stock_request_1.product_uom_qty)
self.assertEqual(stock_request_2.qty_in_progress, 0.0)
self.assertEqual(stock_request_2.qty_done,
stock_request_2.product_uom_qty)
def test_view_actions(self):
vals = {
'product_id': self.product.id,
'product_uom_id': self.product.uom_id.id,
'product_uom_qty': 5.0,
'company_id': self.main_company.id,
'warehouse_id': self.warehouse.id,
'location_id': self.warehouse.lot_stock_id.id,
}
stock_request = self.stock_request.sudo().create(vals)
stock_request.action_confirm()
action = stock_request.action_view_purchase()
self.assertEqual(action['domain'], '[]')
self.assertEqual('views' in action.keys(), True)
self.assertEqual(action['res_id'],
stock_request.purchase_ids[0].id)
action = stock_request.purchase_ids[0].action_view_stock_request()
self.assertEqual(action['type'], 'ir.actions.act_window')
self.assertEqual(action['res_id'], stock_request.id)

View File

@@ -0,0 +1,43 @@
<?xml version="1.0"?>
<!-- Copyright 2016 Eficent Business and IT Consulting Services S.L.
License LGPL-3.0 or later (http://www.gnu.org/licenses/lgpl-3.0) -->
<odoo>
<record id="purchase_order_form" model="ir.ui.view">
<field name="name">purchase.order.form</field>
<field name="model">purchase.order</field>
<field name="inherit_id" ref="purchase.purchase_order_form"/>
<field name="arch" type="xml">
<xpath expr="//div[@name='button_box']" position="inside">
<button type="object"
name="action_view_stock_request"
class="oe_stat_button"
icon="fa-chain"
attrs="{'invisible':[('stock_request_ids', '=', [])]}">
<field name="stock_request_count" widget="statinfo"
string="Stock Requests"/>
<field name="stock_request_ids" invisible="1"/>
</button>
</xpath>
<xpath expr="//field[@name='order_line']/form/sheet/notebook"
position="inside">
<page name="stock_requests" string="Stock Requests"
groups="stock_request.group_stock_request_user">
<field name="stock_request_ids"/>
</page>
</xpath>
</field>
</record>
<record id="purchase_order_line_form2" model="ir.ui.view">
<field name="name">purchase.order.line.form2</field>
<field name="model">purchase.order.line</field>
<field name="inherit_id" ref="purchase.purchase_order_line_form2"/>
<field name="arch" type="xml">
<field name="name" position="after">
<separator string="Stock Requests"/>
<field name="stock_request_ids"/>
</field>
</field>
</record>
</odoo>

View File

@@ -0,0 +1,26 @@
<?xml version="1.0" encoding="utf-8"?>
<!-- Copyright 2017 Eficent
License LGPL-3.0 or later (http://www.gnu.org/licenses/agpl). -->
<odoo>
<record id="view_stock_request_form" model="ir.ui.view">
<field name="name">stock.request.form</field>
<field name="model">stock.request</field>
<field name="inherit_id" ref="stock_request.view_stock_request_form"/>
<field name="arch" type="xml">
<div name="button_box" position="inside">
<field name="purchase_ids" invisible="1"/>
<button type="object"
name="action_view_purchase"
class="oe_stat_button"
icon="fa-truck"
attrs="{'invisible': [('purchase_count', '=', 0)]}"
groups="purchase.group_purchase_user">
<field name="purchase_count" widget="statinfo"
string="Purchase"/>
</button>
</div>
</field>
</record>
</odoo>