diff --git a/odoo_product_expiry_dashboard/README.rst b/odoo_product_expiry_dashboard/README.rst new file mode 100755 index 000000000..642badd68 --- /dev/null +++ b/odoo_product_expiry_dashboard/README.rst @@ -0,0 +1,46 @@ +.. 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 +======================== +Product Expiry Dashboard allow users to view all the product details those are about to expire. + +Configuration +============= +* No additional configurations needed + +License +------- +General Public License, Version 3 (AGPL v3). +(https://www.gnu.org/licenses/agpl-3.0-standalone.html) + +Company +------- +* `Cybrosys Techno Solutions `__ + +Credits +------- +* Developer:(V15) Unnimaya C O, Contact: odoo@cybrosys.com + +Contacts +-------- +* Mail Contact : odoo@cybrosys.com +* Website : https://cybrosys.com + +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..b2744bb0c --- /dev/null +++ b/odoo_product_expiry_dashboard/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# 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..de16fa19d --- /dev/null +++ b/odoo_product_expiry_dashboard/__manifest__.py @@ -0,0 +1,53 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# 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': '15.0.1.0.0', + 'category': 'Warehouse', + 'summary': """Allow users to view all the product details those are going to + expire.""", + 'description': """Product Expiry Dashboard display graphical view of + expiredproducts, nearly expiring products, their locations and + warehouses. This app allows take significant decisions quickly by + overseeing the products that will expire soon""", + 'author': 'Cybrosys Techno Solutions', + 'company': 'Cybrosys Techno Solutions', + 'maintainer': 'Cybrosys Techno Solutions', + 'website': 'https://www.cybrosys.com', + 'depends': ['stock', 'product_expiry'], + 'data': ['views/product_expiry_view.xml'], + 'assets': { + 'web.assets_backend': [ + '/odoo_product_expiry_dashboard/static/src/js/product_expiry_action.js', + '/odoo_product_expiry_dashboard/static/src/css/style.css', + 'https://cdn.jsdelivr.net/npm/chart.js' + ], + 'web.assets_qweb': [ + '/odoo_product_expiry_dashboard/static/src/xml/odoo_product_expiry_dashboard.xml', + ], + }, + '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..7913e61f0 --- /dev/null +++ b/odoo_product_expiry_dashboard/doc/RELEASE_NOTES.md @@ -0,0 +1,7 @@ +## Module + +#### 13.10.2023 +#### Version 15.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..30188ad60 --- /dev/null +++ b/odoo_product_expiry_dashboard/models/__init__.py @@ -0,0 +1,22 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# 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_production_lot diff --git a/odoo_product_expiry_dashboard/models/stock_production_lot.py b/odoo_product_expiry_dashboard/models/stock_production_lot.py new file mode 100644 index 000000000..8c99d966c --- /dev/null +++ b/odoo_product_expiry_dashboard/models/stock_production_lot.py @@ -0,0 +1,195 @@ +# -*- coding: utf-8 -*- +################################################################################ +# +# Cybrosys Technologies Pvt. Ltd. +# +# Copyright (C) 2023-TODAY Cybrosys Technologies(). +# Author: Unnimaya C O (odoo@cybrosys.com) +# +# 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 StockProductionLot(models.Model): + """Inherited to include the functions for fetching the data which is to be + displayed on the dashboard""" + _inherit = "stock.production.lot" + + @api.model + def get_product_expiry(self, *args): + """Returns the data to be displayed on the dashboard tiles""" + expiry_dict = {"expired": 0, "today": 0, "one_day": 0, "seven_day": 0, + "thirty_day": 0, + "one_twenty_day": 0} + search_params = [] + if args[0].get('start_date') and args[0].get('end_date'): + search_params = [ + ('expiration_date', '>=', args[0].get('start_date')), + ('expiration_date', '<=', args[0].get('end_date'))] + elif args[0].get('start_date'): + search_params = [ + ('expiration_date', '>=', args[0].get('start_date'))] + elif args[0].get('end_date'): + search_params = [('expiration_date', '<=', args[0].get('end_date'))] + 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 == 0: + expiry_dict["today"] += record.product_qty + elif date_difference == 1: + expiry_dict["one_day"] += record.product_qty + elif 7 >= date_difference > 1: + expiry_dict["seven_day"] += record.product_qty + elif 30 >= date_difference > 7: + expiry_dict["thirty_day"] += record.product_qty + elif 120 >= date_difference > 30: + expiry_dict["one_twenty_day"] += record.product_qty + search_params.append(('expiration_date', '<', fields.date.today())) + expiry_dict["expired"] = \ + sum(self.search(search_params).mapped('product_qty')) + return expiry_dict + + @api.model + def get_expired_product(self, *args): + """Function for fetching the expired products""" + search_params = [('expiration_date', '<', fields.date.today())] + if args[0].get('start_date'): + search_params.append( + ('expiration_date', '>=', args[0].get('start_date'))) + if args[0].get('end_date'): + search_params.append(('expiration_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)} + 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): + """Functions for fetching the category of expired products""" + search_params = [('expiration_date', '<', fields.date.today())] + if args[0].get('start_date'): + search_params.append( + ('expiration_date', '>=', args[0].get('start_date'))) + if args[0].get('end_date'): + search_params.append(('expiration_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)} + 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_category(self): + """Function for fetching the category of products expiring in 7 days""" + 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_near_expiry_product(self): + """Function for fetching the products expiring in 7 days""" + 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_product_expired_today(self): + """Function for fetching the products expiring today""" + return len([record for record in self.search([]) if + record.expiration_date and + fields.Date.to_date(record.expiration_date) == + fields.date.today()]) + + @api.model + def get_expire_product_location(self): + """Function for fetching the location of products expiring in 7 days""" + 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): + """Function for fetching the warehouse of products expiring in 7 days""" + 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 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/modules/avg_lc.png b/odoo_product_expiry_dashboard/static/description/assets/modules/avg_lc.png new file mode 100644 index 000000000..f091600e7 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/avg_lc.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/brand_inventory.png b/odoo_product_expiry_dashboard/static/description/assets/modules/brand_inventory.png new file mode 100644 index 000000000..dd149ac30 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/brand_inventory.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/export_stock.png b/odoo_product_expiry_dashboard/static/description/assets/modules/export_stock.png new file mode 100644 index 000000000..46a13fb8f Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/export_stock.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/inter_company.png b/odoo_product_expiry_dashboard/static/description/assets/modules/inter_company.png new file mode 100644 index 000000000..86f799dd0 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/inter_company.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/scrap.png b/odoo_product_expiry_dashboard/static/description/assets/modules/scrap.png new file mode 100644 index 000000000..68dc568ff Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/scrap.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/modules/serial_number.png b/odoo_product_expiry_dashboard/static/description/assets/modules/serial_number.png new file mode 100644 index 000000000..a4aa0997f Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/modules/serial_number.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot1.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot1.png new file mode 100644 index 000000000..e6b7fecd4 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot1.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot2.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot2.png new file mode 100644 index 000000000..7d86012a2 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot2.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot3.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot3.png new file mode 100644 index 000000000..777c8c517 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot3.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot5.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot5.png new file mode 100644 index 000000000..7a85c7d7e Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot5.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot6.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot6.png new file mode 100644 index 000000000..82b051542 Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot6.png differ diff --git a/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot7.png b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot7.png new file mode 100644 index 000000000..ffab4528c Binary files /dev/null and b/odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot7.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..e50024b7b 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..82d6ab955 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..fed610376 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..a1da618ba --- /dev/null +++ b/odoo_product_expiry_dashboard/static/description/index.html @@ -0,0 +1,626 @@ +
+
+
+
+ +
+
+
+ Community +
+
+ Enterprise +
+
+
+
+
+
+
+
+

+ Product Expiry Dashboard

+

+ Product Expiry Dashboard Allow Users to View All the Product + Details those are About to Expire. +

+ +
+
+ +
+
+

+ Overview +

+
+
+

+ Product Expiry Dashboard display counts of expired products, + nearly expiring products, graphical view of expired + products, nearly expiring products, their locations and + warehouses. This app allows take significant decisions quickly + by overseeing the products which will expire soon. +

+
+
+
+
+

+ Features +

+
+
+
+ +
+
+

+ Shows all Products which are already Expired.

+
+
+
+
+ +
+
+

+ Shows all Products which will Expire Today.

+
+
+
+
+ +
+
+

+ Contains Tiles for displaying Count of Products which will + Expire soon based on their Expiry Date.

+
+
+
+
+ +
+
+

+ Graphical view of Expired Products

+
+
+
+
+ +
+
+

+ Graphical view of Nearly Expiring Products based on their + Location and Warehouse

+
+
+
+
+
+
+

+ Screenshots +

+
+
+

+ Product Expiry Dashboard view

+ +
+
+

+ Bottom part of Product Expiry Dashboard

+ +
+
+

+ Count of Expiring Products if no Start or End Date selected

+ +
+
+

+ Count of Products whose Expiry Date is between Start or End Date + selected

+ +
+
+

+ Click on any Tile to view corresponding Products

+ +
+
+

+ List of Products corresponding to the Tile clicked

+ +
+ +
+ +
+
+

Suggested 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

+
+
+
+
+ + + +
+
+
+

Need Help?

+
+
+
+ +
+ + +
+ +
+ +
+
+ +
+ +
+ +
+
+ +
+
+
+ + + \ No newline at end of file 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..f3765707e --- /dev/null +++ b/odoo_product_expiry_dashboard/static/src/css/style.css @@ -0,0 +1,86 @@ +.order-card { + color: #fff; +} + +.bg-c-red { + background: linear-gradient(45deg, #e60000, #ff8080); +} + +.bg-c-lavender { + background: linear-gradient(45deg, #d279d2, #df9fdf); +} + +.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{ + width:110% +} + +.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: 250px; +} + +.dashboard-heading{ + min-height: 140px; + padding: 20px; + text-align: center; + background: #376270; +} + +.banner-heading { + color: #ffffff; + font-size: 45px; + margin: 0; + } + +.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..b9bb4d3f4 --- /dev/null +++ b/odoo_product_expiry_dashboard/static/src/js/product_expiry_action.js @@ -0,0 +1,396 @@ +odoo.define('odoo_product_expiry_dashboard.product_expiry', function (require) { + 'use strict'; + var AbstractAction = require('web.AbstractAction'); + var core = require('web.core'); + var rpc = require('web.rpc'); + var ProductExpiryDashboard = AbstractAction.extend({ + template: 'ProductExpiryDashboard', + events: { + //Events + 'change #start_date': 'filter_date', + 'change #end_date': 'filter_date', + 'click .expired': 'expired_click', + 'click .today': 'today_click', + 'click .one-day': 'one_day_click', + 'click .seven-day': 'seven_day_click', + 'click .thirty-day': 'thirty_day_click', + 'click .one-twenty-day': 'one_twenty_day_click' + }, + start: function () { + //Call functions to fetch the data to display on the dashboard + this.fetch_products_expiry() + this.render_expired_products_graph() + this.expiry_by_category() + this.near_exp_category() + this.near_exp_products() + this.product_expired_today() + this.get_expire_product_location() + this.get_expire_product_warehouse() + }, + filter_date(ev) { + //Works if start date or end date is changed. Fetch the data according to + //the date chosen + var start_date = this.$("#start_date").val() + var end_date = this.$("#end_date").val() + this.fetch_products_expiry(start_date, end_date) + this.render_expired_products_graph(start_date, end_date) + this.expiry_by_category(start_date, end_date) + }, + fetch_products_expiry(start_date, end_date) { + //Fetch the data to be displayed on the tiles of the dashboard. + this.$('#expired').remove() + this.$("#today").remove() + this.$("#one_day").remove() + this.$("#seven_day").remove() + this.$("#thirty_day").remove() + this.$("#one_twenty_day").remove() + var date_dict = { 'start_date': start_date, 'end_date': end_date } + rpc.query({ + model: 'stock.production.lot', + method: 'get_product_expiry', + args: [date_dict] + }).then(function (result) { + $(".expired").append('
' + + '' + result['expired'] + '' + + '
') + $(".today").append('
' + + '' + result['today'] + '' + + '
') + $(".one-day").append('
' + + '' + result['one_day'] + '' + + '
') + $(".seven-day").append('
' + + '' + result['seven_day'] + '' + + '
') + $(".thirty-day").append('
' + + '' + result['thirty_day'] + '' + + '
') + $(".one-twenty-day").append('
' + + '' + result['one_twenty_day'] + '' + + '
') + }) + }, + product_expired_today() { + //Function for fetching all products expiring today + rpc.query({ + model: 'stock.production.lot', + method: 'get_product_expired_today' + }).then(function (result) { + $('.product_expired_heading').append('

' + result + '

') + }) + }, + render_expired_products_graph(start_date, end_date) { + //Function for rendering the graph of expired products + let chartStatus = Chart.getChart('expired_product_count'); + if (chartStatus != undefined) { + chartStatus.destroy(); + } + var product_array = [] + var expired_qty_array = [] + var date_dict = { 'start_date': start_date, 'end_date': end_date } + let data = rpc.query({ + model: 'stock.production.lot', + method: 'get_expired_product', + args: [date_dict] + }).then(function (result) { + $.each(result, function (index, name) { + product_array.push(index) + expired_qty_array.push(name) + }) + if (product_array.length != 0) { + const ctx = $('#expired_product_count') + new Chart(ctx, { + type: 'pie', + data: { + labels: product_array, + datasets: [{ + label: 'Quantity', + data: expired_qty_array, + borderWidth: 1, + backgroundColor: ["#e60000", "#d279d2", "#4099ff","#2ed8b6", + "#FFB64D, #ffcb80"], + }] + }, + }); + $(".chart_heading").show() + } + else { + $(".chart_heading").hide() + } + }) + }, + expiry_by_category(start_date, end_date) { + //Function for rendering the graph of product's expiry based on their + //category + let chartStatus = Chart.getChart('expired_product_category_count'); + if (chartStatus != undefined) { + chartStatus.destroy(); + } + var product_category_array = [] + var expired_qty_array = [] + var date_dict = { 'start_date': start_date, 'end_date': end_date } + rpc.query({ + model: 'stock.production.lot', + method: 'get_product_expiry_by_category', + args: [date_dict] + }).then(function (result) { + $.each(result, function (index, name) { + product_category_array.push(index) + expired_qty_array.push(name) + }) + if (product_category_array.length != 0) { + const ctx = $('#expired_product_category_count') + new Chart(ctx, { + type: 'bar', + data: { + labels: product_category_array, + datasets: [{ + label: 'Quantity', + data: expired_qty_array, + borderWidth: 1, + backgroundColor: ["#4099ff", "#e60000", "#d279d2", "#2ed8b6", + "#FFB64D, #ffcb80"], + }] + }, + }); + } + else { + $(".chart_heading").hide() + } + }) + }, + near_exp_products() { + //Function for rendering graph of products expiring in 7 days + var product_array = [] + var nearby_expire_qty = [] + rpc.query({ + model: 'stock.production.lot', + method: 'get_near_expiry_product', + }).then(function (result) { + $.each(result, function (index, name) { + product_array.push(index) + nearby_expire_qty.push(name) + }) + if (product_array.length != 0) { + const ctx = $('#nearby_expire_product') + new Chart(ctx, { + type: 'doughnut', + data: { + labels: product_array, + datasets: [{ + label: 'Quantity', + data: nearby_expire_qty, + borderWidth: 1, + backgroundColor: ["#ffcb80", "#4099ff", "#e60000", "#d279d2", + "#2ed8b6", "#FFB64D"], + }] + }, + }); + } + }) + }, + near_exp_category() { + //Function for rendering graph of products expiring in 7 days based on + //their category + var product_category_array = [] + var nearby_expire_qty = [] + rpc.query({ + model: 'stock.production.lot', + method: 'get_near_expiry_category', + }).then(function (result) { + $.each(result, function (index, name) { + product_category_array.push(index) + nearby_expire_qty.push(name) + }) + const ctx = $('#nearby_expire_catg') + new Chart(ctx, { + type: 'line', + data: { + labels: product_category_array, + datasets: [{ + label: 'Quantity', + data: nearby_expire_qty, + backgroundColor: ["#FFB64D", "#4099ff", "#e60000", "#d279d2", + "#2ed8b6", "#ffcb80"], + borderWidth: 1 + }] + }, + }) + }) + }, + get_expire_product_location() { + //Function for rendering graph of expiring products based on + //their location + var product_location_array = [] + var nearby_expire_qty = [] + rpc.query({ + model: 'stock.production.lot', + method: 'get_expire_product_location', + }).then(function (result) { + $.each(result, function (index, name) { + product_location_array.push(index) + nearby_expire_qty.push(name) + }) + const ctx = $('#nearby_expire_location') + new Chart(ctx, { + type: 'pie', + data: { + labels: product_location_array, + datasets: [{ + label: 'Quantity', + data: nearby_expire_qty, + backgroundColor: ["#ffcb80", "#FFB64D", "#4099ff", "#e60000", + "#d279d2", "#2ed8b6"], + borderWidth: 1 + }] + }, + }) + }) + }, + get_expire_product_warehouse() { + //Function for rendering graph of expiring products based on + //their warehouse + var product_warehouse_array = [] + var nearby_expire_qty = [] + rpc.query({ + model: 'stock.production.lot', + method: 'get_expire_product_warehouse', + }).then(function (result) { + $.each(result, function (index, name) { + product_warehouse_array.push(index) + nearby_expire_qty.push(name) + }) + const ctx = $('#nearby_expire_warehouse') + new Chart(ctx, { + type: 'doughnut', + data: { + labels: product_warehouse_array, + datasets: [{ + label: 'Quantity', + data: nearby_expire_qty, + borderWidth: 1, + backgroundColor: ["#4099ff", "#e60000", "#ffcb80", "#FFB64D", + "#d279d2", "#2ed8b6"], + }] + }, + }) + }) + }, + expired_click(){ + //Click event of expired products tile + this.click_event(-1,"Expired") + }, + today_click() { + //Click event of expire today tile + this.click_event(0,"Expire Today"); + }, + one_day_click() { + //Click event of expire in one day tile + this.click_event(1,"Expiry in One Day"); + }, + seven_day_click() { + //Click event of expire in one 7 days tile + this.click_event(7, "Expiry in Seven Days"); + }, + thirty_day_click() { + //Click event of expire in 30 days tile + this.click_event(30, "Expiry in Thirty Days"); + }, + one_twenty_day_click() { + //Click event of expire in 120 day tile + this.click_event(120, "Expiry in One Twenty Days"); + }, + click_event(days,name){ + //Function for displaying corresponding products while clicking on a tile + var today = new Date(); + var start_date = this.$("#start_date").val() + var end_date = this.$("#end_date").val() + var Domain = [] + if(start_date != ""){ + Domain.push(['expiration_date', '>=', start_date]) + } + if(end_date != ""){ + Domain.push(['expiration_date', '<=', end_date]) + } + today.setDate(today.getDate()) + today.setHours(0, 0, 0, 0); + var dateString = today.toLocaleDateString(); + var timeString = today.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' }); + var formattedDateTime = dateString + ' ' + timeString; + if(days==-1){ + Domain.push(['expiration_date', '<', formattedDateTime]) + } + else if(days==0){ + Domain.push(['expiration_date', '=', formattedDateTime]) + } + else if(days==1){ + // Calculate the end date for the next-day range (one days from + // the today). + today.setDate(today.getDate() + 1); + today.setHours(0, 0, 0, 0); + // Format the date and time as a formatted date-time string. + var dateString = today.toLocaleDateString(); + var timeString = today.toLocaleTimeString([], { hour: '2-digit', + minute: '2-digit', second: '2-digit' }); + var formattedDateTime = dateString + ' ' + timeString; + Domain.push(['expiration_date', '=', formattedDateTime]) + } + else if(days==7){ + // Calculate the end date for the seven-day range (6th days from + // today). + today.setDate(today.getDate() + 1); + today.setHours(0, 0, 0, 0); + var dateString = today.toLocaleDateString(); + var timeString = today.toLocaleTimeString([], { hour: '2-digit', minute: + '2-digit', second: '2-digit' }); + var tomorrow_date = dateString + ' ' + timeString; + today.setDate(today.getDate() + 6); + var dateString = today.toLocaleDateString(); + var seven_day_date = dateString + ' ' + timeString; + Domain.push(['expiration_date', '<=', seven_day_date], + ['expiration_date', '>', tomorrow_date]) + } + else if(days==30){ + today.setDate(today.getDate() + 8); + today.setHours(0, 0, 0, 0); + var dateString = today.toLocaleDateString(); + var timeString = today.toLocaleTimeString([], { hour: '2-digit', minute: + '2-digit', second: '2-digit' }); + var seventh_day = dateString + ' ' + timeString; + // Calculate the end date for the thirty-day range (thirty days from + // the eighth day). + today.setDate(today.getDate() + 22); + dateString = today.toLocaleDateString(); + var thirty_day_date = dateString + ' ' + timeString; + Domain.push(['expiration_date', '<=', thirty_day_date], + ['expiration_date', '>', seventh_day]) + } + else if(days==120){ + today.setDate(today.getDate() + 31); + today.setHours(0, 0, 0, 0); + var dateString = today.toLocaleDateString(); + var timeString = today.toLocaleTimeString([], { hour: '2-digit', minute: + '2-digit', second: '2-digit' }); + var thirtieth_day = dateString + ' ' + timeString; + // Calculate the end date for the one hundred twenty-day range +// (eighty-nine days from the thirty-first day). + today.setDate(today.getDate() + 89); + dateString = today.toLocaleDateString(); + var day_one_twenty = dateString + ' ' + timeString; + Domain.push(['expiration_date', '<=', day_one_twenty], + ['expiration_date', '>', thirtieth_day]) + } + this.do_action({ + name: name, + type: 'ir.actions.act_window', + view_mode: 'list', + res_model: 'stock.production.lot', + views: [[false, 'list'], [false, 'form']], + domain: Domain, + target: 'current', + }) + }, + }); + core.action_registry.add("product_expiry", ProductExpiryDashboard); + return ProductExpiryDashboard; +}); diff --git a/odoo_product_expiry_dashboard/static/src/xml/odoo_product_expiry_dashboard.xml b/odoo_product_expiry_dashboard/static/src/xml/odoo_product_expiry_dashboard.xml new file mode 100644 index 000000000..40a843c56 --- /dev/null +++ b/odoo_product_expiry_dashboard/static/src/xml/odoo_product_expiry_dashboard.xml @@ -0,0 +1,216 @@ + + diff --git a/odoo_product_expiry_dashboard/views/product_expiry_view.xml b/odoo_product_expiry_dashboard/views/product_expiry_view.xml new file mode 100644 index 000000000..777eef0d6 --- /dev/null +++ b/odoo_product_expiry_dashboard/views/product_expiry_view.xml @@ -0,0 +1,16 @@ + + + + + Expiry Dashboard + product_expiry + current + + + +