Browse Source

Oct 20 : [ADD] Initial Commit 'odoo_product_expiry_dashboard'

pull/254/merge
RisvanaCybro 2 years ago
parent
commit
87b84b8082
  1. 46
      odoo_product_expiry_dashboard/README.rst
  2. 22
      odoo_product_expiry_dashboard/__init__.py
  3. 53
      odoo_product_expiry_dashboard/__manifest__.py
  4. 7
      odoo_product_expiry_dashboard/doc/RELEASE_NOTES.md
  5. 22
      odoo_product_expiry_dashboard/models/__init__.py
  6. 195
      odoo_product_expiry_dashboard/models/stock_production_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/modules/avg_lc.png
  28. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/brand_inventory.png
  29. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/export_stock.png
  30. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/inter_company.png
  31. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/scrap.png
  32. BIN
      odoo_product_expiry_dashboard/static/description/assets/modules/serial_number.png
  33. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot1.png
  34. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot2.png
  35. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot3.png
  36. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot5.png
  37. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot6.png
  38. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/Screenshot7.png
  39. BIN
      odoo_product_expiry_dashboard/static/description/assets/screenshots/hero.gif
  40. BIN
      odoo_product_expiry_dashboard/static/description/banner.jpg
  41. BIN
      odoo_product_expiry_dashboard/static/description/icon.png
  42. 626
      odoo_product_expiry_dashboard/static/description/index.html
  43. 86
      odoo_product_expiry_dashboard/static/src/css/style.css
  44. 396
      odoo_product_expiry_dashboard/static/src/js/product_expiry_action.js
  45. 216
      odoo_product_expiry_dashboard/static/src/xml/odoo_product_expiry_dashboard.xml
  46. 16
      odoo_product_expiry_dashboard/views/product_expiry_view.xml

46
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 <https://cybrosys.com/>`__
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 <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) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
from . import models

53
odoo_product_expiry_dashboard/__manifest__.py

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

7
odoo_product_expiry_dashboard/doc/RELEASE_NOTES.md

@ -0,0 +1,7 @@
## Module <odoo_product_expiry_dashboard>
#### 13.10.2023
#### Version 15.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) 2023-TODAY Cybrosys Technologies(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
from . import stock_production_lot

195
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(<https://www.cybrosys.com>).
# 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 <http://www.gnu.org/licenses/>.
#
################################################################################
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

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/modules/avg_lc.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 70 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 72 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 80 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 136 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

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

Binary file not shown.

After

Width:  |  Height:  |  Size: 238 KiB

BIN
odoo_product_expiry_dashboard/static/description/banner.jpg

Binary file not shown.

After

Width:  |  Height:  |  Size: 82 KiB

BIN
odoo_product_expiry_dashboard/static/description/icon.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.9 KiB

626
odoo_product_expiry_dashboard/static/description/index.html

@ -0,0 +1,626 @@
<div class="container"
style="padding: 1rem !important; margin-bottom: 1rem !important;">
<div class="row">
<div class="col-sm-12 col-md-12 col-lg-12 d-flex justify-content-between"
style="border-bottom: 1px solid #d5d5d5;">
<div class="my-3">
<img src="./assets/icons/logo.png"
style="width: auto !important; height: 40px !important;">
</div>
<div class="my-3 d-flex align-items-center">
<div
style="background-color: #7C7BAD !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;">
<i class="fa fa-check mr-1"></i>Community
</div>
<div
style="background-color: #875A7B !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;">
<i class="fa fa-check mr-1"></i>Enterprise
</div>
</div>
</div>
</div>
</div>
<div class="container" style="padding: 0rem 1.5rem 4rem !important">
<div class="row" style="height: 900px !important;">
<div class="col-sm-12 col-md-12 col-lg-12"
style="padding: 4rem 1rem !important; background-color: #714B67 !important; height: 600px !important; border-radius: 20px !important;">
<h1
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #FFFFFF !important; font-size: 3.5rem !important; text-align: center !important;">
Product Expiry Dashboard</h1>
<p
style="font-family: 'Montserrat', sans-serif !important; font-weight: 300 !important; color: #FFFFFF !important; font-size: 1.4rem !important; text-align: center !important;">
Product Expiry Dashboard Allow Users to View All the Product
Details those are About to Expire.
</p>
<img src="./assets/screenshots/hero.gif" class="img-responsive"
width="100%" height="auto"/>
</div>
</div>
<div class="row">
<div class="col-md-12"
style="border-bottom: 1px solid #d5d5d5 !important; margin-bottom: 2rem !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-compass mr-2"></i>Explore this module
</h2>
</div>
<div class="col-md-6">
<a href="#overview" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Overview</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
Learn more about this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right"
style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<a href="#features" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Features</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
View features of this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right"
style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
<div class="col-md-6">
<a href="#screenshots" style="text-decoration: none !important;">
<div class="row"
style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;">
<div class="col-8">
<h3
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;">
Screenshots</h3>
<p
style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;">
See key screenshots of this module</p>
</div>
<div class="col-4 text-right d-flex justify-content-end align-items-center">
<i class="fa fa-chevron-right"
style="color: #714B67 !important;"></i>
</div>
</div>
</a>
</div>
</div>
<div class="row" id="overview">
<div class="col-md-12"
style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-pie-chart mr-2"></i>Overview
</h2>
</div>
<div class="col-mg-12 pl-3">
<p style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important; line-height: 30px !important;">
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.
</p>
</div>
</div>
<div class="row" id="features">
<div class="col-md-12"
style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-star mr-2"></i>Features
</h2>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Shows all Products which are already Expired.</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Shows all Products which will Expire Today.</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Contains Tiles for displaying Count of Products which will
Expire soon based on their Expiry Date.</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Graphical view of Expired Products</h4>
</div>
</div>
<div class="col-md-6 pl-3 py-3 d-flex">
<div>
<img src="assets/icons/check.png">
</div>
<div>
<h4 style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Graphical view of Nearly Expiring Products based on their
Location and Warehouse</h4>
</div>
</div>
</div>
</div>
<div class="row" id="screenshots">
<div class="col-md-12"
style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important">
<h2
style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;">
<i class="fa fa-image mr-2"></i>Screenshots
</h2>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Product Expiry Dashboard view</h4>
<img src="assets/screenshots/Screenshot1.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Bottom part of Product Expiry Dashboard</h4>
<img src="assets/screenshots/Screenshot2.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Count of Expiring Products if no Start or End Date selected</h4>
<img src="assets/screenshots/Screenshot3.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Count of Products whose Expiry Date is between Start or End Date
selected</h4>
<img src="assets/screenshots/Screenshot5.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
Click on any Tile to view corresponding Products</h4>
<img src="assets/screenshots/Screenshot6.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
<div class="col-lg-12 my-2">
<h4 class="mt-2"
style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;">
List of Products corresponding to the Tile clicked</h4>
<img src="assets/screenshots/Screenshot7.png"
class="img-responsive img-thumbnail border" width="100%"
height="auto"/>
</div>
</div>
<!-- SUGGESTED PRODUCTS -->
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center"
style="text-align: center; padding: 2.5rem 1rem !important;">
<h2 style="color: #212529 !important;">Suggested Products</h2>
<hr style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/>
<div id="demo1" class="row carousel slide" data-ride="carousel">
<!-- The slideshow -->
<div class="carousel-inner">
<div class="carousel-item active" style="min-height:0px">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/export_stockinfo_xls/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/export_stock.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/15.0/stock_intercompany_transfer/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/inter_company.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/15.0/product_brand_inventory/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/brand_inventory.png">
</div>
</a>
</div>
</div>
<div class="carousel-item" style="min-height:0px">
<div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16"
style="float:left">
<a href="https://apps.odoo.com/apps/modules/15.0/product_batch_report/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/serial_number.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/15.0/average_landed_cost/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/avg_lc.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/15.0/scrap_move_report/"
target="_blank">
<div style="border-radius:10px">
<img class="img img-responsive center-block"
style="border-top-left-radius:10px; border-top-right-radius:10px"
src="./assets/modules/scrap.png">
</div>
</a>
</div>
</div>
</div>
<!-- Left and right controls -->
<a class="carousel-control-prev" href="#demo1" data-slide="prev"
style="left:-25px;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="right:-25px;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 SUGGESTED PRODUCTS -->
<!-- OUR SERVICES -->
<section class="container" style="margin-top: 6rem !important;">
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Our Services</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/>
</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: #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>
</section>
<!-- END OF OUR SERVICES -->
<!-- OUR INDUSTRIES -->
<section class="container" style="margin-top: 6rem !important;">
<div class="row">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Our Industries</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/>
</div>
<div class="col-lg-3">
<div class="my-4 d-flex flex-column justify-content-center"
style="background-color: #f6f8f9 !important; border-radius: 10px; 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: 10px; 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: 10px; 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: 10px; 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: 10px; 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: 10px; 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: 10px; 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: 10px; 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>
</section>
<!--END OF OUR INDUSTRIES -->
<!-- FOOTER -->
<!-- Footer Section -->
<section class="container" style="margin: 5rem auto 2rem;">
<div class="row" style="max-width:1540px;">
<div class="col-lg-12 d-flex flex-column justify-content-center align-items-center">
<h2 style="color: #212529 !important;">Need Help?</h2>
<hr
style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/>
</div>
</div>
<!-- Contact Cards -->
<div class="row d-flex justify-content-center align-items-center"
style="max-width:1540px; margin: 0 auto 2rem auto;">
<div class="col-lg-12"
style="padding: 0rem 3rem 2rem; border-radius: 10px; margin-right: 3rem; ">
<div class="row mt-4">
<div class="col-lg-6">
<a href="mailto:odoo@cybrosys.com" target="_blank"
class="btn btn-block mb-2 deep_hover"
style="text-decoration: none; background-color: #4d4d4d; color: #FFF; border-radius: 4px;"><i
class="fa fa-envelope mr-2"></i>odoo@cybrosys.com</a>
</div>
<div class="col-lg-6">
<a href="https://api.whatsapp.com/send?phone=918606827707"
target="_blank"
class="btn btn-block mb-2 deep_hover"
style="text-decoration: none; background-color: #25D366; color: #FFF; border-radius: 4px;"><i
class="fa fa-whatsapp mr-2"></i>+91 86068 27707</a>
</div>
</div>
</div>
</div>
<!-- End of Contact Cards -->
</section>
<!-- Footer -->
<section class="oe_container" style="padding: 2rem 3rem 1rem;">
<div class="row"
style="max-width:1540px; margin: 0 auto; margin-right: 3rem; ">
<!-- Logo -->
<div class="col-lg-12 d-flex justify-content-center align-items-center"
style="margin-top: 3rem;">
<img src="https://www.cybrosys.com/images/logo.png"
width="200px" height="auto"/>
</div>
<!-- End of Logo -->
<div class="col-lg-12">
<hr
style="margin-top: 3rem;background: linear-gradient(90deg, rgba(2,0,36,0) 0%, rgba(229,229,229,1) 33%, rgba(229,229,229,1) 58%, rgba(0,212,255,0) 100%); height: 2px; border-style: none;">
<!-- End of Footer Section -->
</div>
</div>
</section>
<!-- END OF FOOTER -->
<script src="https://cdn.jsdelivr.net/npm/jquery@3.5.1/dist/jquery.slim.min.js"
integrity="sha384-DfXdz2htPH0lsSSs5nCTpuj/zy4C+OGpamoFVy38MVBnE+IbbVYUew+OrCXaRkfj"
crossorigin="anonymous"></script>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@4.6.1/dist/js/bootstrap.bundle.min.js"
integrity="sha384-fQybjgWLrvvRgtW6bFlB7jaZrFsaBXjsOMm/tB9LTS58ONXgqbR9W8oWht/amnpF"
crossorigin="anonymous"></script>

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

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

216
odoo_product_expiry_dashboard/static/src/xml/odoo_product_expiry_dashboard.xml

@ -0,0 +1,216 @@
<?xml version="1.0" encoding="UTF-8" ?>
<template id="expiry_dashboard_template">
<t t-name="ProductExpiryDashboard">
<div class="o_action_manager"
style="height:100%; overflow-y: scroll; overflow-x: hidden;">
<section class="dashboard_main_section" id="main_section_manager">
<!-- Dashboard Header-->
<div class="dashboard-heading shadow-sm">
<center>
<div style="width: 544px">
<h1 class="banner-heading">Product Expiry Dashboard
</h1>
</div>
</center>
<div class="col-4 col-sm-4 col-md-4"
style="float: right;color: white;">
<form class="form-group">
<span>Start Date:</span>
<input type="date" id="start_date"
name="start_date"/>
<span>End Date:</span>
<input type="date" id="end_date" name="end_date"/>
</form>
</div>
</div>
<br/>
<div class="card-group">
<!-- Dashboard Tiles-->
<div class="card">
<div class="card-body">
<div class="container">
<div class="row">
<div class="col-md-2 col-xl-6"
style="float: left">
<div class="card bg-c-red order-card">
<div class="card-block expired">
<h2 style="color:white;
text-align:center;">
Expired
</h2>
<hr/>
</div>
</div>
</div>
<div class="col-md-2 col-xl-6"
style="float: right">
<div class="card bg-c-lavender
order-card">
<div class="card-block today">
<h2 style="color:white;
text-align:center;">
Expire Today
</h2>
<hr/>
</div>
</div>
</div>
<div class="col-md-2 col-xl-6"
style="float: left">
<div class="card bg-c-blue order-card">
<div class="card-block one-day">
<h2 style="color:white;
text-align:center;">
Expire
in 1 Day
</h2>
<hr/>
</div>
</div>
</div>
<div class="col-md-2 col-xl-6"
style="float: right">
<div class="card bg-c-green order-card">
<div class="card-block seven-day">
<h2 style="color:white;
text-align:center;">
Expire
in 7 Days
</h2>
<hr/>
</div>
</div>
</div>
<div class="col-md-2 col-xl-6"
style="float: left">
<div class="card bg-c-yellow
order-card">
<div class="card-block thirty-day">
<h2 style="color:white;
text-align:center;">
Expire
in 30 Days
</h2>
<hr/>
</div>
</div>
</div>
<div class="col-md-2 col-xl-6"
style="float: right">
<div class="card bg-c-pink order-card">
<div class="card-block
one-twenty-day">
<h2 style="color:white;
text-align:center;">
Expire
in 120 Days
</h2>
<hr/>
</div>
</div>
</div>
</div>
</div>
</div>
</div>
<div class="card">
<!-- Graph of Expired Products-->
<div class="card-body">
<center>
<h2 class="card-title">Expired Products</h2>
<div style="max-width: 250px;
margin-right: 120px;">
<canvas id="expired_product_count"/>
</div>
</center>
</div>
<br/>
<br/>
<!-- Graph of Expired Products by Category-->
<div class="card-body">
<center>
<h2 class="card-title">Expired Products by
Category
</h2>
<div style="max-width: 500px;
margin-right: 120px;">
<canvas
id="expired_product_category_count"/>
</div>
</center>
</div>
</div>
<div class="card">
<!-- Graph of Products Expiring in 7 Days-->
<div class="card-body">
<center>
<h2 class="chart_heading">
Products Expiring in 7 Days
</h2>
<div style="max-width: 250px;
margin-right: 120px;">
<canvas id="nearby_expire_product"/>
</div>
</center>
</div>
<br/>
<br/>
<!-- Graph of Category of Products expiring of in
7 Days-->
<div class="card-body">
<center>
<div>
<center>
<h2>Category Products Expiring of in 7
Days
</h2>
</center>
<div style="max-width: 500px;
margin-right: 120px;">
<canvas id="nearby_expire_catg"/>
</div>
</div>
</center>
</div>
</div>
</div>
<div class="row">
<!-- Graph of location of Products expiring of in 7 Days-->
<div class="col-sm-6">
<div class="card">
<div class="card-body">
<center>
<h2 class="chart_heading">Location of
Products Expiring in 7 Days
</h2>
<div style="max-width: 500px;
margin-right: 120px;">
<canvas id="nearby_expire_location"/>
</div>
</center>
</div>
</div>
</div>
<!-- Graph of warehouse of Products expiring of in 7 Days-->
<div class="col-sm-6" >
<div class="card">
<div class="card-body">
<center>
<h2 class="chart_heading">Warehouse of
Products
Expiring in 7 Days
</h2>
<div style="max-width: 500px;
margin-right: 120px;">
<canvas id="nearby_expire_warehouse"/>
</div>
</center>
</div>
</div>
</div>
</div>
</section>
</div>
</t>
</template>

16
odoo_product_expiry_dashboard/views/product_expiry_view.xml

@ -0,0 +1,16 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<!-- Product Expiry Dashboard action-->
<record id="expiry_dashboard_action" model="ir.actions.client">
<field name="name">Expiry Dashboard</field>
<field name="tag">product_expiry</field>
<field name="target">current</field>
</record>
<!-- Product Expiry Dashboard menu-->
<menuitem
id="expiry_dashboard_menu"
name="Product Expiry Dashboard"
action="expiry_dashboard_action"
parent="stock.menu_stock_root"
sequence="99"/>
</odoo>
Loading…
Cancel
Save