Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[WIP][WMS][12.0] stock_minimum_shelf_life #723

Closed
wants to merge 3 commits into from
Closed
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions stock_minimum_shelf_life/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import models
22 changes: 22 additions & 0 deletions stock_minimum_shelf_life/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,22 @@
# Copyright 2019 Camptocamp
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
{
"name": "Stock minimum shelf life",
"version": "12.0.1.0.0",
"license": "AGPL-3",
"summary": "Allows to set a minimum date in procurement group to force the"
" reservation mecanism to take only product that expiry date is"
" after the minimum date.",
"author": "Camptocamp,"
"Odoo Community Association (OCA)",
"website": "https://github.com/OCA/stock-logistics-warehouse",
"category": "Warehouse",
"depends": [
"stock",
"product_expiry",
],
"data": [
],
damdam-s marked this conversation as resolved.
Show resolved Hide resolved
"installable": True,
"development_status": 'Alpha',
}
6 changes: 6 additions & 0 deletions stock_minimum_shelf_life/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,6 @@
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from . import res_company
from . import res_config_settings
from . import procurement_group
from . import stock_move
16 changes: 16 additions & 0 deletions stock_minimum_shelf_life/models/procurement_group.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
# Copyright 2019 Camptocamp
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from datetime import datetime
from dateutil.relativedelta import relativedelta

from odoo import api, models


class ProcurementGroup(models.Model):
_inherit = 'procurement.group'

@api.model
def _get_lot_min_expiration_date(self):
months_adjust = self.env.user.company_id.minimum_shelf_life
return datetime.now() + relativedelta(hour=0, minute=0, second=0,
months=+months_adjust)
13 changes: 13 additions & 0 deletions stock_minimum_shelf_life/models/res_company.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,13 @@
# Copyright 2019 Camptocamp
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class ResCompany(models.Model):
_inherit = 'res.company'

minimum_shelf_life = fields.Integer(
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jgrandguillaume In case of fresh products, isn't it a too big window (days instead) ?

default=6,
string="Minimum shelf life (in months)"
)
14 changes: 14 additions & 0 deletions stock_minimum_shelf_life/models/res_config_settings.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
# Copyright 2019 Camptocamp
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).

from odoo import fields, models


class ResConfigSettings(models.TransientModel):
_inherit = 'res.config.settings'

minimum_shelf_life = fields.Integer(
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jgrandguillaume In SAP is documented as 'minimum_remaining_shelf_life'. That would be better understood? Also, why document it at company level? Why not maintain it at product and product category levels?

related='company_id.minimum_shelf_life',
string="Minimum shelf life (in months)",
readonly=False
)
58 changes: 58 additions & 0 deletions stock_minimum_shelf_life/models/stock_move.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,58 @@
# Copyright 2019 Camptocamp
# License AGPL-3.0 or later (https://www.gnu.org/licenses/agpl.html).
from datetime import datetime

from odoo.tools.misc import DEFAULT_SERVER_DATETIME_FORMAT as dt_fmt
from odoo import models


class StockQuant(models.Model):
_inherit = 'stock.quant'

def _gather(self, product_id, location_id, lot_id=None, package_id=None,
owner_id=None, strict=False):
res = super()._gather(
product_id, location_id, lot_id=lot_id,
package_id=package_id, owner_id=owner_id, strict=strict
)

# filter the quants that respect the minimum shelf life date
if "minimum_expiry_shelf_life" in self.env.context:
minimum_expiry_shelf_life = (
self.env.context.get('minimum_expiry_shelf_life')
)
quants = self.search(
[('id', 'in', res.ids),
('lot_id.removal_date', '>', minimum_expiry_shelf_life)
]
)
return quants

return res


class StockMove(models.Model):
_inherit = 'stock.move'

def _action_assign(self):
proc_sales_moves = self.filtered(
lambda m: m.picking_id.group_id.sale_id
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jgrandguillaume are you sure that this should be limited to stock moves for sales to customers? What about checking it also in production orders, so that you don't accept to consume products that have a certain shelf life limit? This is very important, for example, for food processing.

Al alternative could be that the user defines in settings when they want to check minimum shelf life:

  1. Shipping to customers (destination location in the stock move is type customer)
  2. Consuming products for production (destination location in the stock move is type production)

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@jbeficent I agree with you, this is a very good remark.

Will take this into account.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not so easy because if in pick pack ship setup, then the pick make the reservation.. so it's not a customer one yet..

)
groups = proc_sales_moves.mapped('picking_id.group_id')
dates = {}
for k, v in [
(g._get_lot_min_expiration_date().strftime(dt_fmt),
g.id) for g in groups]:
dates.setdefault(k, []).append(v)

for dt, groups_ids in dates.items():
min_shelf_life_date = datetime.strptime(dt, dt_fmt)
moves_filtered = proc_sales_moves.filtered(
lambda m: m.picking_id.group_id.id in groups_ids
)
super(StockMove, moves_filtered.with_context(
minimum_expiry_shelf_life=min_shelf_life_date
))._action_assign()

# run action_assign on other moves
super(StockMove, self - proc_sales_moves)._action_assign()