@ -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>`__ | 
				
			||||
@ -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 | 
				
			||||
@ -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 | 
				
			||||
 | 
					} | 
				
			||||
@ -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 | 
				
			||||
@ -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 | 
				
			||||
@ -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 | 
				
			||||
| 
		 After Width: | Height: | Size: 3.6 KiB  | 
| 
		 After Width: | Height: | Size: 310 B  | 
| 
		 After Width: | Height: | Size: 1.3 KiB  | 
| 
		 After Width: | Height: | Size: 1.4 KiB  | 
| 
		 After Width: | Height: | Size: 576 B  | 
| 
		 After Width: | Height: | Size: 733 B  | 
| 
		 After Width: | Height: | Size: 911 B  | 
| 
		 After Width: | Height: | Size: 1.1 KiB  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 3.4 KiB  | 
| 
		 After Width: | Height: | Size: 673 B  | 
| 
		 After Width: | Height: | Size: 878 B  | 
| 
		 After Width: | Height: | Size: 653 B  | 
| 
		 After Width: | Height: | Size: 905 B  | 
| 
		 After Width: | Height: | Size: 839 B  | 
| 
		 After Width: | Height: | Size: 427 B  | 
| 
		 After Width: | Height: | Size: 627 B  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 988 B  | 
| 
		 After Width: | Height: | Size: 1.2 KiB  | 
| 
		 After Width: | Height: | Size: 1.5 KiB  | 
| 
		 After Width: | Height: | Size: 1.1 KiB  | 
| 
		 After Width: | Height: | Size: 1.9 KiB  | 
| 
		 After Width: | Height: | Size: 1.1 KiB  | 
| 
		 After Width: | Height: | Size: 2.1 KiB  | 
| 
		 After Width: | Height: | Size: 4.4 KiB  | 
| 
		 After Width: | Height: | Size: 589 B  | 
| 
		 After Width: | Height: | Size: 3.4 KiB  | 
| 
		 After Width: | Height: | Size: 1.7 KiB  | 
| 
		 After Width: | Height: | Size: 2.3 KiB  | 
| 
		 After Width: | Height: | Size: 967 B  | 
| 
		 After Width: | Height: | Size: 1.6 KiB  | 
| 
		 After Width: | Height: | Size: 3.8 KiB  | 
| 
		 After Width: | Height: | Size: 5.0 KiB  | 
| 
		 After Width: | Height: | Size: 79 KiB  | 
| 
		 After Width: | Height: | Size: 82 KiB  | 
| 
		 After Width: | Height: | Size: 82 KiB  | 
| 
		 After Width: | Height: | Size: 84 KiB  | 
| 
		 After Width: | Height: | Size: 79 KiB  | 
| 
		 After Width: | Height: | Size: 77 KiB  | 
| 
		 After Width: | Height: | Size: 63 KiB  | 
| 
		 After Width: | Height: | Size: 182 KiB  | 
| 
		 After Width: | Height: | Size: 122 KiB  | 
| 
		 After Width: | Height: | Size: 185 KiB  | 
| 
		 After Width: | Height: | Size: 77 KiB  | 
| 
		 After Width: | Height: | Size: 182 KiB  | 
| 
		 After Width: | Height: | Size: 71 KiB  | 
| 
		 After Width: | Height: | Size: 187 KiB  | 
| 
		 After Width: | Height: | Size: 114 KiB  | 
| 
		 After Width: | Height: | Size: 116 KiB  | 
| 
		 After Width: | Height: | Size: 301 KiB  | 
| 
		 After Width: | Height: | Size: 97 KiB  | 
| 
		 After Width: | Height: | Size: 11 KiB  | 
@ -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 & 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 --> | 
				
			||||
@ -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; | 
				
			||||
 | 
					} | 
				
			||||
@ -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); | 
				
			||||
@ -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> | 
				
			||||
@ -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> | 
				
			||||