diff --git a/odoo_product_expiry_dashboard/README.rst b/odoo_product_expiry_dashboard/README.rst new file mode 100644 index 000000000..8203c04c7 --- /dev/null +++ b/odoo_product_expiry_dashboard/README.rst @@ -0,0 +1,45 @@ +.. image:: https://img.shields.io/badge/license-AGPL--3-blue.svg + :target: https://www.gnu.org/licenses/agpl-3.0-standalone.html + :alt: License: AGPL-3 + +Product Expiry Dashboard +======================== +This Module help to analyse products and their expiry + +Configuration +============= +* No configuration needed + +Company +------- +* `Cybrosys Techno Solutions `__ + +Credits +------- +* Developer: (V16) Hafeesul Ali, Kailas Krishna + Contact: odoo@cybrosys.com + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + +License +------- +General Public License, Version 3 (AGPL v3). +(https://www.gnu.org/licenses/agpl-3.0-standalone.html) + +Bug Tracker +----------- +Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. + +Maintainer +========== +.. image:: https://cybrosys.com/images/logo.png + :target: https://cybrosys.com +This module is maintained by Cybrosys Technologies. +For support and more information, please visit `Our Website `__ + +Further information +=================== +HTML Description: ``__ diff --git a/odoo_product_expiry_dashboard/__init__.py b/odoo_product_expiry_dashboard/__init__.py new file mode 100644 index 000000000..fbfecab9b --- /dev/null +++ b/odoo_product_expiry_dashboard/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import models diff --git a/odoo_product_expiry_dashboard/__manifest__.py b/odoo_product_expiry_dashboard/__manifest__.py new file mode 100644 index 000000000..60ffc2f5d --- /dev/null +++ b/odoo_product_expiry_dashboard/__manifest__.py @@ -0,0 +1,48 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +{ + 'name': 'Product Expiry Dashboard', + 'version': '16.0.1.0.0', + 'category': 'Productivity', + 'summary': 'This module provides visualized product expiry data', + 'description': 'This module presents visualized charts showcasing ' + 'product expiration data categorized by location and ' + 'category', + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': 'https://www.cybrosys.com', + 'depends': ['product_expiry', 'stock'], + 'data': ['views/product_expiry_views.xml'], + 'assets': { + 'web.assets_backend': [ + 'odoo_product_expiry_dashboard/static/src/js/product_expiry_action.js', + 'odoo_product_expiry_dashboard/static/src/xml/product_expiry_dashboard.xml', + 'odoo_product_expiry_dashboard/static/src/css/style.css', + 'https://cdn.jsdelivr.net/npm/chart.js' + ]}, + 'images': ['static/description/banner.jpg'], + 'license': 'AGPL-3', + 'installable': True, + 'auto_install': False, + 'application': False +} diff --git a/odoo_product_expiry_dashboard/doc/RELEASE_NOTES.md b/odoo_product_expiry_dashboard/doc/RELEASE_NOTES.md new file mode 100644 index 000000000..f2dedd75a --- /dev/null +++ b/odoo_product_expiry_dashboard/doc/RELEASE_NOTES.md @@ -0,0 +1,6 @@ +## Module + +#### 17.08.2024 +#### Version 16.0.1.0.0 +#### ADD +- Initial commit for Product Expiry Dashboard diff --git a/odoo_product_expiry_dashboard/models/__init__.py b/odoo_product_expiry_dashboard/models/__init__.py new file mode 100644 index 000000000..7918cee0a --- /dev/null +++ b/odoo_product_expiry_dashboard/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +from . import stock_lot diff --git a/odoo_product_expiry_dashboard/models/stock_lot.py b/odoo_product_expiry_dashboard/models/stock_lot.py new file mode 100644 index 000000000..fa58d2b8a --- /dev/null +++ b/odoo_product_expiry_dashboard/models/stock_lot.py @@ -0,0 +1,304 @@ +# -*- coding: utf-8 -*- +############################################################################# +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2024-TODAY Cybrosys Technologies(). +# Author: Cybrosys Techno Solutions() +# +# You can modify it under the terms of the GNU AFFERO +# GENERAL PUBLIC LICENSE (AGPL v3), Version 3. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU AFFERO GENERAL PUBLIC LICENSE (AGPL v3) for more details. +# +# You should have received a copy of the GNU AFFERO GENERAL PUBLIC LICENSE +# (AGPL v3) along with this program. +# If not, see . +# +############################################################################# +from odoo import api, fields, models + + +class StockLot(models.Model): + _inherit = "stock.lot" + + @api.model + def search_params(self, start_date, end_date, enabled_companies): + """Method to get domain for searching.""" + if start_date and end_date: + search_params = [('expiration_date', '>=', start_date), + ('expiration_date', '<=', end_date), + ('company_id', 'in', enabled_companies)] + elif start_date: + search_params = [('expiration_date', '>=', start_date), + ('company_id', 'in', enabled_companies)] + else: + search_params = [('company_id', 'in', enabled_companies)] + return search_params + + @api.model + def get_product_expiry(self, *args): + """Method to get products that expires in 1 day ,7 days,30 days + and 120 days. + Args: + *args(dict):Start date and End date to add filtration + Returns: + dict: A dict contains 1 day ,7 day ,30 day,120 day, and their + respective counts of products that will expire. + """ + data = [{"one_day": [], "counts": 0}, + {"seven_day": [], "counts": 0}, + {"thirty_day": [], "counts": 0}, + {"one_twenty_day": [], "counts": 0}] + search_params = self.search_params(args[0].get('start_date'), + args[0].get('end_date'), args[1]) + for record in self.search(search_params): + if record.expiration_date and record.product_qty != 0: + date_difference = (fields.Date.to_date( + record.expiration_date) - fields.Date.today()).days + if date_difference == 1: + data[0]["one_day"].append(record.id) + data[0]["counts"] += record.product_qty + elif 7 >= date_difference >= 1: + data[1]["seven_day"].append(record.id) + data[1]["counts"] += record.product_qty + elif 30 >= date_difference > 7: + data[2]["thirty_day"].append(record.id) + data[2]["counts"] += record.product_qty + elif 120 >= date_difference > 30: + data[3]["one_twenty_day"].append(record.id) + return data + + @api.model + def get_product_expired_today(self, enabled_companies): + """ + Method to get products that expired today + Returns: + int:count of products. + """ + count = len([record for record in self.search([]) if + record.expiration_date and + fields.Date.to_date(record.expiration_date) == fields.date.today() and + record.company_id.id in enabled_companies]) + return count + + @api.model + def get_expired_product(self, *args): + """ + Method to get products that expired + Args: + *args(dict):Start date and End date to add filtration. + Returns: + dict: A dict that contains expired products and their count. + """ + search_params = self.search_params(args[0].get('start_date'), + args[0].get('end_date')) + products_dict = {record: {'product_qty': record.product_qty, + 'product': record.product_id.name} + for record in self.search(search_params) + if record.expiration_date and record.product_qty != 0 + and record.product_expiry_alert} + expired_products_dict = {product: sum(data['product_qty'] + for lot, data in + products_dict.items() if + data['product'] == product) + for product in set( + data['product'] for lot, data in products_dict.items())} + return expired_products_dict + + @api.model + def get_product_expiry_by_category(self, *args): + """ + Method to get category of products that expired. + Args: + *args(dict):Start date and End date to add filtration. + Returns: + dict: A dict that contains expired products category and their + count. + """ + search_params = self.search_params(args[0].get('start_date'), + args[0].get('end_date')) + products_category_dict = {record: {'product_qty': record.product_qty, + 'product_category': + record.product_id.categ_id.name} + for record in self.search(search_params) + if record.expiration_date and + record.product_qty != 0 + and record.product_expiry_alert} + expired_product_category_dict = {product: sum(data['product_qty'] + for lot, data in + products_category_dict. + items() if + data['product_category'] + == product) + for product in + set(data['product_category'] + for lot, data in + products_category_dict.items())} + return expired_product_category_dict + + @api.model + def get_near_expiry_product(self, *args): + """ + Method to get products that will expire in coming 7 days. + Returns: + dict:A dict that contains products and their count + """ + search_params = self.search_params(args[0].get('start_date'), + args[0].get('end_date')) + if len(search_params) != 0: + product_dict = {record: {'product_name': record.product_id.name, + 'product_qty': record.product_qty + } + for record in self.search(search_params) + if + record.expiration_date and record.product_qty != 0} + + else: + product_dict = {record: {'product_name': record.product_id.name, + 'product_qty': record.product_qty + } + for record in self.search([]) + if + record.expiration_date and record.product_qty and 7 >= + (fields.Date.to_date(record.expiration_date) - + fields.Date.today()).days > 0} + nearby_exp_products_dict = {product: sum( + data['product_qty'] for lot, data in product_dict.items() if + data['product_name'] == product) + for product in + set(data['product_name'] for lot, data in + product_dict.items()) + } + return nearby_exp_products_dict + + @api.model + def get_near_expiry_category(self, *args): + """ + Method to get cate'gory of products that will expire in coming 7 days. + Returns: + dict:A dict that contains category and their count + """ + search_params = self.search_params(args[0].get('start_date'), + args[0].get('end_date')) + if len(search_params) != 0: + product_dict = { + record: {'category': record.product_id.categ_id.name, + 'product_qty': record.product_qty + } + for record in self.search(search_params) + if + record.expiration_date and record.product_qty != 0} + else: + product_dict = {record: {'category': record.product_id.categ_id.name, + 'product_qty': record.product_qty + } + for record in self.search([]) + if + record.expiration_date and record.product_qty and 7 >= + (fields.Date.to_date(record.expiration_date) - + fields.Date.today()).days > 0} + + nearby_exp_products_dict = {product: sum( + data['product_qty'] for lot, data in product_dict.items() if + data['category'] == product) + for product in + set(data['category'] for lot, data in + product_dict.items()) + } + return nearby_exp_products_dict + + @api.model + def get_expire_product_location(self, *args): + """Method to get products locations that will expire + in coming 7 days + Returns: + dict:A dict of location and their respective count + """ + search_params = self.search_params(args[0].get('start_date'), + args[0].get('end_date')) + if len(search_params) != 0: + location_dict = { + record: {'location': location.location_id.display_name, + 'count': location.inventory_quantity_auto_apply} for + record in self.search(search_params) if + record.expiration_date and record.product_qty != 0 + for location in record.quant_ids if + location.inventory_quantity_auto_apply > 0} + else: + location_dict = { + record: {'location': location.location_id.display_name, + 'count': location.inventory_quantity_auto_apply} for + record in self.search([]) if + record.expiration_date and record.product_qty and 7 >= ( + fields.Date.to_date(record.expiration_date) - fields.Date.today()).days > 0 + for location in record.quant_ids if + location.inventory_quantity_auto_apply > 0} + nearby_expiry_location = {product: sum( + data['count'] for lot, data in location_dict.items() if + data['location'] == product) for product in set( + data['location'] for lot, data in location_dict.items())} + return nearby_expiry_location + + @api.model + def get_expire_product_warehouse(self, *args): + """Method to get products warehouse that will expire + in coming 7 days + Returns: + dict:A dict of warehouse and their respective counts. + """ + search_params = self.search_params(args[0].get('start_date'), + args[0].get('end_date')) + if len(search_params) != 0: + warehouse_dict = { + record: { + 'warehouse': location.location_id.warehouse_id.display_name, + 'count': location.inventory_quantity_auto_apply} for + record in self.search([]) if + record.expiration_date and record.product_qty != 0 + for location in record.quant_ids if + location.inventory_quantity_auto_apply > 0} + else: + warehouse_dict = { + record: { + 'warehouse': location.location_id.warehouse_id.display_name, + 'count': location.inventory_quantity_auto_apply} for + record in self.search([]) if + record.expiration_date and record.product_qty and 7 >= ( + fields.Date.to_date( + record.expiration_date) - fields.Date.today()).days > 0 + for location in record.quant_ids if + location.inventory_quantity_auto_apply > 0} + nearby_expiry_warehouse = {product: sum( + data['count'] for lot, data in warehouse_dict.items() if + data['warehouse'] == product) for product in set( + data['warehouse'] for lot, data in warehouse_dict.items())} + return nearby_expiry_warehouse + + @api.model + def get_today_expire(self): + """Method to get products that will expire current day + Returns: + A dict which includes list of products id, + list of products name, list of products quantity, and + list of products category. + """ + data = {'id': [], 'name': [], 'qty': [], 'categ': []} + for line in self.search([]): + if line.expiration_date and line.expiration_date.date() == fields.date.today(): + data['id'].append(line.id) + data['name'].append(line.product_id.name) + data['qty'].append(line.product_qty) + found_category = False + for rec in data['categ']: + for key, value in rec.items(): + if line.product_id.categ_id.name == key: + rec[key] += line.product_qty + found_category = True + break + if not found_category: + data['categ'].append({line.product_id.categ_id.name: line.product_qty}) + return data diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/check.png b/odoo_product_expiry_dashboard/static/description/assets/icons/check.png new file mode 100644 index 000000000..c8e85f51d Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/check.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/chevron.png b/odoo_product_expiry_dashboard/static/description/assets/icons/chevron.png new file mode 100644 index 000000000..2089293d6 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/chevron.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/cogs.png b/odoo_product_expiry_dashboard/static/description/assets/icons/cogs.png new file mode 100644 index 000000000..95d0bad62 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/cogs.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/consultation.png b/odoo_product_expiry_dashboard/static/description/assets/icons/consultation.png new file mode 100644 index 000000000..8319d4baa Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/consultation.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/ecom-black.png b/odoo_product_expiry_dashboard/static/description/assets/icons/ecom-black.png new file mode 100644 index 000000000..a9385ff13 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/ecom-black.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/education-black.png b/odoo_product_expiry_dashboard/static/description/assets/icons/education-black.png new file mode 100644 index 000000000..3eb09b27b Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/education-black.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/hotel-black.png b/odoo_product_expiry_dashboard/static/description/assets/icons/hotel-black.png new file mode 100644 index 000000000..130f613be Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/hotel-black.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/license.png b/odoo_product_expiry_dashboard/static/description/assets/icons/license.png new file mode 100644 index 000000000..a5869797e Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/license.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/lifebuoy.png b/odoo_product_expiry_dashboard/static/description/assets/icons/lifebuoy.png new file mode 100644 index 000000000..658d56ccc Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/lifebuoy.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/logo.png b/odoo_product_expiry_dashboard/static/description/assets/icons/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/logo.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/manufacturing-black.png b/odoo_product_expiry_dashboard/static/description/assets/icons/manufacturing-black.png new file mode 100644 index 000000000..697eb0e9f Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/manufacturing-black.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/pos-black.png b/odoo_product_expiry_dashboard/static/description/assets/icons/pos-black.png new file mode 100644 index 000000000..97c0f90c1 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/pos-black.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/puzzle.png b/odoo_product_expiry_dashboard/static/description/assets/icons/puzzle.png new file mode 100644 index 000000000..65cf854e7 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/puzzle.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/restaurant-black.png b/odoo_product_expiry_dashboard/static/description/assets/icons/restaurant-black.png new file mode 100644 index 000000000..4a35eb939 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/restaurant-black.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/service-black.png b/odoo_product_expiry_dashboard/static/description/assets/icons/service-black.png new file mode 100644 index 000000000..301ab51cb Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/service-black.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/trading-black.png b/odoo_product_expiry_dashboard/static/description/assets/icons/trading-black.png new file mode 100644 index 000000000..9398ba2f1 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/trading-black.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/training.png b/odoo_product_expiry_dashboard/static/description/assets/icons/training.png new file mode 100644 index 000000000..884ca024d Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/training.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/update.png b/odoo_product_expiry_dashboard/static/description/assets/icons/update.png new file mode 100644 index 000000000..ecbc5a01a Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/update.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/user.png b/odoo_product_expiry_dashboard/static/description/assets/icons/user.png new file mode 100644 index 000000000..6ffb23d9f Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/user.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/icons/wrench.png b/odoo_product_expiry_dashboard/static/description/assets/icons/wrench.png new file mode 100644 index 000000000..6c04dea0f Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/icons/wrench.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/categories.png b/odoo_product_expiry_dashboard/static/description/assets/misc/categories.png new file mode 100644 index 000000000..bedf1e0b1 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/categories.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/check-box.png b/odoo_product_expiry_dashboard/static/description/assets/misc/check-box.png new file mode 100644 index 000000000..42caf24b9 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/check-box.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/compass.png b/odoo_product_expiry_dashboard/static/description/assets/misc/compass.png new file mode 100644 index 000000000..d5fed8faa Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/compass.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/corporate.png b/odoo_product_expiry_dashboard/static/description/assets/misc/corporate.png new file mode 100644 index 000000000..2eb13edbf Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/corporate.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/customer-support.png b/odoo_product_expiry_dashboard/static/description/assets/misc/customer-support.png new file mode 100644 index 000000000..79efc72ed Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/customer-support.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/cybrosys-logo.png b/odoo_product_expiry_dashboard/static/description/assets/misc/cybrosys-logo.png new file mode 100644 index 000000000..cc3cc0ccf Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/cybrosys-logo.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/features.png b/odoo_product_expiry_dashboard/static/description/assets/misc/features.png new file mode 100644 index 000000000..b41769f77 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/features.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/logo.png b/odoo_product_expiry_dashboard/static/description/assets/misc/logo.png new file mode 100644 index 000000000..478462d3e Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/logo.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/pictures.png b/odoo_product_expiry_dashboard/static/description/assets/misc/pictures.png new file mode 100644 index 000000000..56d255fe9 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/pictures.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/pie-chart.png b/odoo_product_expiry_dashboard/static/description/assets/misc/pie-chart.png new file mode 100644 index 000000000..426e05244 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/pie-chart.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/right-arrow.png b/odoo_product_expiry_dashboard/static/description/assets/misc/right-arrow.png new file mode 100644 index 000000000..730984a06 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/right-arrow.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/star.png b/odoo_product_expiry_dashboard/static/description/assets/misc/star.png new file mode 100644 index 000000000..2eb9ab29f Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/star.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/support.png b/odoo_product_expiry_dashboard/static/description/assets/misc/support.png new file mode 100644 index 000000000..4f18b8b82 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/support.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/misc/whatsapp.png b/odoo_product_expiry_dashboard/static/description/assets/misc/whatsapp.png new file mode 100644 index 000000000..d513a5356 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/misc/whatsapp.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/module01.png b/odoo_product_expiry_dashboard/static/description/assets/modules/module01.png new file mode 100644 index 000000000..b145c7a29 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/module01.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/module02.png b/odoo_product_expiry_dashboard/static/description/assets/modules/module02.png new file mode 100644 index 000000000..f3c986fc1 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/module02.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/module03.png b/odoo_product_expiry_dashboard/static/description/assets/modules/module03.png new file mode 100644 index 000000000..5c56f0bcd Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/module03.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/module04.png b/odoo_product_expiry_dashboard/static/description/assets/modules/module04.png new file mode 100644 index 000000000..6c8c8adc3 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/module04.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/module05.png b/odoo_product_expiry_dashboard/static/description/assets/modules/module05.png new file mode 100644 index 000000000..25ed3e0b6 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/module05.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/module06.png b/odoo_product_expiry_dashboard/static/description/assets/modules/module06.png new file mode 100644 index 000000000..17c14989e Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/module06.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/01.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/01.png new file mode 100644 index 000000000..2808405fc Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/01.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/1.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/1.png new file mode 100644 index 000000000..b00ba1be1 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/1.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/2.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/2.png new file mode 100644 index 000000000..53e705a03 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/2.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/3.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/3.png new file mode 100644 index 000000000..cd0b87941 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/3.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/4.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/4.png new file mode 100644 index 000000000..4e0c0188c Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/4.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/5.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/5.png new file mode 100644 index 000000000..87ffa10ee Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/5.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/6.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/6.png new file mode 100644 index 000000000..96e6a9488 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/6.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/7.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/7.png new file mode 100644 index 000000000..0f2baef65 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/7.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/8.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/8.png new file mode 100644 index 000000000..119b399f2 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/8.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/9.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/9.png new file mode 100644 index 000000000..d0dee6a05 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/9.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/hero.gif b/odoo_product_expiry_dashboard/static/description/assets/screenshots/hero.gif new file mode 100644 index 000000000..334aaf725 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/hero.gif differ diff --git a/odoo_product_expiry_dashboard/static/description/banner.jpg b/odoo_product_expiry_dashboard/static/description/banner.jpg new file mode 100644 index 000000000..d7c94f2b3 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/banner.jpg differ diff --git a/odoo_product_expiry_dashboard/static/description/icon.png b/odoo_product_expiry_dashboard/static/description/icon.png new file mode 100644 index 000000000..1c2e2edc2 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/icon.png differ diff --git a/odoo_product_expiry_dashboard/static/description/index.html b/odoo_product_expiry_dashboard/static/description/index.html new file mode 100644 index 000000000..4def7021f --- /dev/null +++ b/odoo_product_expiry_dashboard/static/description/index.html @@ -0,0 +1,631 @@ +
+ +
+ +
+
+ Community +
+
+ Enterprise +
+
+
+ + + +

Product Expiry Dashboard

+

Allows To View All Product Details Those Are About To Expire.

+ + +
+ + +
+
+ +
+

Explore This + Module

+
+ + + + +
+
+ +
+

Overview +

+
+
+
+ The Product Expiry Dashboard provides information on the number of + expired and nearly expiring products. It also offers a graphical view of + these products, along with their respective locations and warehouses. + This application facilitates swift decision-making by allowing users to + monitor items that are approaching their expiration dates. +
+
+ + + +
+
+ +
+

Features +

+
+
+
+
+ + Contains Tiles for displaying Count of Products which will Expire soon based on their Expiry Date.. +
+
+ + Analyse your products expiry on which location and date. +
+
+ + Shows all Products which are already Expired. +
+
+ + Graphical view of Expired Products. +
+
+ + Graphical view of Nearly Expiring Products based on their Location and Warehouse. +
+
+ + Community & Enterprise Support. +
+
+
+ + + +
+
+ +
+

Screenshots +

+
+
+
+
+

Product Expiry Dashboard.

+

+ Navigate to Inventory --> Product Expiry Dashboard menu. +

+ +
+
+
+
+
+
+

Product Expiry Dashboard.

+

+ 1.We can view items that have reached their expiration date + today, those expiring within a day, a week, thirty days, and + one hundred and twenty days
+ 2.Additionally, we can also observe items that have already + expired, as well as expired items categorized by their + respective product categories +

+ +
+
+
+
+
+
+

Different Charts.

+

+ We can view products expiring within 7 days by categorized by category, location and warehouse. +

+ +
+
+
+
+
+
+

Product Expired Today

+

+ We can see count of products expired today, with a clickable button + that redirects to the product list view. +

+ +
+
+
+
+
+
+

List View of Products Expired Today.

+ +
+
+
+
+
+
+

Products Expiry Cards

+

+ Cards displaying product count expiring tomorrow, in 7 days, + 30 days and 120 days, each clickable to redirect to its corresponding list view. +

+ +
+
+
+
+
+
+

List View of Products Expiry in Tomorrow

+ +
+
+
+
+
+
+

Card Filtration

+

+ The cards can be filtered using date. +

+ +
+
+
+
+
+
+

Graphs based on Card Filtration

+ +
+
+
+
+
+
+

Total Expired Products

+

+ Total expired products based on product name and product catrgory. +

+ +
+
+
+ + + + +
+
+ +
+

Related + Products +

+
+
+
+ +
+
+ + + + +
+
+ +
+

Our Services +

+
+ +
+
+
+
+ +
+
+ Odoo + Customization
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Support
+
+ + +
+
+ +
+
+ Hire + Odoo + Developer
+
+ +
+
+ +
+
+ Odoo + Integration
+
+ +
+
+ +
+
+ Odoo + Migration
+
+ + +
+
+ +
+
+ Odoo + Consultancy
+
+ +
+
+ +
+
+ Odoo + Implementation
+
+ +
+
+ +
+
+ Odoo + Licensing Consultancy
+
+
+
+ + + +
+
+ +
+

Our + Industries +

+
+ +
+
+
+
+ +
+ Trading +
+

+ Easily procure + and + sell your products

+
+
+
+
+ +
+ POS +
+

+ Easy + configuration + and convivial experience

+
+
+
+
+ +
+ Education +
+

+ A platform for + educational management

+
+
+
+
+ +
+ Manufacturing +
+

+ Plan, track and + schedule your operations

+
+
+
+
+ +
+ E-commerce & Website +
+

+ Mobile + friendly, + awe-inspiring product pages

+
+
+
+
+ +
+ Service Management +
+

+ Keep track of + services and invoice

+
+
+
+
+ +
+ Restaurant +
+

+ Run your bar or + restaurant methodically

+
+
+ +
+
+ +
+ Hotel Management +
+

+ An + all-inclusive + hotel management application

+
+
+
+
+ + + +
+
+ +
+

Support

+
+
+
+
+
+
+ +
+
+

Need Help?

+

Got questions or need help? Get in touch.

+ +

odoo@cybrosys.com

+
+
+
+
+
+
+
+ +
+
+

WhatsApp

+

Say hi to us on WhatsApp!

+ +

+91 8606827707

+
+
+
+
+
+
+
+ +
+
+
+ diff --git a/odoo_product_expiry_dashboard/static/src/css/style.css b/odoo_product_expiry_dashboard/static/src/css/style.css new file mode 100644 index 000000000..06cf44ec0 --- /dev/null +++ b/odoo_product_expiry_dashboard/static/src/css/style.css @@ -0,0 +1,76 @@ +.order-card { + color: #fff; +} + +.bg-c-blue { + background: linear-gradient(45deg,#4099ff,#73b4ff); +} + +.bg-c-green { + background: linear-gradient(45deg,#2ed8b6,#59e0c5); +} + +.bg-c-yellow { + background: linear-gradient(45deg,#FFB64D,#ffcb80); +} + +.bg-c-pink { + background: linear-gradient(45deg,#FF5370,#ff869a); +} + +.card { + border-radius: 5px; + -webkit-box-shadow: 0 1px 2.94px 0.06px rgba(4,26,55,0.16); + box-shadow: 0 1px 2.94px 0.06px rgba(4,26,55,0.16); + border: none; + margin-bottom: 30px; + -webkit-transition: all 0.3s ease-in-out; + transition: all 0.3s ease-in-out; +} + +.card .card-block { + padding: 25px; +} + +.order-card i { + font-size: 26px; +} + +.f-left { + float: left; +} + +.f-right { + float: right; +} + +.card-block:hover{ + box-shadow: 5px 5px 10px #ccc; +} + +.expiry_dashboard_row{ + padding-left: 50px; + padding-right: 50px; +} + +.dashboard-heading{ + min-height: 140px; + padding: 20px; + text-align: center; + background: #376270; +} + +.banner-heading { + color: #ffffff; + font-size: 44px; + margin: 0; + margin-top: 20px; + } + +.product_expired_heading{ + background: aliceblue; + width: 236px; + float: left; + border-radius: 16px; + height: 102px; +} diff --git a/odoo_product_expiry_dashboard/static/src/js/product_expiry_action.js b/odoo_product_expiry_dashboard/static/src/js/product_expiry_action.js new file mode 100644 index 000000000..0e3a2a952 --- /dev/null +++ b/odoo_product_expiry_dashboard/static/src/js/product_expiry_action.js @@ -0,0 +1,602 @@ +/** @odoo-module */ +import { registry } from "@web/core/registry" +import rpc from 'web.rpc'; +const { Component, onWillStart, useState } = owl; +const actionRegistry = registry.category("actions"); +var session = require('web.session'); + +export class ProductExpiryDashboard extends Component { + setup() { + super.setup(...arguments); + this.state = useState({ + data: null, + charts:[] + }) + onWillStart(async () => { + await this.fetch_products_expiry() + await this.product_expired_today() + await this.get_today_expire_products() + await this.get_today_expire_products_category() + await this.near_exp_products() + await this.near_exp_category() + await this.get_expire_product_location() + await this.get_expire_product_warehouse() + await this.render_expired_products_graph() + await this.expiry_by_category() + }); + } +// Filter products based on the specified start and end dates. + async filter_date(ev) { + // Get the start and end dates selected by the user from input fields. + var start_date = $("#start_date").val(); + var end_date = $("#end_date").val(); + if (this.state.charts.length != 0) { + this.state.charts.forEach((item)=> { + item.destroy() + }); + } + // Fetch and display products that fall within the specified date range. + await this.fetch_products_expiry(start_date, end_date); + await this.near_exp_products(start_date, end_date); + await this.near_exp_category(start_date, end_date); + await this.get_expire_product_location(start_date, end_date); + await this.get_expire_product_warehouse(start_date, end_date); + await this.render_expired_products_graph(start_date, end_date); + await this.expiry_by_category(start_date, end_date); + } + fetch_products_expiry(start_date, end_date) { + // Remove existing elements before updating the product expiry counts. + $("#one_day").remove(); + $("#seven_day").remove(); + $("#thirty_day").remove(); + $("#one_twenty_day").remove(); + var self = this; + // Prepare the date dictionary to pass as an argument in the RPC query. + var date_dict = { 'start_date': start_date, 'end_date': end_date }; + // Send an RPC query to fetch product expiry data from the server. + rpc.query({ + model: 'stock.lot', + method: 'get_product_expiry', + args: [date_dict, session.user_context.allowed_company_ids] + }).then(function(result) { + self.state.data = result + var seven_day = result[0]['counts'] + result[1]['counts']; + // Update the HTML elements to display the product counts for different expiry periods. + $(".one-day").append('
' + + '' + result[0]['counts'] + '' + + '
'); + $(".seven-day").append('
' + + '' + seven_day + '' + + '
'); + $(".thirty-day").append('
' + + '' + result[2]['counts'] + '' + + '
'); + $(".one-twenty-day").append('
' + + '' + result[3]['counts'] + '' + + '
'); + }); + } +// Fetches the count of products that have expired today using an +// RPC query and updates the HTML element to display the count. + product_expired_today() { + // Send an RPC query to fetch the count of products that have expired today. + rpc.query({ + model: 'stock.lot', + method: 'get_product_expired_today', + args: [session.user_context.allowed_company_ids] + }).then(function (result) { + // Update the HTML element to display the count of products expired today. + $('.product_expired_heading').append('

' + result + '

'); + + }); + } +// Fetches the list of products that have expired today + click_expired_today() { + var self = this; + rpc.query({ + model: 'stock.lot', + method: 'get_today_expire', + }).then(function (result) { + var id = [] + for( var data in result['id']){ + id.push(parseInt(result['id'][data])) + } + // Perform the action to display products that have expired on the current day. + self.env.services['action'].doAction({ + name: "Products Expired Today", + type: 'ir.actions.act_window', + res_model: 'stock.lot', + views: [[false, 'tree'], [false, 'form']], + domain: [['id', 'in', id]], + target: 'current', + context: { + 'create': false + } + }); + }); + } +// Fetches the list of products that have expired within 1 day(tomorrow) + one_day_click() { + // Perform the action to display products that are expiring in one day with negative product quantities. + this.env.services['action'].doAction({ + name: "Expiry Tomorrow", + type: 'ir.actions.act_window', + res_model: 'stock.lot', + views: [[false, 'tree'], [false, 'form']], + domain: [['id', 'in', this.state.data[0]['one_day']]], + target: 'current', + context: { + 'create': false + } + }); + } +// Fetches the list of products that have expired with in 7days + seven_day_click() { + const ids = [...this.state.data[1]['seven_day'], ...this.state.data[0]['one_day']] + // Perform the action to display products that are expiring within the seven-day range. + this.env.services['action'].doAction({ + name: "Expiry in Seven Days", + type: 'ir.actions.act_window', + res_model: 'stock.lot', + views: [[false, 'tree'], [false, 'form']], + domain: [['id', 'in', ids]], + target: 'current', + context: { + 'create': false + } + }); + } +// Fetches the list of products that have expired in 30 days + thirty_day_click() { + const ids = [...this.state.data[2]['thirty_day']] + // Perform the action to display products that are expiring within the thirty-day range. + this.env.services['action'].doAction({ + name: "Expiry in Thirty Days", + type: 'ir.actions.act_window', + res_model: 'stock.lot', + views: [[false, 'tree'], [false, 'form']], + domain: [['id', 'in', ids]], + target: 'current', + context: { + 'create': false + } + }); + } +// Fetches the list of products that have expired in 120 days + one_twenty_day_click() { + const ids = [...this.state.data[3]['one_twenty_day']] + // Perform the action to display products that are expiring within the one hundred twenty-day range. + this.env.services['action'].doAction({ + name: "Expiry in One Twenty Days", + type: 'ir.actions.act_window', + res_model: 'stock.lot', + views: [[false, 'tree'], [false, 'form']], + domain: [['id', 'in', ids]], + target: 'current', + context: { + 'create': false + } + }); + } +// Line Chart for Products Expired Today + get_today_expire_products() { + // Initialize arrays to hold product warehouse names and their corresponding quantities. + var expire_product_name = []; + var expire_product_qty = []; + // Send an RPC query to fetch data about products that are about to expire, categorized by their warehouses, from the server. + rpc.query({ + model: 'stock.lot', + method: 'get_today_expire', + }).then(function (result) { + for( var data in result['name']){ + expire_product_name.push(result['name'][data]) + expire_product_qty.push(parseInt(result['qty'][data])) + } + // Render the bar chart using Chart.js. + const ctx = $('#today_expire_products'); + new Chart(ctx, { + type: 'line', + data: { + labels: expire_product_name, + datasets: [{ + label: 'Quantity', + data: expire_product_qty, + borderWidth: 1 + }] + }, + options: { + plugins: { + legend: { + position: 'bottom', + }, + title: { + display: true, + } + } + } + }); + }); + } +// Bar chart for Products Expired Today by Category + get_today_expire_products_category() { + // Initialize arrays to hold product warehouse names and their corresponding quantities. + var expire_product_categ_name = []; + var expire_product_qty = []; + // Send an RPC query to fetch data about products that are about to expire, categorized by their warehouses, from the server. + rpc.query({ + model: 'stock.lot', + method: 'get_today_expire', + }).then(function (result) { + // Extract product warehouse names and their corresponding quantities from the fetched data. + for( var data in result['categ']){ + for (var key in result['categ'][data]) { + if (result['categ'][data].hasOwnProperty(key)) { + var value = result['categ'][data][key]; + } + expire_product_categ_name.push(key) + expire_product_qty.push(parseInt(value)) + } + } + // Render the bar chart using Chart.js. + const ctx = $('#today_expire_products_category'); + new Chart(ctx, { + type: 'bar', + data: { + labels: expire_product_categ_name, + datasets: [{ + label: 'Quantity', + data: expire_product_qty, + backgroundColor: [ + 'rgba(75, 192, 192, 0.2)', + 'rgba(54, 162, 235, 0.2)', + 'rgba(153, 102, 255, 0.2)', + 'rgba(201, 203, 207, 0.2)', + 'rgba(255, 99, 132, 0.2)', + 'rgba(255, 159, 64, 0.2)', + 'rgba(255, 205, 86, 0.2)', + ], + borderColor: [ + 'rgb(75, 192, 192)', + 'rgb(54, 162, 235)', + 'rgb(153, 102, 255)', + 'rgb(201, 203, 207)', + 'rgb(255, 99, 132)', + 'rgb(255, 159, 64)', + 'rgb(255, 205, 86)', + ], + borderWidth: 1 + }] + }, + options: { + plugins: { + legend: { + position: 'bottom', + }, + title: { + display: true, + } + } + } + }); + }); + } +// chart for products expire in 7 days + near_exp_products(start_date, end_date) { + var self = this; + // Initialize arrays to hold product names and their corresponding near expiry quantities. + var product_array = []; + var nearby_expire_qty = []; + // Prepare the date dictionary to pass as an argument in the RPC query. + var date_dict = { 'start_date': start_date, 'end_date': end_date }; + // Send an RPC query to fetch data about products that are near their expiry date from the server. + rpc.query({ + model: 'stock.lot', + method: 'get_near_expiry_product', + args: [date_dict], + }).then(function (result) { + // Extract product names and their corresponding near expiry quantities from the fetched data. + $.each(result, function (index, name) { + product_array.push(index); + nearby_expire_qty.push(name); + }); + // Render the bar chart using Chart.js. + const ctx = $('#nearby_expire_product'); + self.state.charts.push(new Chart(ctx, { + type: 'bar', + data: { + labels: product_array, + datasets: [{ + label: 'Quantity', + data: nearby_expire_qty, + backgroundColor: [ + 'rgba(255, 205, 86, 0.2)', + 'rgba(75, 192, 192, 0.2)', + 'rgba(54, 162, 235, 0.2)', + 'rgba(153, 102, 255, 0.2)', + 'rgba(201, 203, 207, 0.2)', + 'rgba(255, 99, 132, 0.2)', + 'rgba(255, 159, 64, 0.2)', + ], + borderColor: [ + 'rgb(255, 205, 86)', + 'rgb(75, 192, 192)', + 'rgb(54, 162, 235)', + 'rgb(153, 102, 255)', + 'rgb(201, 203, 207)', + 'rgb(255, 99, 132)', + 'rgb(255, 159, 64)', + ], + borderWidth: 1 + }] + }, + options: { + plugins: { + legend: { + position: 'bottom', + }, + title: { + display: true, + } + } + } + })); + }); + } +// Chart for products category expire in 7 days + near_exp_category(start_date, end_date) { + var self = this; + // Initialize arrays to hold product category names and their corresponding near expiry quantities. + var product_category_array = []; + var nearby_expire_qty = []; + // Prepare the date dictionary to pass as an argument in the RPC query. + var date_dict = { 'start_date': start_date, 'end_date': end_date }; + // Send an RPC query to fetch data about products that are near their expiry date, categorized by their product categories. + rpc.query({ + model: 'stock.lot', + method: 'get_near_expiry_category', + args: [date_dict], + }).then(function (result) { + // Extract product category names and their corresponding near expiry quantities from the fetched data. + $.each(result, function (index, name) { + product_category_array.push(index); + nearby_expire_qty.push(name); + }); + // Render the bar chart using Chart.js. + const ctx = $('#nearby_expire_catg'); + self.state.charts.push(new Chart(ctx, { + type: 'bar', + data: { + labels: product_category_array, + datasets: [{ + label: 'Quantity', + data: nearby_expire_qty, + backgroundColor: [ + 'rgba(255, 159, 64, 0.2)', + 'rgba(255, 205, 86, 0.2)', + 'rgba(75, 192, 192, 0.2)', + 'rgba(54, 162, 235, 0.2)', + 'rgba(153, 102, 255, 0.2)', + 'rgba(201, 203, 207, 0.2)', + 'rgba(255, 99, 132, 0.2)', + ], + borderWidth: 1 + }] + }, + options: { + plugins: { + legend: { + position: 'bottom', + }, + title: { + display: true, + } + } + } + })); + }); + } +// Expiry in Seven Days + get_expire_product_location(start_date, end_date) { + var self = this; + // Initialize arrays to hold product location names and their corresponding quantities. + var product_location_array = []; + var nearby_expire_qty = []; + // Prepare the date dictionary to pass as an argument in the RPC query. + var date_dict = { 'start_date': start_date, 'end_date': end_date }; + // Send an RPC query to fetch data about products that are about to expire, categorized by their locations, from the server. + rpc.query({ + model: 'stock.lot', + method: 'get_expire_product_location', + args: [date_dict], + }).then(function (result) { + // Extract product location names and their corresponding quantities from the fetched data. + $.each(result, function (index, name) { + product_location_array.push(index); + nearby_expire_qty.push(name); + }); + // Render the pie chart using Chart.js. + const ctx = $('#nearby_expire_location'); + self.state.charts.push(new Chart(ctx, { + type: 'pie', + data: { + labels: product_location_array, + datasets: [{ + label: 'Quantity', + data: nearby_expire_qty, + borderWidth: 1 + }] + }, + options: { + plugins: { + legend: { + position: 'bottom', + }, + title: { + display: true, + } + } + } + })); + }); + } +// Products by Warehouse Expire in 7 Days + get_expire_product_warehouse(start_date, end_date) { + var self = this; + // Initialize arrays to hold product warehouse names and their corresponding quantities. + var product_warehouse_array = []; + var nearby_expire_qty = []; + // Prepare the date dictionary to pass as an argument in the RPC query. + var date_dict = { 'start_date': start_date, 'end_date': end_date }; + // Send an RPC query to fetch data about products that are about to expire, categorized by their warehouses, from the server. + rpc.query({ + model: 'stock.lot', + method: 'get_expire_product_warehouse', + args: [date_dict], + }).then(function (result) { + // Extract product warehouse names and their corresponding quantities from the fetched data. + $.each(result, function (index, name) { + product_warehouse_array.push(index); + nearby_expire_qty.push(name); + }); + // Render the bar chart using Chart.js. + const ctx = $('#nearby_expire_warehouse'); + self.state.charts.push(new Chart(ctx, { + type: 'doughnut', + data: { + labels: product_warehouse_array, + datasets: [{ + label: 'Quantity', + data: nearby_expire_qty, + backgroundColor: [ + 'rgba(75, 192, 192, 0.2)', + 'rgba(54, 162, 235, 0.2)', + 'rgba(153, 102, 255, 0.2)', + 'rgba(201, 203, 207, 0.2)', + 'rgba(255, 99, 132, 0.2)', + 'rgba(255, 159, 64, 0.2)', + 'rgba(255, 205, 86, 0.2)', + ], + borderColor: [ + 'rgb(75, 192, 192)', + 'rgb(54, 162, 235)', + 'rgb(153, 102, 255)', + 'rgb(201, 203, 207)', + 'rgb(255, 99, 132)', + 'rgb(255, 159, 64)', + 'rgb(255, 205, 86)', + ], + borderWidth: 1 + }] + }, + options: { + plugins: { + legend: { + position: 'bottom', + }, + title: { + display: true, + } + } + } + })); + }); + } +// Expired Products + render_expired_products_graph(start_date, end_date) { + // Check if a chart with the ID 'expired_product_count' already exists and destroy it if it does. + let chartStatus = Chart.getChart('expired_product_count'); + if (chartStatus !== undefined) { + chartStatus.destroy(); + } + // Initialize arrays to hold product names and their corresponding expired quantities. + var product_array = []; + var expired_qty_array = []; + // Prepare the date dictionary to pass as an argument in the RPC query. + var date_dict = { 'start_date': start_date, 'end_date': end_date }; + // Send an RPC query to fetch data about expired products from the server. + let data = rpc.query({ + model: 'stock.lot', + method: 'get_expired_product', + args: [date_dict,] + }).then(function (result) { + // Extract product names and their corresponding expired quantities from the fetched data. + $.each(result, function (index, name) { + product_array.push(index); + expired_qty_array.push(name); + }); + // Render the pie chart using Chart.js. + const ctx = $('#expired_product_count'); + new Chart(ctx, { + type: 'pie', + data: { + labels: product_array, + datasets: [{ + label: 'Quantity', + data: expired_qty_array, + borderWidth: 1 + }] + }, + options: { + plugins: { + legend: { + position: 'bottom', + }, + title: { + display: true, + } + } + } + }); + }); + } +// Expired Products by Category + expiry_by_category(start_date, end_date) { + // Check if a chart with the ID 'expired_product_category_count' already exists and destroy it if it does. + let chartStatus = Chart.getChart('expired_product_category_count'); + if (chartStatus !== undefined) { + chartStatus.destroy(); + } + // Initialize arrays to hold product category names and their corresponding expired quantities. + var product_category_array = []; + var expired_qty_array = []; + // Prepare the date dictionary to pass as an argument in the RPC query. + var date_dict = { 'start_date': start_date, 'end_date': end_date }; + // Send an RPC query to fetch data about expired products categorized by their product categories from the server. + rpc.query({ + model: 'stock.lot', + method: 'get_product_expiry_by_category', + args: [date_dict,session.user_context.allowed_company_ids] + }).then(function (result) { + // Extract product category names and their corresponding expired quantities from the fetched data. + $.each(result, function (index, name) { + product_category_array.push(index); + expired_qty_array.push(name); + }); + // Render the bar chart using Chart.js. + const ctx = $('#expired_product_category_count'); + new Chart(ctx, { + type: 'polarArea', + data: { + labels: product_category_array, + datasets: [{ + label: 'Quantity', + data: expired_qty_array, + borderWidth: 1 + }] + }, + options: { + plugins: { + legend: { + position: 'bottom', + }, + title: { + display: true, + } + } + } + }); + }); + } +} +ProductExpiryDashboard.template = "ProductExpiryDashboard" +actionRegistry.add('product_expiry', ProductExpiryDashboard); diff --git a/odoo_product_expiry_dashboard/static/src/xml/product_expiry_dashboard.xml b/odoo_product_expiry_dashboard/static/src/xml/product_expiry_dashboard.xml new file mode 100644 index 000000000..a6d34a381 --- /dev/null +++ b/odoo_product_expiry_dashboard/static/src/xml/product_expiry_dashboard.xml @@ -0,0 +1,178 @@ + + diff --git a/odoo_product_expiry_dashboard/views/product_expiry_views.xml b/odoo_product_expiry_dashboard/views/product_expiry_views.xml new file mode 100644 index 000000000..9431dba7b --- /dev/null +++ b/odoo_product_expiry_dashboard/views/product_expiry_views.xml @@ -0,0 +1,21 @@ + + + + + + + Expiry Dashboard + + product_expiry + + current + + + + +