Skip to content

Commit

Permalink
[ADD] product_expiry_configurable
Browse files Browse the repository at this point in the history
  • Loading branch information
albariera authored and rousseldenis committed Apr 4, 2023
1 parent f386b34 commit a3fcfa4
Show file tree
Hide file tree
Showing 18 changed files with 1,370 additions and 0 deletions.
59 changes: 59 additions & 0 deletions product_expiry_configurable/README.rst
Original file line number Diff line number Diff line change
@@ -0,0 +1,59 @@
===========================
Product Expiry Configurable
===========================

.. !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
!! This file is generated by oca-gen-addon-readme !!
!! changes will be overwritten. !!
!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
.. |badge1| image:: https://img.shields.io/badge/maturity-Beta-yellow.png
:target: https://odoo-community.org/page/development-status
:alt: Beta
.. |badge2| image:: https://img.shields.io/badge/licence-AGPL--3-blue.png
:target: http://www.gnu.org/licenses/agpl-3.0-standalone.html
:alt: License: AGPL-3
.. |badge3| image:: https://img.shields.io/badge/github-tegin%2Fproduct--attribute-lightgray.png?logo=github
:target: https://github.com/tegin/product-attribute/tree/13.0/product_expiry_configurable
:alt: tegin/product-attribute

|badge1| |badge2| |badge3|

This module allows changing the standard expiry dates managing.
Currently, the odoo product_expiry modules compute the use_date, removal_date, life_date, and alert_date applying the use_time, removal_time, life_date, and alert_date to the creation date of the lot. For example, if alert_time is set to 2 days and the lot is created the 16/02/2022, the alert_date is set to 18/02/2022.
With this module, this behavior can be changed. It computes the use_date, removal_date, and alert_date depending on the life_date. For example, if the alert_time is set to 2 days, and the lot life_date is 20/04/2022, the alert_date is set to 18/04/22.
In addition, the times and type of computing (from current_date or life_date) can be configured on the product_category and on the product_template. If a field is provided on the product, the provided on the category is set.
Filters of "Alert Date Reached", "Use Date Reached", "Life Date Reached" and "Removal Date Reached" have been added.
Finally, crons that generate activities have been created to warn for each date. By default, they are desastivated.

**Table of contents**

.. contents::
:local:

Bug Tracker
===========

Bugs are tracked on `GitHub Issues <https://github.com/tegin/product-attribute/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 <https://github.com/tegin/product-attribute/issues/new?body=module:%20product_expiry_configurable%0Aversion:%2013.0%0A%0A**Steps%20to%20reproduce**%0A-%20...%0A%0A**Current%20behavior**%0A%0A**Expected%20behavior**>`_.

Do not contact contributors directly about support or help with technical issues.

Credits
=======

Contributors
~~~~~~~~~~~~

* `CreuBlanca <https://www.creublanca.es>`_:

* Alba Riera <[email protected]>

Maintainers
~~~~~~~~~~~

This module is part of the `tegin/product-attribute <https://github.com/tegin/product-attribute/tree/13.0/product_expiry_configurable>`_ project on GitHub.

You are welcome to contribute.
1 change: 1 addition & 0 deletions product_expiry_configurable/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
from . import models
20 changes: 20 additions & 0 deletions product_expiry_configurable/__manifest__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

{
"name": "Product Expiry Configurable",
"summary": """
This model allows setting expiry times on category and
to use the 'end_of_life' date for the computation of lot dates""",
"version": "13.0.1.0.0",
"license": "AGPL-3",
"author": "Odoo Community Association (OCA)",
"website": "https://github.com/OCA/product-attribute",
"depends": ["product_expiry"],
"data": [
"views/product_category.xml",
"views/product_template.xml",
"views/stock_production_lot.xml",
],
"demo": [],
}
3 changes: 3 additions & 0 deletions product_expiry_configurable/models/__init__.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,3 @@
from . import stock_production_lot
from . import product_template
from . import product_category
155 changes: 155 additions & 0 deletions product_expiry_configurable/models/product_category.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,155 @@
# Copyright 2022 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class ProductCategory(models.Model):

_inherit = "product.category"

compute_dates_from = fields.Selection(
selection=[("current_date", "Current Date"), ("life_date", "Life Time Date")],
help="If current_date is selected, the dates will be computed taking "
"as reference the current date when the lot is created."
"Whereas if life_date is selected, "
"the dates will be computed taking as reference the lot's life_date.",
compute="_compute_compute_dates_from",
)
specific_compute_dates_from = fields.Selection(
selection=[("current_date", "Current Date"), ("life_date", "Life Time Date")],
help="If not provided, the one defined on the parent is used.",
)
parent_compute_dates_from = fields.Selection(
selection=[("current_date", "Current Date"), ("life_date", "Life Time Date")],
compute="_compute_parent_compute_dates_from",
)

life_time = fields.Integer(
string="Product Life Time",
help="Number of days before the goods"
" may become dangerous and must not be consumed. "
"It will be computed on the lot/serial number.",
compute="_compute_date_fields",
)
use_time = fields.Integer(
string="Product Use Time",
help="Number of days before the goods starts deteriorating, "
"without being dangerous yet."
" It will be computed using the lot/serial number.",
compute="_compute_date_fields",
)
removal_time = fields.Integer(
string="Product Removal Time",
help="Number of days before the goods should be removed from the stock. "
"It will be computed on the lot/serial number.",
compute="_compute_date_fields",
)
alert_time = fields.Integer(
string="Product Alert Time",
help="Number of days before an alert should be raised "
"on the lot/serial number.",
compute="_compute_date_fields",
)

specific_life_time = fields.Integer(
string="Specific Product Life Time",
help="Number of days before the goods may become dangerous "
"and must not be consumed. "
"It will be computed on the lot/serial number."
" If not provided, the one defined on the parent is used.",
)
specific_use_time = fields.Integer(
string="Specific Product Use Time",
help="Number of days before the goods starts deteriorating, "
"without being dangerous yet. "
"It will be computed using the lot/serial number."
" If not provided, the one defined on the parent is used.",
)
specific_removal_time = fields.Integer(
string="Specific Product Removal Time",
help="Number of days before the goods should be removed from the stock."
" It will be computed on the lot/serial number."
" If not provided, the one defined on the parent is used.",
)
specific_alert_time = fields.Integer(
string="Specific Product Alert Time",
help="Number of days before an alert should be raised on the lot/serial number."
" If not provided, the one defined on the parent is used.",
)

parent_life_time = fields.Integer(
string="Parent Product Life Time",
help="Number of days before the goods may become dangerous and must not be consumed. "
"It will be computed on the lot/serial number.",
compute="_compute_parent_date_fields",
)
parent_use_time = fields.Integer(
string="Parent Product Use Time",
help="Number of days before the goods starts deteriorating,"
" without being dangerous yet. "
"It will be computed using the lot/serial number.",
compute="_compute_parent_date_fields",
)
parent_removal_time = fields.Integer(
string="Parent Product Removal Time",
help="Number of days before the goods should be removed from the stock. "
"It will be computed on the lot/serial number.",
compute="_compute_parent_date_fields",
)
parent_alert_time = fields.Integer(
string="Parent Product Alert Time",
help="Number of days before an alert should be raised on the lot/serial number.",
compute="_compute_parent_date_fields",
)

@api.depends("specific_compute_dates_from", "parent_compute_dates_from")
def _compute_compute_dates_from(self):
for rec in self:
rec.compute_dates_from = (
rec.specific_compute_dates_from
or rec.parent_compute_dates_from
or "current_date"
)

@api.depends(
"parent_id.specific_compute_dates_from", "parent_id.parent_compute_dates_from"
)
def _compute_parent_compute_dates_from(self):
for rec in self:
parent_id = rec.parent_id
rec.parent_compute_dates_from = (
parent_id.specific_compute_dates_from
or parent_id.parent_compute_dates_from
)

def _get_date_fields(self):
return ["life_time", "use_time", "removal_time", "alert_time"]

def _get_specific_and_parent_date_fields(self):
specific_dates = ["specific_%s" % date for date in self._get_date_fields()]
parent_dates = ["parent_%s" % date for date in self._get_date_fields()]
return specific_dates + parent_dates

@api.depends(lambda r: r._get_specific_and_parent_date_fields())
def _compute_date_fields(self):
for rec in self:
for date in rec._get_date_fields():
specific_value = getattr(rec, "specific_%s" % date)
parent_value = getattr(rec, "parent_%s" % date)
setattr(rec, date, specific_value or parent_value)

def _get_parent_specific_and_parent_date_fields(self):
return [
"parent_id.%s" % date_field
for date_field in self._get_specific_and_parent_date_fields()
]

@api.depends(lambda r: r._get_parent_specific_and_parent_date_fields())
def _compute_parent_date_fields(self):
for rec in self:
for date in self._get_date_fields():
parent_id = rec.parent_id
specific_value = getattr(parent_id, "specific_%s" % date)
parent_value = getattr(parent_id, "parent_%s" % date)
setattr(rec, "parent_%s" % date, specific_value or parent_value)
120 changes: 120 additions & 0 deletions product_expiry_configurable/models/product_template.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,120 @@
# Copyright 2021 Creu Blanca
# License AGPL-3.0 or later (http://www.gnu.org/licenses/agpl).

from odoo import api, fields, models


class ProductTemplate(models.Model):

_inherit = "product.template"

compute_dates_from = fields.Selection(
selection=[("current_date", "Current Date"), ("life_date", "Life Date")],
help="If current_date is selected, "
"the dates will be computed taking as reference "
"the current date when the lot is created."
"Whereas if life_date is selected,"
" the dates will be computed taking as reference the lot's life_date.",
compute="_compute_compute_dates_from",
)
specific_compute_dates_from = fields.Selection(
selection=[("current_date", "Current Date"), ("life_date", "Life Date")],
help="If current_date is selected, "
"the dates will be computed taking as reference "
"the current date when the lot is created."
"Whereas if life_date is selected,"
" the dates will be computed taking as reference the lot's life_date.",
)
category_compute_dates_from = fields.Selection(
selection=[("current_date", "Current Date"), ("life_date", "Life Date")],
help="If current_date is selected, "
"the dates will be computed taking as reference "
"the current date when the lot is created."
"Whereas if life_date is selected, "
"the dates will be computed taking as reference the lot's life_date.",
related="categ_id.compute_dates_from",
string="Category Compute Dates From",
)

life_time = fields.Integer(compute="_compute_date_fields")
use_time = fields.Integer(compute="_compute_date_fields")
removal_time = fields.Integer(compute="_compute_date_fields")
alert_time = fields.Integer(compute="_compute_date_fields")

specific_life_time = fields.Integer(
string="Specific Product Life Time",
help="Number of days before the goods may "
"become dangerous and must not be consumed. "
"It will be computed on the lot/serial number."
"If not provided, the one defined on the category is used.",
)
specific_use_time = fields.Integer(
string="Specific Product Use Time",
help="Number of days before the goods starts deteriorating,"
" without being dangerous yet. "
"It will be computed using the lot/serial number."
"If not provided, the one defined on the category is used.",
)
specific_removal_time = fields.Integer(
string="Specific Product Removal Time",
help="Number of days before the goods should be removed from the stock. "
"It will be computed on the lot/serial number."
"If not provided, the one defined on the category is used.",
)
specific_alert_time = fields.Integer(
string="Specific Product Alert Time",
help="Number of days before an alert should be raised on the lot/serial number."
"If not provided, the one defined on the category is used.",
)

category_life_time = fields.Integer(
string="Category Product Life Time",
help="Number of days before the goods may become "
"dangerous and must not be consumed. "
"It will be computed on the lot/serial number.",
related="categ_id.life_time",
)
category_use_time = fields.Integer(
string="Category Product Use Time",
help="Number of days before the goods starts deteriorating,"
" without being dangerous yet."
" It will be computed using the lot/serial number.",
related="categ_id.use_time",
)
category_removal_time = fields.Integer(
string="Category Product Removal Time",
help="Number of days before the goods should be removed from the stock. "
"It will be computed on the lot/serial number.",
related="categ_id.removal_time",
)
category_alert_time = fields.Integer(
string="Category Product Alert Time",
help="Number of days before an alert should be raised "
"on the lot/serial number.",
related="categ_id.alert_time",
)

def _get_date_fields(self):
return ["life_time", "use_time", "removal_time", "alert_time"]

@api.depends("specific_compute_dates_from", "category_compute_dates_from")
def _compute_compute_dates_from(self):
for rec in self:
rec.compute_dates_from = (
rec.specific_compute_dates_from
or rec.category_compute_dates_from
or "current_date"
)

def _get_specific_and_category_date_fields(self):
specific_dates = ["specific_%s" % date for date in self._get_date_fields()]
category_dates = ["category_%s" % date for date in self._get_date_fields()]
return specific_dates + category_dates

@api.depends(lambda r: r._get_specific_and_category_date_fields())
def _compute_date_fields(self):
for rec in self:
for date in rec._get_date_fields():
specific_value = getattr(rec, "specific_%s" % date)
category_value = getattr(rec, "category_%s" % date)
setattr(rec, date, specific_value or category_value)
Loading

0 comments on commit a3fcfa4

Please sign in to comment.