Skip to content

Commit

Permalink
stock_orderpoint_manual_procurement (OCA#210)
Browse files Browse the repository at this point in the history
[ADD] stock_orderpoint_procure_uom
  • Loading branch information
JordiBForgeFlow authored and DavidBForgeFlow committed May 28, 2021
1 parent 8bb6375 commit 2eb4bef
Show file tree
Hide file tree
Showing 14 changed files with 564 additions and 0 deletions.
67 changes: 67 additions & 0 deletions stock_orderpoint_manual_procurement/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,67 @@
.. image:: https://img.shields.io/badge/licence-AGPL--3-blue.svg
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3

===================================
Stock Orderpoint Manual Procurement
===================================

This module allows users to manually start procurements from the list of
reordering rules, based on the quantity that is recommended to be procured.


Usage
=====

Go to 'Configuration / Reordering Rules' and review the quantity recommended
to be procured. You can now start the procurement for a single or a list of
reordering rules.

The recommended quantity to procure is adjusted to the procurement unit of
measure indicated in the reordering rule.

If you want users to be able to change the recommended quantity to procure,
you should assign them to the security group 'Change quantity in manual
procurements from reordering rules', under 'Settings / Users / Users'.

.. 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/8.0


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 smashing it by providing a detailed and welcomed feedback.

Credits
=======

Images
------

* Odoo Community Association: `Icon <https://github.com/OCA/maintainer-tools/blob/master/template/module/static/description/icon.svg>`_.

Contributors
------------

* Jordi Ballester Alomar <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.
7 changes: 7 additions & 0 deletions stock_orderpoint_manual_procurement/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import models
from . import wizards
24 changes: 24 additions & 0 deletions stock_orderpoint_manual_procurement/__openerp__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Stock Orderpoint manual procurement",
"summary": "Allows to create procurement orders from orderpoints instead "
"of relying only on the scheduler",
"version": "8.0.1.0.0",
"author": "Eficent Business and IT Consulting Services S.L,"
"Odoo Community Association (OCA)",
"website": "https://www.odoo-community.org",
"category": "Warehouse Management",
"depends": ["stock",
"stock_orderpoint_uom"],
"data": ["security/stock_orderpoint_manual_procurement_security.xml",
"wizards/make_procurement_orderpoint_view.xml",
"views/procurement_order_view.xml",
"views/stock_warehouse_orderpoint_view.xml"
],
"license": "AGPL-3",
'installable': True,
'application': True,
}
6 changes: 6 additions & 0 deletions stock_orderpoint_manual_procurement/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import stock_warehouse_orderpoint
Original file line number Diff line number Diff line change
@@ -0,0 +1,65 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from openerp import api, fields, models
from datetime import datetime
from openerp.addons import decimal_precision as dp
from openerp.tools import float_compare, float_round


UNIT = dp.get_precision('Product Unit of Measure')


class StockWarehouseOrderpoint(models.Model):
_inherit = 'stock.warehouse.orderpoint'

@api.multi
@api.depends("product_min_qty", "product_id", "qty_multiple")
def _compute_procure_recommended(self):
procurement_model = self.env['procurement.order']
for op in self:
op.procure_recommended_date = \
procurement_model._get_orderpoint_date_planned(
op, datetime.today())
procure_recommended_qty = 0.0
prods = procurement_model._product_virtual_get(op)
if prods is None:
continue
if float_compare(prods, op.product_min_qty,
precision_rounding=op.product_uom.rounding) < 0:
qty = max(op.product_min_qty, op.product_max_qty) - prods
reste = op.qty_multiple > 0 and qty % op.qty_multiple or 0.0
if float_compare(
reste, 0.0,
precision_rounding=op.product_uom.rounding) > 0:
qty += op.qty_multiple - reste

if float_compare(
qty, 0.0,
precision_rounding=op.product_uom.rounding) <= 0:
continue

qty -= op.subtract_procurements(op)

qty_rounded = float_round(
qty, precision_rounding=op.product_uom.rounding)
if qty_rounded > 0:
procure_recommended_qty = qty_rounded
if op.procure_uom_id:
product_qty = op.procure_uom_id._compute_qty(
op.product_id.uom_id.id, procure_recommended_qty,
op.procure_uom_id.id)
else:
product_qty = procure_recommended_qty

op.procure_recommended_qty = product_qty

procure_recommended_qty = fields.Float(
string='Procure recommendation',
compute="_compute_procure_recommended",
digits=UNIT)
procure_recommended_date = fields.Date(
string='Request Date',
compute="_compute_procure_recommended")
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="utf-8"?>
<openerp>
<data noupdate="0">

<record id="group_change_orderpoint_procure_qty" model="res.groups">
<field name="name">Change quantity in manual procurements from reordering rules</field>
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
<field name="category_id" ref="base.module_category_warehouse_management"/>
</record>

</data>
</openerp>
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
7 changes: 7 additions & 0 deletions stock_orderpoint_manual_procurement/tests/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,7 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import test_stock_orderpoint_manual_procurement
Original file line number Diff line number Diff line change
@@ -0,0 +1,133 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# Copyright 2016 Serpent Consulting Services Pvt. Ltd.
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from openerp.tests import common


class TestStockWarehouseOrderpoint(common.TransactionCase):

def setUp(self):
super(TestStockWarehouseOrderpoint, self).setUp()

# Refs
self.group_stock_manager = self.env.ref('stock.group_stock_manager')
self.group_change_procure_qty = self.env.ref(
'stock_orderpoint_manual_procurement.'
'group_change_orderpoint_procure_qty')
self.company1 = self.env.ref('base.main_company')

# Get required Model
self.reordering_rule_model = self.env['stock.warehouse.orderpoint']
self.product_model = self.env['product.product']
self.user_model = self.env['res.users']
self.product_ctg_model = self.env['product.category']
self.stock_change_model = self.env['stock.change.product.qty']
self.make_procurement_orderpoint_model =\
self.env['make.procurement.orderpoint']

# Create users
self.user = self._create_user('user_1',
[self.group_stock_manager,
self.group_change_procure_qty],
self.company1)
# Get required Model data
self.product_uom = self.env.ref('product.product_uom_unit')
self.location = self.env.ref('stock.stock_location_stock')
self.product = self.env.ref('product.product_product_7')

# Create Product category and Product
self.product_ctg = self._create_product_category()
self.product = self._create_product()

# Add default quantity
quantity = 20.00
self._update_product_qty(self.product, self.location, quantity)

# Create Reordering Rule
self.reorder = self.create_orderpoint()

def _create_user(self, login, groups, company):
""" Create a user."""
group_ids = [group.id for group in groups]
user = \
self.user_model.with_context({'no_reset_password': True}).create({
'name': 'Test User',
'login': login,
'password': 'demo',
'email': 'test@yourcompany.com',
'company_id': company.id,
'company_ids': [(4, company.id)],
'groups_id': [(6, 0, group_ids)]
})
return user

def _create_product_category(self):
"""Create a Product Category."""
product_ctg = self.product_ctg_model.create({
'name': 'test_product_ctg',
'type': 'normal',
})
return product_ctg

def _create_product(self):
"""Create a Product."""
product = self.product_model.create({
'name': 'Test Product',
'categ_id': self.product_ctg.id,
'type': 'product',
'uom_id': self.product_uom.id,
})
return product

def _update_product_qty(self, product, location, quantity):
"""Update Product quantity."""
change_product_qty = self.stock_change_model.create({
'location_id': location.id,
'product_id': product.id,
'new_quantity': quantity,
})
change_product_qty.change_product_qty()
return change_product_qty

def create_orderpoint(self):
"""Create a Reordering Rule"""
reorder = self.reordering_rule_model.sudo(self.user).create({
'name': 'Order-point',
'product_id': self.product.id,
'product_min_qty': '100',
'product_max_qty': '500',
'qty_multiple': '1'
})
return reorder

def create_orderpoint_procurement(self):
"""Make Procurement from Reordering Rule"""
context = {
'active_model': 'stock.warehouse.orderpoint',
'active_ids': self.reorder.ids,
'active_id': self.reorder.id
}
wizard = self.make_procurement_orderpoint_model.sudo(self.user).\
with_context(context).create({})
wizard.make_procurement()
return wizard

def test_security(self):
"""Test Manual Procurement created from Order-Point"""

# Create Manual Procurement from order-point procured quantity
self.create_orderpoint_procurement()

# Assert that Procurement is created with the desired quantity
self.assertTrue(self.reorder.procurement_ids)
self.assertEqual(self.reorder.product_id.id,
self.reorder.procurement_ids.product_id.id)
self.assertEqual(self.reorder.name,
self.reorder.procurement_ids.origin)
self.assertNotEqual(self.reorder.procure_recommended_qty,
self.reorder.procurement_ids.product_qty)
self.assertEqual(self.reorder.procurement_ids.product_qty,
480.0)
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
<?xml version="1.0"?>
<openerp>
<data>

<record id="view_procurement_filter" model="ir.ui.view">
<field name="name">procurement.order.select</field>
<field name="model">procurement.order</field>
<field name="inherit_id"
ref="procurement.view_procurement_filter"/>
<field name="arch" type="xml">
<field name="origin" position="after">
<field name="orderpoint_id"/>
</field>

</field>
</record>

</data>
</openerp>
Original file line number Diff line number Diff line change
@@ -0,0 +1,29 @@
<?xml version="1.0"?>
<openerp>
<data>

<record id="view_warehouse_orderpoint_tree" model="ir.ui.view">
<field name="name">stock.warehouse.orderpoint.tree</field>
<field name="model">stock.warehouse.orderpoint</field>
<field name="inherit_id"
ref="stock.view_warehouse_orderpoint_tree"/>
<field name="arch" type="xml">
<field name="product_uom" position="after">
<field name="procurement_ids" invisible="1"/>
<field name="procure_recommended_qty"/>
<field name="procure_recommended_date"/>
<button string="Create Procurement"
name="%(stock_orderpoint_manual_procurement.act_make_procurement_from_orderpoint)d"
icon="gtk-execute" type="action"/>
<button string="Procurements"
name="%(procurement.procurement_action)d"
attrs="{'invisible':[('procurement_ids', '=', False)]}"
icon="gtk-open" type="action"
domain="[('orderpoint_id','=', active_id)]"
context="{'search_default_orderpoint_id': [active_id]}"/>
</field>
</field>
</record>

</data>
</openerp>
6 changes: 6 additions & 0 deletions stock_orderpoint_manual_procurement/wizards/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# -*- coding: utf-8 -*-
# Copyright 2016 Eficent Business and IT Consulting Services S.L.
# (http://www.eficent.com)
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import make_procurement_orderpoint
Loading

0 comments on commit 2eb4bef

Please sign in to comment.