Browse Source

Aug 17: [ADD] Initital Commits 'odoo_product_expiry_dashboard'

pull/332/merge
Cybrosys Technologies 8 months ago
parent
commit
2fe6c09ec3
  1. 45
      odoo_product_expiry_dashboard/README.rst
  2. 22
      odoo_product_expiry_dashboard/__init__.py
  3. 48
      odoo_product_expiry_dashboard/__manifest__.py
  4. 6
      odoo_product_expiry_dashboard/doc/RELEASE_NOTES.md
  5. 22
      odoo_product_expiry_dashboard/models/__init__.py
  6. 304
      odoo_product_expiry_dashboard/models/stock_lot.py
  7. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/check.png
  8. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/chevron.png
  9. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/cogs.png
  10. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/consultation.png
  11. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/ecom-black.png
  12. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/education-black.png
  13. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/hotel-black.png
  14. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/license.png
  15. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/lifebuoy.png
  16. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/logo.png
  17. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/manufacturing-black.png
  18. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/pos-black.png
  19. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/puzzle.png
  20. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/restaurant-black.png
  21. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/service-black.png
  22. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/trading-black.png
  23. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/training.png
  24. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/update.png
  25. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/user.png
  26. BIN
      odoo_product_expiry_dashboard/static/description/assets/icons/wrench.png
  27. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/categories.png
  28. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/check-box.png
  29. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/compass.png
  30. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/corporate.png
  31. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/customer-support.png
  32. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/cybrosys-logo.png
  33. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/features.png
  34. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/logo.png
  35. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/pictures.png
  36. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/pie-chart.png
  37. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/right-arrow.png
  38. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/star.png
  39. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/support.png
  40. BIN
      odoo_product_expiry_dashboard/static/description/assets/misc/whatsapp.png
  41. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/module01.png
  42. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/module02.png
  43. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/module03.png
  44. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/module04.png
  45. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/module05.png
  46. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/module06.png
  47. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/01.png
  48. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/1.png
  49. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/2.png
  50. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/3.png
  51. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/4.png
  52. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/5.png
  53. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/6.png
  54. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/7.png
  55. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/8.png
  56. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/9.png
  57. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/hero.gif
  58. BIN
      odoo_product_expiry_dashboard/static/description/banner.jpg
  59. BIN
      odoo_product_expiry_dashboard/static/description/icon.png
  60. 631
      odoo_product_expiry_dashboard/static/description/index.html
  61. 76
      odoo_product_expiry_dashboard/static/src/css/style.css
  62. 602
      odoo_product_expiry_dashboard/static/src/js/product_expiry_action.js
  63. 178
      odoo_product_expiry_dashboard/static/src/xml/product_expiry_dashboard.xml
  64. 21
      odoo_product_expiry_dashboard/views/product_expiry_views.xml

45
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 <https://cybrosys.com/>`__
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 <https://cybrosys.com/>`__
Further information
===================
HTML Description: `<static/description/index.html>`__

22
odoo_product_expiry_dashboard/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import models

48
odoo_product_expiry_dashboard/__manifest__.py

@ -0,0 +1,48 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
#
#############################################################################
{
'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
}

6
odoo_product_expiry_dashboard/doc/RELEASE_NOTES.md

@ -0,0 +1,6 @@
## Module <odoo_product_expiry_dashboard>
#### 17.08.2024
#### Version 16.0.1.0.0
#### ADD
- Initial commit for Product Expiry Dashboard

22
odoo_product_expiry_dashboard/models/__init__.py

@ -0,0 +1,22 @@
# -*- coding: utf-8 -*-
#############################################################################
#
# Cybrosys Technologies Pvt. Ltd.
#
# Copyright (C) 2024-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
#
#############################################################################
from . import stock_lot

304
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(<https://www.cybrosys.com>).
# Author: Cybrosys Techno Solutions(<https://www.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 <http://www.gnu.org/licenses/>.
#
#############################################################################
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

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/check.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.6 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/chevron.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 310 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/cogs.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.3 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/consultation.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.4 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/ecom-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 576 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/education-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 733 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/hotel-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 911 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/license.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/lifebuoy.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/manufacturing-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 673 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/pos-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 878 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/puzzle.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 653 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/restaurant-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 905 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/service-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 839 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/trading-black.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 427 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/training.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 627 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/update.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/user.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 988 B

BIN
odoo_product_expiry_dashboard/static/description/assets/icons/wrench.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.2 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/categories.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.5 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/check-box.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/compass.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.9 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/corporate.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.1 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/customer-support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.1 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/cybrosys-logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.4 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/features.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 589 B

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/logo.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.4 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/pictures.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/pie-chart.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.3 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/right-arrow.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 967 B

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/star.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/support.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.8 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/misc/whatsapp.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/modules/module01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/modules/module02.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/modules/module03.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/modules/module04.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 84 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/modules/module05.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/modules/module06.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/01.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 63 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/1.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/2.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 122 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/3.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 185 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/4.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 77 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/5.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 182 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/6.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 71 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/7.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 187 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/8.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 114 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/9.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 116 KiB

BIN
odoo_product_expiry_dashboard/static/description/assets/screenshots/hero.gif

Binary file not shown.

After

Width:  |  Height:  |  Size: 301 KiB

BIN
odoo_product_expiry_dashboard/static/description/banner.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 97 KiB

BIN
odoo_product_expiry_dashboard/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 11 KiB

631
odoo_product_expiry_dashboard/static/description/index.html

@ -0,0 +1,631 @@
<div style="background-color: #714B67; min-height: 600px; width: 100%; padding: 15px; position: relative;">
<!-- TITLE BAR -->
<div
style="border-bottom: 1px solid #875A7B; padding: 15px; display: flex; justify-content: space-between; align-items: center;">
<img src="assets/misc/cybrosys-logo.png" width="42" height="42" style="width: 42px; height: 42px;"/>
<div>
<div style="color: #7C7BAD; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Community
</div>
<div style="color: #875A7B; font-size: 14px; font-family: 'Montserrat', sans-serif; font-weight: bold; background-color: white; display: inline-block; padding: 3px 10px; border-radius: 50px;"
class="mr-2">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
</div>
</div>
<!-- END OF TITLE BAR -->
<!-- APP HERO -->
<h1 style="color: #FFFFFF; font-weight: bolder; font-size: 50px; text-align: center; margin-top: 50px;">Product Expiry Dashboard</h1>
<p style="color:#FFFFFF; padding: 8px 15px; text-align: center; font-size: 24px;">Allows To View All Product Details Those Are About To Expire.</p>
<!-- END OF APP HERO -->
<img src="./assets/screenshots/hero.gif"
style="width: 75%; height: auto; position: absolute; margin-left: auto; margin-right: auto; top: 45%; left: 12%; right: auto;"/>
</div>
<!-- NAVIGATION SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px; margin-top: 300px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/compass.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Explore This
Module</h2>
</div>
<div class="row my-4" style="font-family: 'Montserrat', sans-serif;">
<div class="col-sm-12 col-md-6 my-3">
<a href="#overview">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Overview</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">Learn
more about this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#features">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Features</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
features of this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
<div class="col-sm-12 col-md-6 my-3">
<a href="#screenshots">
<div class="d-flex justify-content-between align-items-center"
style="background-color: #f5f5f5; padding: 30px; width: 100%;">
<div>
<span style="color: #714B67; font-size: 24px; font-weight: 500; display: block;">Screenshots</span>
<span
style="color: #714B67; font-size: 16px; font-weight: 400; color:#282F33; display: block;">View
screenshots for this
module</span>
</div>
<img src="assets/misc/right-arrow.png" width="36" height="36"/>
</div>
</a>
</div>
</div>
<!-- END OF NAVIGATION SECTION -->
<!-- OVERVIEW SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="overview">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pie-chart.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Overview
</h2>
</div>
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 py-4">
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.
</div>
</div>
<!-- END OF OVERVIEW SECTION -->
<!-- FEATURES SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="features">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/features.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Features
</h2>
</div>
<div class="row" style="font-family: 'Montserrat', sans-serif; font-weight: 400; font-size: 14px; line-height: 200%;">
<div class="col-sm-12 col-md-6">
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Contains Tiles for displaying Count of Products which will Expire soon based on their Expiry Date..</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Analyse your products expiry on which location and date.</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Shows all Products which are already Expired.</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Graphical view of Expired Products.</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 30px; margin-bottom: 30px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Graphical view of Nearly Expiring Products based on their Location and Warehouse.</span>
</div>
<div class="d-flex align-items-center" style="margin-top: 40px; margin-bottom: 40px">
<img src="assets/misc/check-box.png" class="mr-2"/>
<span style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Community & Enterprise Support.</span>
</div>
</div>
</div>
<!-- END OF FEATURES SECTION -->
<!-- SCREENSHOTS SECTION -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;" id="screenshots">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/pictures.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Screenshots
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Product Expiry Dashboard.</h3>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Navigate to Inventory --> Product Expiry Dashboard menu.
</p>
<img src="assets/screenshots/01.png" class="img-thumbnail">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Product Expiry Dashboard.</h3>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
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 </br>
2.Additionally, we can also observe items that have already
expired, as well as expired items categorized by their
respective product categories
</p>
<img src="assets/screenshots/1.png" class="img-thumbnail">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Different Charts.</h3>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
We can view products expiring within 7 days by categorized by category, location and warehouse.
</p>
<img src="assets/screenshots/2.png" class="img-thumbnail">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Product Expired Today</h3>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
We can see count of products expired today, with a clickable button
that redirects to the product list view.
</p>
<img src="assets/screenshots/3.png" class="img-thumbnail">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">List View of Products Expired Today.</h3>
<img src="assets/screenshots/4.png" class="img-thumbnail">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Products Expiry Cards</h3>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Cards displaying product count expiring tomorrow, in 7 days,
30 days and 120 days, each clickable to redirect to its corresponding list view.
</p>
<img src="assets/screenshots/5.png" class="img-thumbnail">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">List View of Products Expiry in Tomorrow</h3>
<img src="assets/screenshots/6.png" class="img-thumbnail">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Card Filtration</h3>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
The cards can be filtered using date.
</p>
<img src="assets/screenshots/7.png" class="img-thumbnail">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Graphs based on Card Filtration</h3>
<img src="assets/screenshots/8.png" class="img-thumbnail">
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12">
<div style="display: block; margin: 30px auto;">
<h3 style="font-family: 'Montserrat', sans-serif; font-size: 18px; font-weight: bold;">Total Expired Products</h3>
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;">
Total expired products based on product name and product catrgory.
</p>
<img src="assets/screenshots/9.png" class="img-thumbnail">
</div>
</div>
</div>
<!-- END OF SCREENSHOTS SECTION -->
<!-- RELATED PRODUCTS -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/categories.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Related
Products
</h2>
</div>
<div class="row">
<div class="col-sm-12">
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner" style="padding: 30px;">
<div class="carousel-item" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/product_management_app/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/module01.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/odoo_dynamic_dashboard/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/module02.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/inventory_stock_dashboard_odoo/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/module03.png">
</div>
</a>
</div>
</div>
<div class="carousel-item active" style="min-height: 198.656px;">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/project_dashboard_odoo/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/module04.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/crm_dashboard/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/module05.png">
</div>
</a>
</div>
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" style="float:left">
<a href="https://apps.odoo.com/apps/modules/16.0/dashboard_pos/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-radius: 0px;"
src="./assets/modules/module06.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev" style="width:35px; color:#000"> <span
class="carousel-control-prev-icon"><i class="fa fa-chevron-left" style="font-size:24px"></i></span>
</a> <a class="carousel-control-next" href="#demo1" data-slide="next" style="width:35px; color:#000">
<span class="carousel-control-next-icon"><i class="fa fa-chevron-right"
style="font-size:24px"></i></span>
</a>
</div>
</div>
</div>
<!-- END OF RELATED PRODUCTS -->
<!-- OUR SERVICES -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/star.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Our Services
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/cogs.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Customization</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/wrench.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/lifebuoy.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Support</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/user.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Hire
Odoo
Developer</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #54a0ff !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/puzzle.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Integration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/update.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Migration</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/consultation.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Consultancy</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/training.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Implementation</h6>
</div>
<div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4">
<div class="d-flex justify-content-center align-items-center mx-3 my-3"
style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;">
<img src="assets/icons/license.png" class="img-responsive" height="48px" width="48px">
</div>
<h6 class="text-center" style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;">
Odoo
Licensing Consultancy</h6>
</div>
</div>
</div>
<!-- END OF END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/corporate.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Our
Industries
</h2>
</div>
<div class="container my-5">
<div class="row">
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/trading-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Trading
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easily procure
and
sell your products</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/pos-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
POS
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Easy
configuration
and convivial experience</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/education-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Education
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
A platform for
educational management</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/manufacturing-black.png" class="img-responsive mb-3" height="48px"
width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Manufacturing
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Plan, track and
schedule your operations</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/ecom-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
E-commerce &amp; Website
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Mobile
friendly,
awe-inspiring product pages</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/service-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Service Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Keep track of
services and invoice</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/restaurant-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Restaurant
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
Run your bar or
restaurant methodically</p>
</div>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 0px; padding: 2rem !important; height: 250px !important;">
<img src="assets/icons/hotel-black.png" class="img-responsive mb-3" height="48px" width="48px">
<h5 style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;">
Hotel Management
</h5>
<p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;">
An
all-inclusive
hotel management application</p>
</div>
</div>
</div>
</div>
<!-- END OF END OF OUR INDUSTRIES -->
<!-- SUPPORT -->
<div class="d-flex align-items-center" style="border-bottom: 2px solid #714B67; padding: 15px 0px;">
<div class="d-flex justify-content-center align-items-center mr-2"
style="background-color: #F5F5F5; border-radius: 0px; width: 40px; height: 40px;">
<img src="assets/misc/customer-support.png"/>
</div>
<h2 class="mt-2" style="font-family: 'Montserrat', sans-serif; font-size: 24px; font-weight: bold;">Support</h2>
</div>
<div class="container mt-5">
<div class="row">
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #714B67; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/support.png" height="48" width="48" style="width: 42px; height: 42px;" />
</div>
<div>
<h4>Need Help?</h4>
<p style="line-height: 100%;">Got questions or need help? Get in touch.</p>
<a href="mailto:odoo@cybrosys.com">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">odoo@cybrosys.com</p>
</a>
</div>
</div>
</div>
<div class="col-sm-12 col-md-6">
<div style="background-color: #F6F8F9; padding: 30px; display: flex; align-items: center;">
<div class="mr-4 d-flex justify-content-center align-items-center"
style="background-color: #2AC44D; display: inline-block; height: 70px; width: 70px; display: flex; align-items: center; justify-content: center;">
<img src="assets/misc/whatsapp.png" height="52" width="52" style="width: 52px; height: 52px;" />
</div>
<div>
<h4>WhatsApp</h4>
<p style="line-height: 100%;">Say hi to us on WhatsApp!</p>
<a href="https://api.whatsapp.com/send?phone=918606827707">
<p style="font-weight: 400; font-size: 28px; line-height: 80%; color: #714B67;">+91 8606827707</p>
</a>
</div>
</div>
</div>
</div>
<div class="row">
<div class="col-sm-12 my-5 d-flex justify-content-center align-items-center">
<img src="assets/misc/logo.png" width="144" height="31" style="width:144px; height: 31px; margin-top: 40px;" />
</div>
</div>
</div>
<!-- END OF SUPPORT -->

76
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;
}

602
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('<center>'
+ '<span style="font-size: xxx-large;" id="one_day">' + result[0]['counts'] + '</span>'
+ '</center>');
$(".seven-day").append('<center>'
+ '<span style="font-size: xxx-large;" id="seven_day">' + seven_day + '</span>'
+ '</center>');
$(".thirty-day").append('<center>'
+ '<span style="font-size: xxx-large;" id="thirty_day">' + result[2]['counts'] + '</span>'
+ '</center>');
$(".one-twenty-day").append('<center>'
+ '<span style="font-size: xxx-large;" id="one_twenty_day">' + result[3]['counts'] + '</span>'
+ '</center>');
});
}
// 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('<p style="font-size: 38px;margin-top: -10px;">' + result + '</p>');
});
}
// 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);

178
odoo_product_expiry_dashboard/static/src/xml/product_expiry_dashboard.xml

@ -0,0 +1,178 @@
<?xml version="1.0" encoding="UTF-8" ?>
<template id="expiry_dashboard_template">
<!-- Product Expiry Dashboard Template -->
<t t-name="ProductExpiryDashboard" owl="1">
<!-- Main component for the Product Expiry Dashboard -->
<!-- Container for the entire dashboard content -->
<div class="o_action_manager "
style="height:100%; overflow-y: scroll; overflow-x: scroll;">
<!-- Main section of the dashboard -->
<section class="dashboard_main_section" id="main_section_manager">
<!-- Dashboard header -->
<div class="dashboard-heading shadow-sm">
<!-- Section to display products expired today -->
<div class="product_expired_heading card-block" t-on-click="click_expired_today">
<!-- Heading for products expired today -->
<h2 style="margin-top: 8px;">Products Expired Today</h2>
<hr/>
</div>
<!-- Centered banner for the dashboard -->
<center>
<div style="width: 544px">
<h1 class="banner-heading">Product Expiry Dashboard</h1>
</div>
</center>
<!-- Date filtering form -->
<div class="col-12 " style="color: white; display: flex; justify-content: flex-end;">
<form class="form-group">
<span>Start Date: </span>
<input type="date" id="start_date" name="start_date" t-on-change="filter_date" style="border-radius: 5px; font-family: monospace; padding: 5px; border: none;"/>
<span> End Date: </span>
<input type="date" id="end_date" name="end_date" t-on-change="filter_date" style="border-radius: 5px; font-family: monospace; padding: 5px; border: none;"/>
</form>
</div>
</div>
<br/>
<!-- Row for displaying cards showing expiries within different timeframes -->
<div class="row expiry_dashboard_row">
<div class="col-md-4 col-xl-3">
<!-- Card for products expiring in 1 day -->
<div class="card bg-c-blue order-card">
<div class="card-block one-day" t-on-click="one_day_click">
<h2 style="color:white; text-align:center;">Expiry Tomorrow</h2>
<hr/>
</div>
</div>
</div>
<div class="col-md-4 col-xl-3">
<!-- Card for products expiring in 7 days -->
<div class="card bg-c-green order-card">
<div class="card-block seven-day" t-on-click="seven_day_click">
<h2 style="color:white; text-align:center;">Expiry in 7 Days</h2>
<hr/>
</div>
</div>
</div>
<div class="col-md-4 col-xl-3">
<!-- Card for products expiring in 30 days -->
<div class="card bg-c-yellow order-card">
<div class="card-block thirty-day" t-on-click="thirty_day_click">
<h2 style="color:white; text-align:center;">Expiry in 30 Days</h2>
<hr/>
</div>
</div>
</div>
<div class="col-md-4 col-xl-3">
<!-- Card for products expiring in 120 days -->
<div class="card bg-c-pink order-card">
<div class="card-block one-twenty-day" t-on-click="one_twenty_day_click">
<h2 style="color:white; text-align:center;">Expiry in 120 Days</h2>
<hr/>
</div>
</div>
</div>
</div>
<br/>
<!-- Row for displaying charts related to expired products -->
<div class="row">
<div class="col-md">
<div class="shadow-sm m-2 p-4"
style="border-radius:5px; background-color: snow;"
t-on-click="click_expired_today">
<center>
<h2 class="chart_heading" style="margin-top: 8px;">Products Expired Today</h2>
</center>
<!-- Chart for displaying the count of expired products -->
<div>
<canvas id="today_expire_products"/>
</div>
</div>
</div>
<div class="col-md">
<div class="shadow-sm m-2 p-4"
style="border-radius:5px; background-color: snow;">
<center>
<h2 class="chart_heading" style="margin-top: 8px;">Products Expired Today by Category</h2>
</center>
<!-- Chart for displaying the count of expired products by category -->
<div>
<canvas id="today_expire_products_category"/>
</div>
</div>
</div>
</div>
<!-- Row for displaying charts related to products expiring within 7 days -->
<div class="row">
<div class="col-md">
<div class="shadow-sm m-2 p-4"
style="border-radius:5px; background-color: snow;"
t-on-click="seven_day_click">
<center>
<h2 class="chart_heading" style="margin-top: 8px;">Products Expire in 7 Days</h2>
</center>
<!-- Chart for displaying products expiring within 7 days -->
<div>
<canvas t-ref="asd" id="nearby_expire_product"/>
</div>
</div>
</div>
<div class="col-md">
<div class="shadow-sm m-2 p-4"
style="border-radius:5px; background-color: snow;">
<center>
<h2 class="chart_heading" style="margin-top: 8px;">Products Category Expire in 7 Days</h2>
</center>
<!-- Chart for displaying products expiring by category within 7 days -->
<div>
<canvas id="nearby_expire_catg"/>
</div>
</div>
</div>
</div>
<!-- Row for displaying charts related to products expiring within 7 days and their location/warehouse -->
<div class="row">
<div class="col-lg-3">
<div class="shadow-sm m-2 p-4"
style="border-radius:5px; background-color: snow;">
<center>
<!-- Chart for displaying products expiring by location within 7 days -->
<h2 class="chart_heading" style="margin-top: 8px;">Location Expire in 7 Days</h2>
<canvas id="nearby_expire_location"/>
</center>
</div>
</div>
<div class="col-lg-3">
<div class="shadow-sm m-2 p-4"
style="border-radius:5px; background-color: snow;">
<center>
<!-- Chart for displaying products expiring by warehouse within 7 days -->
<h2 class="chart_heading" style="margin-top: 8px;">Products by Warehouse Expire in 7 Days</h2>
<canvas id="nearby_expire_warehouse"/>
</center>
</div>
</div>
<div class="col-lg-3">
<div class="shadow-sm m-2 p-4"
style="border-radius:5px; background-color: snow;">
<center>
<!-- Chart for displaying products expiring by location within 7 days -->
<h2 class="chart_heading" style="margin-top: 8px;">Expired Products</h2>
<canvas id="expired_product_count"/>
</center>
</div>
</div>
<div class="col-lg-3">
<div class="shadow-sm m-2 p-4"
style="border-radius:5px; background-color: snow;">
<center>
<!-- Chart for displaying products expiring by warehouse within 7 days -->
<h2 class="chart_heading" style="margin-top: 8px;">Expired Products by Category</h2>
<canvas id="expired_product_category_count"/>
</center>
</div>
</div>
</div>
</section>
</div>
</t>
</template>

21
odoo_product_expiry_dashboard/views/product_expiry_views.xml

@ -0,0 +1,21 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<data>
<!-- Record for defining a client action for the Expiry Dashboard -->
<record id="action_expiry_dashboard" model="ir.actions.client">
<!-- Name of the client action -->
<field name="name">Expiry Dashboard</field>
<!-- Tag to identify the client action as related to product expiry -->
<field name="tag">product_expiry</field>
<!-- Target for opening the client action in the current window -->
<field name="target">current</field>
</record>
<!-- Menu item for accessing the Product Expiry Dashboard -->
<menuitem
id="expiry_dashboard"
name="Product Expiry Dashboard"
action="action_expiry_dashboard"
parent="stock.menu_stock_root"
sequence="1"/>
</data>
</odoo>
Loading…
Cancel
Save