@ -0,0 +1,46 @@ | 
				
			|||||
 | 
					.. image:: https://img.shields.io/badge/license-LGPL--3-green.svg | 
				
			||||
 | 
					    :target: https://www.gnu.org/licenses/lgpl-3.0-standalone.html | 
				
			||||
 | 
					    :alt: License: LGPL-3 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Stock 3D View | 
				
			||||
 | 
					============= | 
				
			||||
 | 
					Virtual 3D Visualization of warehouses and Locations | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Configuration | 
				
			||||
 | 
					============= | 
				
			||||
 | 
					The user should be added to the security group: Administrator(Inventory/ Stock) inorder to get access to the 3d view.. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					License | 
				
			||||
 | 
					------- | 
				
			||||
 | 
					General Public License, Version 3 (LGPL v3). | 
				
			||||
 | 
					(https://www.gnu.org/licenses/lgpl-3.0-standalone.html) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Company | 
				
			||||
 | 
					------- | 
				
			||||
 | 
					* `Cybrosys Techno Solutions <https://cybrosys.com/>`__ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Credits | 
				
			||||
 | 
					------- | 
				
			||||
 | 
					* Developers: (V16) Prasanna Kumara B, Contact: odoo@cybrosys.com | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Contacts | 
				
			||||
 | 
					-------- | 
				
			||||
 | 
					* Mail Contact : odoo@cybrosys.com | 
				
			||||
 | 
					* Website : https://cybrosys.com | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Bug Tracker | 
				
			||||
 | 
					----------- | 
				
			||||
 | 
					Bugs are tracked on GitHub Issues. In case of trouble, please check there if your issue has already been reported. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Maintainer | 
				
			||||
 | 
					========== | 
				
			||||
 | 
					.. image:: https://cybrosys.com/images/logo.png | 
				
			||||
 | 
					   :target: https://cybrosys.com | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					This module is maintained by Cybrosys Technologies. | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					For support and more information, please visit `Our Website <https://cybrosys.com/>`__ | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					Further information | 
				
			||||
 | 
					=================== | 
				
			||||
 | 
					HTML Description: `<static/description/index.html>`__ | 
				
			||||
@ -0,0 +1,23 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2023-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 LESSER | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (LGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					from . import controllers | 
				
			||||
 | 
					from . import models | 
				
			||||
@ -0,0 +1,63 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2023-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 LESSER | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (LGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					{ | 
				
			||||
 | 
					    'name': "Stock 3D View", | 
				
			||||
 | 
					    'version': '15.0.1.0.0', | 
				
			||||
 | 
					    'category': 'Warehouse', | 
				
			||||
 | 
					    'summary': """Virtual 3D Visualization of warehouses and Locations""", | 
				
			||||
 | 
					    'description': """This module innovative addition to the inventory and  | 
				
			||||
 | 
					     warehouse management module, enhancing the traditional methods of tracking  | 
				
			||||
 | 
					     stock and warehouse operations. Leveraging advanced visualization  | 
				
			||||
 | 
					     technology, this app provides users with an immersive and dynamic  | 
				
			||||
 | 
					     three-dimensional representation of their warehouses, inventory items, and  | 
				
			||||
 | 
					     stock movements.""", | 
				
			||||
 | 
					    'author': 'Cybrosys Techno Solutions', | 
				
			||||
 | 
					    'company': 'Cybrosys Techno Solutions', | 
				
			||||
 | 
					    'maintainer': 'Cybrosys Techno Solutions', | 
				
			||||
 | 
					    'website': "https://www.cybrosys.com", | 
				
			||||
 | 
					    'depends': ['stock', 'web'], | 
				
			||||
 | 
					    'data': [ | 
				
			||||
 | 
					        'views/stock_location_views.xml', | 
				
			||||
 | 
					    ], | 
				
			||||
 | 
					    'assets': { | 
				
			||||
 | 
					        'web.assets_backend': [ | 
				
			||||
 | 
					            '/stock_3d_view/static/src/js/form_3d_view.js', | 
				
			||||
 | 
					            '/stock_3d_view/static/src/js/listview_3d.js', | 
				
			||||
 | 
					            '/stock_3d_view/static/src/css/3d_view.scss', | 
				
			||||
 | 
					            'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.js', | 
				
			||||
 | 
					            'https://cdnjs.cloudflare.com/ajax/libs/three.js/r128/three.min.js', | 
				
			||||
 | 
					            "https://cdn.jsdelivr.net/npm/three@0.122.0/examples/js/controls/OrbitControls.min.js", | 
				
			||||
 | 
					        ], | 
				
			||||
 | 
					        'web.assets_qweb': [ | 
				
			||||
 | 
					            'stock_3d_view/static/src/xml/stock_location_3d_templates.xml', | 
				
			||||
 | 
					            'stock_3d_view/static/src/xml/stock_location_modal_templates.xml', | 
				
			||||
 | 
					            'stock_3d_view/static/src/xml/stock_location_breadcrumb_templates.xml', | 
				
			||||
 | 
					        ], | 
				
			||||
 | 
					    }, | 
				
			||||
 | 
					    'images': [ | 
				
			||||
 | 
					        'static/description/banner.png', | 
				
			||||
 | 
					    ], | 
				
			||||
 | 
					    'license': 'LGPL-3', | 
				
			||||
 | 
					    'installable': True, | 
				
			||||
 | 
					    'auto_install': False, | 
				
			||||
 | 
					    'application': False, | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,22 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2023-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 LESSER | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (LGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					from . import stock_3d_view | 
				
			||||
@ -0,0 +1,170 @@ | 
				
			|||||
 | 
					"""This module handles the requests made by js files and returns the corresponding data.""" | 
				
			||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2023-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 LESSER | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (LGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					import math | 
				
			||||
 | 
					from odoo import http | 
				
			||||
 | 
					from odoo.http import request | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class Stock3DView(http.Controller): | 
				
			||||
 | 
					    """Class for handling the requests and responses""" | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route('/3Dstock/warehouse', type='json', auth='public') | 
				
			||||
 | 
					    def get_warehouse_data(self, company_id): | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        This method is used to handle the request for warehouse data. | 
				
			||||
 | 
					        ------------------------------------------------ | 
				
			||||
 | 
					        @param self: object pointer. | 
				
			||||
 | 
					        @param company_id: current company id. | 
				
			||||
 | 
					        @return: a list of warehouses created under the active company. | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        warehouse = request.env['stock.warehouse'].sudo().search([]) | 
				
			||||
 | 
					        warehouse_list = [] | 
				
			||||
 | 
					        warehouse_list.clear() | 
				
			||||
 | 
					        for rec in warehouse: | 
				
			||||
 | 
					            if rec.company_id.id == company_id: | 
				
			||||
 | 
					                warehouse_list.append((rec.id, rec.name)) | 
				
			||||
 | 
					        return warehouse_list | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route('/3Dstock/data', type='json', auth='public') | 
				
			||||
 | 
					    def get_stock_data(self, company_id, wh_id): | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        This method is used to handle the request for location data. | 
				
			||||
 | 
					        ------------------------------------------------ | 
				
			||||
 | 
					        @param self: object pointer | 
				
			||||
 | 
					        @param company_id: current company id. | 
				
			||||
 | 
					        @param wh_id: the selected warehouse id. | 
				
			||||
 | 
					        @return:a list of locations with their dimensions and positions of | 
				
			||||
 | 
					                selected warehouse. | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        warehouse = request.env['stock.warehouse'].sudo().search( | 
				
			||||
 | 
					            [('id', '=', int(wh_id)), ('company_id', '=', int(company_id))]) | 
				
			||||
 | 
					        locations = request.env['stock.location'].sudo().search( | 
				
			||||
 | 
					            [('company_id', '=', int(company_id)), | 
				
			||||
 | 
					             ('active', '=', 'true'), | 
				
			||||
 | 
					             ('usage', '=', 'internal')]) | 
				
			||||
 | 
					        location_dict = {} | 
				
			||||
 | 
					        for loc in locations: | 
				
			||||
 | 
					            for wh in warehouse: | 
				
			||||
 | 
					                if loc.warehouse_id.id == warehouse.id: | 
				
			||||
 | 
					                    if loc.id not in ( | 
				
			||||
 | 
					                            wh.lot_stock_id.id, wh.wh_input_stock_loc_id.id, | 
				
			||||
 | 
					                            wh.wh_qc_stock_loc_id.id, | 
				
			||||
 | 
					                            wh.wh_pack_stock_loc_id.id, wh.wh_output_stock_loc_id.id): | 
				
			||||
 | 
					                        length = int(loc.length * 3.779 * 2) | 
				
			||||
 | 
					                        width = int(loc.width * 3.779 * 2) | 
				
			||||
 | 
					                        height = int(loc.height * 3.779 * 2) | 
				
			||||
 | 
					                        location_dict.update( | 
				
			||||
 | 
					                            {loc.unique_code: [loc.pos_x, loc.pos_y, loc.pos_z, | 
				
			||||
 | 
					                                               length, width, height]}) | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        return location_dict | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route('/3Dstock/data/quantity', type='json', auth='public') | 
				
			||||
 | 
					    def get_stock_count_data(self, loc_code): | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        This method is used to handle the request for location's current stock | 
				
			||||
 | 
					        quantity. | 
				
			||||
 | 
					        ------------------------------------------------ | 
				
			||||
 | 
					        @param self: object pointer. | 
				
			||||
 | 
					        @param loc_code: the selected location code. | 
				
			||||
 | 
					        @return: current quantity of selected location. | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        quantity = request.env['stock.quant'].sudo().search( | 
				
			||||
 | 
					            [('location_id.unique_code', '=', loc_code)]).mapped( | 
				
			||||
 | 
					            'quantity') | 
				
			||||
 | 
					        capacity = request.env['stock.location'].sudo().search( | 
				
			||||
 | 
					            [('unique_code', '=', loc_code)]).max_capacity | 
				
			||||
 | 
					        count = math.fsum(quantity) | 
				
			||||
 | 
					        quant_data = (0, 0) | 
				
			||||
 | 
					        if capacity: | 
				
			||||
 | 
					            if capacity > 0: | 
				
			||||
 | 
					                load = int((count * 100) / capacity) | 
				
			||||
 | 
					                quant_data = (capacity, load) | 
				
			||||
 | 
					            else: | 
				
			||||
 | 
					                if count > 0: | 
				
			||||
 | 
					                    quant_data = (0, -1) | 
				
			||||
 | 
					        return quant_data | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route('/3Dstock/data/product', type='json', auth='public') | 
				
			||||
 | 
					    def get_stock_product_data(self, loc_code): | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        This method is used to handle the request for data of products of | 
				
			||||
 | 
					        selected location. | 
				
			||||
 | 
					        ------------------------------------------------ | 
				
			||||
 | 
					        @param self: object pointer. | 
				
			||||
 | 
					        @param loc_code: the selected location code. | 
				
			||||
 | 
					        @return: a dictionary including total capacity, current capacity and | 
				
			||||
 | 
					        products stored in selected location. | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        products = request.env['stock.quant'].sudo().search( | 
				
			||||
 | 
					            [('location_id.unique_code', '=', loc_code)]) | 
				
			||||
 | 
					        quantity_obj = request.env['stock.quant'].sudo().search( | 
				
			||||
 | 
					            [('location_id.unique_code', '=', loc_code)]).mapped( | 
				
			||||
 | 
					            'quantity') | 
				
			||||
 | 
					        capacity = request.env['stock.location'].sudo().search( | 
				
			||||
 | 
					            [('unique_code', '=', loc_code)]).max_capacity | 
				
			||||
 | 
					        product_list = [] | 
				
			||||
 | 
					        product_list.clear() | 
				
			||||
 | 
					        if products: | 
				
			||||
 | 
					            for rec in products: | 
				
			||||
 | 
					                product_list.append((rec.product_id.display_name, rec.quantity)) | 
				
			||||
 | 
					        load = math.fsum(quantity_obj) | 
				
			||||
 | 
					        if capacity > 0: | 
				
			||||
 | 
					            space = capacity - load | 
				
			||||
 | 
					        else: | 
				
			||||
 | 
					            space = 0 | 
				
			||||
 | 
					        data = { | 
				
			||||
 | 
					            'capacity': capacity, | 
				
			||||
 | 
					            'space': space, | 
				
			||||
 | 
					            'product_list': product_list | 
				
			||||
 | 
					        } | 
				
			||||
 | 
					        return data | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    @http.route('/3Dstock/data/standalone', type='json', auth='public') | 
				
			||||
 | 
					    def get_standalone_stock_data(self, company_id, loc_id): | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        This method is used to handle the request for individual location data. | 
				
			||||
 | 
					        ------------------------------------------------ | 
				
			||||
 | 
					        @param self: object pointer. | 
				
			||||
 | 
					        @param company_id: the current company id. | 
				
			||||
 | 
					        @param loc_id: the selected location code. | 
				
			||||
 | 
					        @return: a dictionary including of selected location's dimensions and | 
				
			||||
 | 
					        positions. | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        warehouse = request.env['stock.location'].sudo().search( | 
				
			||||
 | 
					            [('company_id.id', '=', int(company_id)), | 
				
			||||
 | 
					             ('id', '=', int(loc_id))]).mapped('warehouse_id') | 
				
			||||
 | 
					        locations = request.env['stock.location'].sudo().search( | 
				
			||||
 | 
					            [('company_id.id', '=', int(company_id)), | 
				
			||||
 | 
					             ('active', '=', 'true'), | 
				
			||||
 | 
					             ('usage', '=', 'internal')]) | 
				
			||||
 | 
					        location_dict = {} | 
				
			||||
 | 
					        for loc in locations: | 
				
			||||
 | 
					            if loc.warehouse_id.id == warehouse.id: | 
				
			||||
 | 
					                length = int(loc.length * 3.779 * 2) | 
				
			||||
 | 
					                width = int(loc.width * 3.779 * 2) | 
				
			||||
 | 
					                height = int(loc.height * 3.779 * 2) | 
				
			||||
 | 
					                location_dict.update( | 
				
			||||
 | 
					                    {loc.unique_code: [loc.pos_x, loc.pos_y, loc.pos_z, | 
				
			||||
 | 
					                                       length, width, height, loc.id]}) | 
				
			||||
 | 
					        return location_dict | 
				
			||||
@ -0,0 +1,6 @@ | 
				
			|||||
 | 
					## Module <stock_3d_view> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					#### 27.09.2023 | 
				
			||||
 | 
					#### Version 15.0.1.0.0 | 
				
			||||
 | 
					#### ADD | 
				
			||||
 | 
					- Initial commit for Stock 3D View | 
				
			||||
@ -0,0 +1,22 @@ | 
				
			|||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2023-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 LESSER | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (LGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					from . import stock_location | 
				
			||||
@ -0,0 +1,67 @@ | 
				
			|||||
 | 
					"""This module inherits stock.location model.""" | 
				
			||||
 | 
					# -*- coding: utf-8 -*- | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Cybrosys Technologies Pvt. Ltd. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    Copyright (C) 2023-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 LESSER | 
				
			||||
 | 
					#    GENERAL PUBLIC LICENSE (LGPL 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 LESSER GENERAL PUBLIC LICENSE (LGPL v3) for more details. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					#    You should have received a copy of the GNU LESSER GENERAL PUBLIC LICENSE | 
				
			||||
 | 
					#    (LGPL v3) along with this program. | 
				
			||||
 | 
					#    If not, see <http://www.gnu.org/licenses/>. | 
				
			||||
 | 
					# | 
				
			||||
 | 
					############################################################################# | 
				
			||||
 | 
					from odoo import fields, models | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					class StockLocation(models.Model): | 
				
			||||
 | 
					    """Class for adding fields to stock.location""" | 
				
			||||
 | 
					    _inherit = 'stock.location' | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    length = fields.Float(string="Length (M)", | 
				
			||||
 | 
					                          help="Length of the location in meters") | 
				
			||||
 | 
					    width = fields.Float(string="Width (M)", | 
				
			||||
 | 
					                         help="Width of the location in meters") | 
				
			||||
 | 
					    height = fields.Float(string="Height (M)", | 
				
			||||
 | 
					                          help="Height of the location in meters") | 
				
			||||
 | 
					    pos_x = fields.Float(string="X (in px)", | 
				
			||||
 | 
					                         help="Position of the location along X-axis") | 
				
			||||
 | 
					    pos_y = fields.Float(string="Y (in px)", | 
				
			||||
 | 
					                         help="Position of the location along Y-axis") | 
				
			||||
 | 
					    pos_z = fields.Float(string="Z (in px)", | 
				
			||||
 | 
					                         help="Position of the location along Z-axis") | 
				
			||||
 | 
					    unique_code = fields.Char(string="Location Code", | 
				
			||||
 | 
					                              help="Unique code of the location") | 
				
			||||
 | 
					    max_capacity = fields.Integer(string="Capacity (Units)", | 
				
			||||
 | 
					                                  help="Maximum capacity of the location in " | 
				
			||||
 | 
					                                       "terms of Units") | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    _sql_constraints = [ | 
				
			||||
 | 
					        ('unique_code', 'UNIQUE(unique_code)', | 
				
			||||
 | 
					         "The location code must be unique per company !"), | 
				
			||||
 | 
					    ] | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    def action_view_location_3d_button(self): | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        This method is used to handle the view_location_3d_button button action. | 
				
			||||
 | 
					        ------------------------------------------------ | 
				
			||||
 | 
					        @param self: object pointer. | 
				
			||||
 | 
					        @return: client action with location id and company id to display. | 
				
			||||
 | 
					        """ | 
				
			||||
 | 
					        return { | 
				
			||||
 | 
					            'type': 'ir.actions.client', | 
				
			||||
 | 
					            'tag': 'open_form_3d_view', | 
				
			||||
 | 
					            'context': { | 
				
			||||
 | 
					                'loc_id': self.id, | 
				
			||||
 | 
					                'company_id': self.company_id.id, | 
				
			||||
 | 
					            } | 
				
			||||
 | 
					        } | 
				
			||||
| 
		 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: 60 KiB  | 
| 
		 After Width: | Height: | Size: 62 KiB  | 
| 
		 After Width: | Height: | Size: 58 KiB  | 
| 
		 After Width: | Height: | Size: 61 KiB  | 
| 
		 After Width: | Height: | Size: 82 KiB  | 
| 
		 After Width: | Height: | Size: 60 KiB  | 
| 
		 After Width: | Height: | Size: 84 KiB  | 
| 
		 After Width: | Height: | Size: 159 KiB  | 
| 
		 After Width: | Height: | Size: 195 KiB  | 
| 
		 After Width: | Height: | Size: 85 KiB  | 
| 
		 After Width: | Height: | Size: 180 KiB  | 
| 
		 After Width: | Height: | Size: 116 KiB  | 
| 
		 After Width: | Height: | Size: 130 KiB  | 
| 
		 After Width: | Height: | Size: 194 KiB  | 
| 
		 After Width: | Height: | Size: 84 KiB  | 
| 
		 After Width: | Height: | Size: 8.2 KiB  | 
@ -0,0 +1,806 @@ | 
				
			|||||
 | 
					<div class="container" | 
				
			||||
 | 
					     style="padding: 1rem !important; margin-bottom: 1rem !important;"> | 
				
			||||
 | 
					    <div class="row"> | 
				
			||||
 | 
					        <div class="col-sm-12 col-md-12 col-lg-12 d-flex justify-content-between" | 
				
			||||
 | 
					             style="border-bottom: 1px solid #d5d5d5;"> | 
				
			||||
 | 
					            <div class="my-3"> | 
				
			||||
 | 
					                <img src="./assets/icons/logo.png" | 
				
			||||
 | 
					                     style="width: auto !important; height: 40px !important;"> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					            <div class="my-3 d-flex align-items-center"> | 
				
			||||
 | 
					                <div | 
				
			||||
 | 
					                        style="background-color: #7C7BAD !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> | 
				
			||||
 | 
					                    <i class="fa fa-check mr-1"></i>Community | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <div | 
				
			||||
 | 
					                        style="background-color: #875A7B !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> | 
				
			||||
 | 
					                    <i class="fa fa-check mr-1"></i>Enterprise | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <div | 
				
			||||
 | 
					                        style="background-color: #875A7B !important; color: #fff !important; font-weight: 600 !important; padding: 5px 15px 8px !important; margin: 0 5px !important;"> | 
				
			||||
 | 
					                    <i class="fa fa-check mr-1"></i>Odoo.sh | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					</div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					<div class="container" style="padding: 0rem 1.5rem 4rem !important"> | 
				
			||||
 | 
					    <div class="row" style="height: 900px !important;"> | 
				
			||||
 | 
					        <div class="col-sm-12 col-md-12 col-lg-12" | 
				
			||||
 | 
					             style="padding: 4rem 1rem !important; background-color: #714B67 !important; height: 600px !important; border-radius: 20px !important;"> | 
				
			||||
 | 
					            <h1 | 
				
			||||
 | 
					                    style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #FFFFFF !important;  font-size: 3.5rem !important; text-align: center !important;"> | 
				
			||||
 | 
					                Stock 3D View | 
				
			||||
 | 
					            </h1> | 
				
			||||
 | 
					            <p | 
				
			||||
 | 
					                    style="font-family: 'Montserrat', sans-serif !important; font-weight: 300 !important; color: #FFFFFF !important;  font-size: 1.4rem !important; text-align: center !important;"> | 
				
			||||
 | 
					                Virtual 3D Visualization of Warehouses and Locations | 
				
			||||
 | 
					            </p> | 
				
			||||
 | 
					            <img src="assets/screenshots/hero.gif" class="img-responsive" width="100%" | 
				
			||||
 | 
					                 height="auto"/> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <div class="row"> | 
				
			||||
 | 
					        <div class="col-md-12" | 
				
			||||
 | 
					             style="border-bottom: 1px solid #d5d5d5 !important; margin-bottom: 2rem !important"> | 
				
			||||
 | 
					            <h2 | 
				
			||||
 | 
					                    style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> | 
				
			||||
 | 
					                <i class="fa fa-compass mr-2"></i>Explore this module | 
				
			||||
 | 
					            </h2> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6"> | 
				
			||||
 | 
					            <a href="#overview" style="text-decoration: none !important;"> | 
				
			||||
 | 
					                <div class="row" | 
				
			||||
 | 
					                     style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;"> | 
				
			||||
 | 
					                    <div class="col-8"> | 
				
			||||
 | 
					                        <h3 | 
				
			||||
 | 
					                                style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;"> | 
				
			||||
 | 
					                            Overview</h3> | 
				
			||||
 | 
					                        <p | 
				
			||||
 | 
					                                style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                            Learn more about this module | 
				
			||||
 | 
					                        </p> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                    <div class="col-4 text-right d-flex justify-content-end align-items-center"> | 
				
			||||
 | 
					                        <i class="fa fa-chevron-right" | 
				
			||||
 | 
					                           style="color: #714B67 !important;"></i> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </a> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6"> | 
				
			||||
 | 
					            <a href="#configuration" style="text-decoration: none !important;"> | 
				
			||||
 | 
					                <div class="row" | 
				
			||||
 | 
					                     style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;"> | 
				
			||||
 | 
					                    <div class="col-8"> | 
				
			||||
 | 
					                        <h3 | 
				
			||||
 | 
					                                style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;"> | 
				
			||||
 | 
					                            Configuration</h3> | 
				
			||||
 | 
					                        <p | 
				
			||||
 | 
					                                style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                            View configurations for this module | 
				
			||||
 | 
					                        </p> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                    <div class="col-4 text-right d-flex justify-content-end align-items-center"> | 
				
			||||
 | 
					                        <i class="fa fa-chevron-right" | 
				
			||||
 | 
					                           style="color: #714B67 !important;"></i> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </a> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6"> | 
				
			||||
 | 
					            <a href="#features" style="text-decoration: none !important;"> | 
				
			||||
 | 
					                <div class="row" | 
				
			||||
 | 
					                     style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;"> | 
				
			||||
 | 
					                    <div class="col-8"> | 
				
			||||
 | 
					                        <h3 | 
				
			||||
 | 
					                                style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;"> | 
				
			||||
 | 
					                            Features</h3> | 
				
			||||
 | 
					                        <p | 
				
			||||
 | 
					                                style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                            View features of this module | 
				
			||||
 | 
					                        </p> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                    <div class="col-4 text-right d-flex justify-content-end align-items-center"> | 
				
			||||
 | 
					                        <i class="fa fa-chevron-right" | 
				
			||||
 | 
					                           style="color: #714B67 !important;"></i> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </a> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6"> | 
				
			||||
 | 
					            <a href="#screenshots" style="text-decoration: none !important;"> | 
				
			||||
 | 
					                <div class="row" | 
				
			||||
 | 
					                     style="background-color: #f5f2f5 !important; border-radius: 10px !important; margin: 1rem !important; padding: 1.5em !important; height: 100px !important;"> | 
				
			||||
 | 
					                    <div class="col-8"> | 
				
			||||
 | 
					                        <h3 | 
				
			||||
 | 
					                                style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.2rem !important;"> | 
				
			||||
 | 
					                            Screenshots</h3> | 
				
			||||
 | 
					                        <p | 
				
			||||
 | 
					                                style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #714B67 !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                            See key screenshots of this module | 
				
			||||
 | 
					                        </p> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                    <div class="col-4 text-right d-flex justify-content-end align-items-center"> | 
				
			||||
 | 
					                        <i class="fa fa-chevron-right" | 
				
			||||
 | 
					                           style="color: #714B67 !important;"></i> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </a> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <div class="row" id="overview"> | 
				
			||||
 | 
					        <div class="col-md-12" | 
				
			||||
 | 
					             style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important"> | 
				
			||||
 | 
					            <h2 | 
				
			||||
 | 
					                    style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> | 
				
			||||
 | 
					                <i class="fa fa-pie-chart mr-2"></i>Overview | 
				
			||||
 | 
					            </h2> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        <div class="col-mg-12 pl-3"> | 
				
			||||
 | 
					            <p | 
				
			||||
 | 
					                    style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important; line-height: 30px !important;"> | 
				
			||||
 | 
					                This app helps users to visualize their stock and locations | 
				
			||||
 | 
					                virtually with integrated features. | 
				
			||||
 | 
					                One can view and manipulate the 3D structure of a stock location | 
				
			||||
 | 
					                using this app. | 
				
			||||
 | 
					                Nowadays warehouse management is hard to handle manually. | 
				
			||||
 | 
					                So, users can handle warehouse management virtually with the | 
				
			||||
 | 
					                help of this app. | 
				
			||||
 | 
					                This app visualizes a 3D view based on multiple warehouses and | 
				
			||||
 | 
					                locations. | 
				
			||||
 | 
					                This app enables users to view, rotate 360° and zoom multi | 
				
			||||
 | 
					                warehouse locations in a 3D space. | 
				
			||||
 | 
					            </p> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <div class="row" id="configuration"> | 
				
			||||
 | 
					        <div class="col-md-12" | 
				
			||||
 | 
					             style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important"> | 
				
			||||
 | 
					            <h2 | 
				
			||||
 | 
					                    style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> | 
				
			||||
 | 
					                <i class="fa fa-cogs mr-2"></i>Configuration | 
				
			||||
 | 
					            </h2> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6 pl-3 py-3 d-flex"> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <h4 | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                    <i class="fa fa-laptop mr-4"></i>Hardware Requirements</h4> | 
				
			||||
 | 
					                <p | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                    RAM : 16GB or Above | 
				
			||||
 | 
					                </p> | 
				
			||||
 | 
					                <p | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                    Graphics card : 4 GB additional | 
				
			||||
 | 
					                </p> | 
				
			||||
 | 
					                <p | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                    Processor : Intel i5 or above, AMD Ryzen 5 or above | 
				
			||||
 | 
					                </p> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6 pl-3 py-3 d-flex"> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <h4 | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                    <i class="fa fa-laptop mr-4"></i>Software Requirements</h4> | 
				
			||||
 | 
					                <p | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                    Web Browser capable of running WebGL: WebGL is a JavaScript | 
				
			||||
 | 
					                    API, or programmable interface, for | 
				
			||||
 | 
					                    drawing interactive 2D and 3D | 
				
			||||
 | 
					                    graphics in web pages. WebGL connects your web browser up to | 
				
			||||
 | 
					                    your device’s graphics | 
				
			||||
 | 
					                    card, providing you with far more graphical processing power | 
				
			||||
 | 
					                    than is available on a | 
				
			||||
 | 
					                    traditional website. | 
				
			||||
 | 
					                </p> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <div class="row" id="features"> | 
				
			||||
 | 
					        <div class="col-md-12" | 
				
			||||
 | 
					             style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important"> | 
				
			||||
 | 
					            <h2 | 
				
			||||
 | 
					                    style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> | 
				
			||||
 | 
					                <i class="fa fa-star mr-2"></i>Features | 
				
			||||
 | 
					            </h2> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6 pl-3 py-3 d-flex"> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <img src="assets/icons/check.png"> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <h4 | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                    Multiple Warehouse Selection</h4> | 
				
			||||
 | 
					                <p | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                    Users can view 3d visualization of all locations based | 
				
			||||
 | 
					                    multiple warehouses. | 
				
			||||
 | 
					                </p> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6 pl-3 py-3 d-flex"> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <img src="assets/icons/check.png"> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <h4 | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                    Location Specific 3D View</h4> | 
				
			||||
 | 
					                <p | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                    Users can view 3d visualization of individual locations as | 
				
			||||
 | 
					                    highlighted in the entire warehouse. | 
				
			||||
 | 
					                </p> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6 pl-3 py-3 d-flex"> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <img src="assets/icons/check.png"> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <h4 | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                    Actual Warehouse into Virtual Warehouse</h4> | 
				
			||||
 | 
					                <p | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                    Users can enter dimension and position of a Location. | 
				
			||||
 | 
					                </p> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6 pl-3 py-3 d-flex"> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <img src="assets/icons/check.png"> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <h4 | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                    Status of each Location</h4> | 
				
			||||
 | 
					                <p | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                    Users can quickly identify the status of location like free | 
				
			||||
 | 
					                    space/overloaded through their indexing | 
				
			||||
 | 
					                    based on their load and capacity. | 
				
			||||
 | 
					                </p> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-md-6 pl-3 py-3 d-flex"> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <img src="assets/icons/check.png"> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					            <div> | 
				
			||||
 | 
					                <h4 | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                    Current Stock of each Location</h4> | 
				
			||||
 | 
					                <p | 
				
			||||
 | 
					                        style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                    Users can easily get the data about current stock of each | 
				
			||||
 | 
					                    location by tapping twice on them. | 
				
			||||
 | 
					                </p> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <div class="row" id="screenshots"> | 
				
			||||
 | 
					        <div class="col-md-12" | 
				
			||||
 | 
					             style="border-bottom: 1px solid #d5d5d5 !important; margin: 2rem 0 !important"> | 
				
			||||
 | 
					            <h2 | 
				
			||||
 | 
					                    style="font-family: 'Montserrat', sans-serif !important; font-weight: 600 !important; color: #714B67 !important; font-size: 1.5rem !important;"> | 
				
			||||
 | 
					                <i class="fa fa-image mr-2"></i>Screenshots | 
				
			||||
 | 
					            </h2> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-lg-12 my-2"> | 
				
			||||
 | 
					            <h4 class="mt-2" | 
				
			||||
 | 
					                style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                Location Form View</h4> | 
				
			||||
 | 
					            <p | 
				
			||||
 | 
					                    style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                Enter the location properties such as location Code, Capacity, | 
				
			||||
 | 
					                Dimension and Position along X,Y and Z | 
				
			||||
 | 
					                axis. | 
				
			||||
 | 
					            </p> | 
				
			||||
 | 
					            <img src="assets/screenshots/1.png" | 
				
			||||
 | 
					                 class="img-responsive img-thumbnail border" width="100%" | 
				
			||||
 | 
					                 height="auto"/> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-lg-12 my-2"> | 
				
			||||
 | 
					            <h4 class="mt-2" | 
				
			||||
 | 
					                style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                3D View Based on Warehouses</h4> | 
				
			||||
 | 
					            <p | 
				
			||||
 | 
					                    style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                Click on the 3D button marked below to open 3D view based on | 
				
			||||
 | 
					                warehouses. | 
				
			||||
 | 
					            </p> | 
				
			||||
 | 
					            <img src="assets/screenshots/2.png" | 
				
			||||
 | 
					                 class="img-responsive img-thumbnail border" width="100%" | 
				
			||||
 | 
					                 height="auto"/> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-lg-12 my-2"> | 
				
			||||
 | 
					            <h4 class="mt-2" | 
				
			||||
 | 
					                style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                Multiple Warehouse Selection</h4> | 
				
			||||
 | 
					            <p | 
				
			||||
 | 
					                    style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                Users can switch to any warehouse by using the dropdown option | 
				
			||||
 | 
					                highlighted below. | 
				
			||||
 | 
					            </p> | 
				
			||||
 | 
					            <img src="assets/screenshots/3.png" | 
				
			||||
 | 
					                 class="img-responsive img-thumbnail border" width="100%" | 
				
			||||
 | 
					                 height="auto"/> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-lg-12 my-2"> | 
				
			||||
 | 
					            <h4 class="mt-2" | 
				
			||||
 | 
					                style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                Location Specific 3D View</h4> | 
				
			||||
 | 
					            <p | 
				
			||||
 | 
					                    style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                Please open a location and provide a proper dimension, position, | 
				
			||||
 | 
					                code and parent stock. Click on the | 
				
			||||
 | 
					                button "3D" located inside header. | 
				
			||||
 | 
					            </p> | 
				
			||||
 | 
					            <img src="assets/screenshots/4.png" | 
				
			||||
 | 
					                 class="img-responsive img-thumbnail border" width="100%" | 
				
			||||
 | 
					                 height="auto"/> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-lg-12 my-2"> | 
				
			||||
 | 
					            <h4 class="mt-2" | 
				
			||||
 | 
					                style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                Individual Location Highlight</h4> | 
				
			||||
 | 
					            <p | 
				
			||||
 | 
					                    style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                Users can view the selected location's 3D view individually. The | 
				
			||||
 | 
					                location is indexed based on its load | 
				
			||||
 | 
					                and capacity. | 
				
			||||
 | 
					            </p> | 
				
			||||
 | 
					            <img src="assets/screenshots/5.png" | 
				
			||||
 | 
					                 class="img-responsive img-thumbnail border" width="100%" | 
				
			||||
 | 
					                 height="auto"/> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <div class="col-lg-12 my-2"> | 
				
			||||
 | 
					            <h4 class="mt-2" | 
				
			||||
 | 
					                style="font-family: 'Roboto', sans-serif !important; font-weight: 600 !important; color: #282F33 !important; font-size: 1.3rem !important;"> | 
				
			||||
 | 
					                Get Stock Data</h4> | 
				
			||||
 | 
					            <p | 
				
			||||
 | 
					                    style="font-family: 'Roboto', sans-serif !important; font-weight: 400 !important; color: #282F33 !important; font-size: 1rem !important;"> | 
				
			||||
 | 
					                Double tap on the location to get its stock data. | 
				
			||||
 | 
					            </p> | 
				
			||||
 | 
					            <img src="assets/screenshots/66.png" | 
				
			||||
 | 
					                 class="img-responsive img-thumbnail border" width="100%" | 
				
			||||
 | 
					                 height="auto"/> | 
				
			||||
 | 
					            <br/> | 
				
			||||
 | 
					            <br/> | 
				
			||||
 | 
					            <img src="assets/screenshots/77.png" | 
				
			||||
 | 
					                 class="img-responsive img-thumbnail border" width="100%" | 
				
			||||
 | 
					                 height="auto"/> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <!-- SUGGESTED PRODUCTS --> | 
				
			||||
 | 
					    <div class="row"> | 
				
			||||
 | 
					        <div class="col-lg-12 d-flex flex-column justify-content-center" | 
				
			||||
 | 
					             style="text-align: center; padding: 2.5rem 1rem !important;"> | 
				
			||||
 | 
					            <h2 style="color: #212529 !important;">Suggested Products</h2> | 
				
			||||
 | 
					            <hr | 
				
			||||
 | 
					                    style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> | 
				
			||||
 | 
					            <div id="demo1" class="row carousel slide" data-ride="carousel"> | 
				
			||||
 | 
					                <!-- The slideshow --> | 
				
			||||
 | 
					                <div class="carousel-inner"> | 
				
			||||
 | 
					                    <div class="carousel-item active" style="min-height:0px"> | 
				
			||||
 | 
					                        <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | 
				
			||||
 | 
					                             style="float:left"> | 
				
			||||
 | 
					                            <a href="https://apps.odoo.com/apps/modules/15.0/export_stockinfo_xls/" | 
				
			||||
 | 
					                               target="_blank"> | 
				
			||||
 | 
					                                <div style="border-radius:10px"> | 
				
			||||
 | 
					                                    <img class="img img-responsive center-block" | 
				
			||||
 | 
					                                         style="border-top-left-radius:10px; border-top-right-radius:10px" | 
				
			||||
 | 
					                                         src="./assets/modules/module_1.png"> | 
				
			||||
 | 
					                                </div> | 
				
			||||
 | 
					                            </a> | 
				
			||||
 | 
					                        </div> | 
				
			||||
 | 
					                        <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | 
				
			||||
 | 
					                             style="float:left"> | 
				
			||||
 | 
					                            <a href="https://apps.odoo.com/apps/modules/15.0/stock_intercompany_transfer/" | 
				
			||||
 | 
					                               target="_blank"> | 
				
			||||
 | 
					                                <div style="border-radius:10px"> | 
				
			||||
 | 
					                                    <img class="img img-responsive center-block" | 
				
			||||
 | 
					                                         style="border-top-left-radius:10px; border-top-right-radius:10px" | 
				
			||||
 | 
					                                         src="./assets/modules/module_2.png"> | 
				
			||||
 | 
					                                </div> | 
				
			||||
 | 
					                            </a> | 
				
			||||
 | 
					                        </div> | 
				
			||||
 | 
					                        <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | 
				
			||||
 | 
					                             style="float:left"> | 
				
			||||
 | 
					                            <a href="https://apps.odoo.com/apps/modules/15.0/product_brand_inventory/" | 
				
			||||
 | 
					                               target="_blank"> | 
				
			||||
 | 
					                                <div style="border-radius:10px"> | 
				
			||||
 | 
					                                    <img class="img img-responsive center-block" | 
				
			||||
 | 
					                                         style="border-top-left-radius:10px; border-top-right-radius:10px" | 
				
			||||
 | 
					                                         src="./assets/modules/module_3.png"> | 
				
			||||
 | 
					                                </div> | 
				
			||||
 | 
					                            </a> | 
				
			||||
 | 
					                        </div> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                    <div class="carousel-item" style="min-height:0px"> | 
				
			||||
 | 
					                        <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | 
				
			||||
 | 
					                             style="float:left"> | 
				
			||||
 | 
					                            <a href="https://apps.odoo.com/apps/modules/15.0/product_batch_report/" | 
				
			||||
 | 
					                               target="_blank"> | 
				
			||||
 | 
					                                <div style="border-radius:10px"> | 
				
			||||
 | 
					                                    <img class="img img-responsive center-block" | 
				
			||||
 | 
					                                         style="border-top-left-radius:10px; border-top-right-radius:10px" | 
				
			||||
 | 
					                                         src="./assets/modules/module_4.png"> | 
				
			||||
 | 
					                                </div> | 
				
			||||
 | 
					                            </a> | 
				
			||||
 | 
					                        </div> | 
				
			||||
 | 
					                        <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | 
				
			||||
 | 
					                             style="float:left"> | 
				
			||||
 | 
					                            <a href="https://apps.odoo.com/apps/modules/15.0/merge_picking_orders/" | 
				
			||||
 | 
					                               target="_blank"> | 
				
			||||
 | 
					                                <div style="border-radius:10px"> | 
				
			||||
 | 
					                                    <img class="img img-responsive center-block" | 
				
			||||
 | 
					                                         style="border-top-left-radius:10px; border-top-right-radius:10px" | 
				
			||||
 | 
					                                         src="./assets/modules/module_5.png"> | 
				
			||||
 | 
					                                </div> | 
				
			||||
 | 
					                            </a> | 
				
			||||
 | 
					                        </div> | 
				
			||||
 | 
					                        <div class="col-xs-12 col-sm-4 col-md-4 mb16 mt16" | 
				
			||||
 | 
					                             style="float:left"> | 
				
			||||
 | 
					                            <a href="https://apps.odoo.com/apps/modules/15.0/stock_valuation_report/" | 
				
			||||
 | 
					                               target="_blank"> | 
				
			||||
 | 
					                                <div style="border-radius:10px"> | 
				
			||||
 | 
					                                    <img class="img img-responsive center-block" | 
				
			||||
 | 
					                                         style="border-top-left-radius:10px; border-top-right-radius:10px" | 
				
			||||
 | 
					                                         src="./assets/modules/module_6.png"> | 
				
			||||
 | 
					                                </div> | 
				
			||||
 | 
					                            </a> | 
				
			||||
 | 
					                        </div> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <!-- Left and right controls --> | 
				
			||||
 | 
					                <a class="carousel-control-prev" href="#demo1" data-slide="prev" | 
				
			||||
 | 
					                   style="left:-25px;width: 35px;color: #000;"> | 
				
			||||
 | 
					                    <span class="carousel-control-prev-icon"><i | 
				
			||||
 | 
					                            class="fa fa-chevron-left" | 
				
			||||
 | 
					                            style="font-size:24px"></i></span> | 
				
			||||
 | 
					                </a> | 
				
			||||
 | 
					                <a class="carousel-control-next" href="#demo1" data-slide="next" | 
				
			||||
 | 
					                   style="right:-25px;width: 35px;color: #000;"> | 
				
			||||
 | 
					                    <span class="carousel-control-next-icon"><i | 
				
			||||
 | 
					                            class="fa fa-chevron-right" | 
				
			||||
 | 
					                            style="font-size:24px"></i></span> | 
				
			||||
 | 
					                </a> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					    <!-- END OF SUGGESTED PRODUCTS --> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <!-- OUR SERVICES --> | 
				
			||||
 | 
					    <section class="container" style="margin-top: 6rem !important;"> | 
				
			||||
 | 
					        <div class="row"> | 
				
			||||
 | 
					            <div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> | 
				
			||||
 | 
					                <h2 style="color: #212529 !important;">Our Services</h2> | 
				
			||||
 | 
					                <hr | 
				
			||||
 | 
					                        style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | 
				
			||||
 | 
					                <div class="d-flex justify-content-center align-items-center mx-3 my-3" | 
				
			||||
 | 
					                     style="background-color: #1dd1a1 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | 
				
			||||
 | 
					                    <img src="assets/icons/cogs.png" class="img-responsive" | 
				
			||||
 | 
					                         height="48px" width="48px"> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <h6 class="text-center" | 
				
			||||
 | 
					                    style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | 
				
			||||
 | 
					                    Odoo Customization | 
				
			||||
 | 
					                </h6> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | 
				
			||||
 | 
					                <div class="d-flex justify-content-center align-items-center mx-3 my-3" | 
				
			||||
 | 
					                     style="background-color: #ff6b6b !important; border-radius: 15px !important; height: 80px; width: 80px;"> | 
				
			||||
 | 
					                    <img src="assets/icons/wrench.png" class="img-responsive" | 
				
			||||
 | 
					                         height="48px" width="48px"> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <h6 class="text-center" | 
				
			||||
 | 
					                    style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | 
				
			||||
 | 
					                    Odoo Implementation | 
				
			||||
 | 
					                </h6> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | 
				
			||||
 | 
					                <div class="d-flex justify-content-center align-items-center mx-3 my-3" | 
				
			||||
 | 
					                     style="background-color: #6462CD !important; border-radius: 15px !important; height: 80px; width: 80px;"> | 
				
			||||
 | 
					                    <img src="assets/icons/lifebuoy.png" class="img-responsive" | 
				
			||||
 | 
					                         height="48px" width="48px"> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <h6 class="text-center" | 
				
			||||
 | 
					                    style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | 
				
			||||
 | 
					                    Odoo Support | 
				
			||||
 | 
					                </h6> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | 
				
			||||
 | 
					                <div class="d-flex justify-content-center align-items-center mx-3 my-3" | 
				
			||||
 | 
					                     style="background-color: #ffa801 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | 
				
			||||
 | 
					                    <img src="assets/icons/user.png" class="img-responsive" | 
				
			||||
 | 
					                         height="48px" width="48px"> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <h6 class="text-center" | 
				
			||||
 | 
					                    style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | 
				
			||||
 | 
					                    Hire Odoo Developer | 
				
			||||
 | 
					                </h6> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | 
				
			||||
 | 
					                <div class="d-flex justify-content-center align-items-center mx-3 my-3" | 
				
			||||
 | 
					                     style="background-color: #54a0ff  !important; border-radius: 15px !important; height: 80px; width: 80px;"> | 
				
			||||
 | 
					                    <img src="assets/icons/puzzle.png" class="img-responsive" | 
				
			||||
 | 
					                         height="48px" width="48px"> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <h6 class="text-center" | 
				
			||||
 | 
					                    style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | 
				
			||||
 | 
					                    Odoo Integration | 
				
			||||
 | 
					                </h6> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | 
				
			||||
 | 
					                <div class="d-flex justify-content-center align-items-center mx-3 my-3" | 
				
			||||
 | 
					                     style="background-color: #6d7680 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | 
				
			||||
 | 
					                    <img src="assets/icons/update.png" class="img-responsive" | 
				
			||||
 | 
					                         height="48px" width="48px"> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <h6 class="text-center" | 
				
			||||
 | 
					                    style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | 
				
			||||
 | 
					                    Odoo Migration | 
				
			||||
 | 
					                </h6> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | 
				
			||||
 | 
					                <div class="d-flex justify-content-center align-items-center mx-3 my-3" | 
				
			||||
 | 
					                     style="background-color: #786fa6 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | 
				
			||||
 | 
					                    <img src="assets/icons/consultation.png" | 
				
			||||
 | 
					                         class="img-responsive" height="48px" width="48px"> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <h6 class="text-center" | 
				
			||||
 | 
					                    style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | 
				
			||||
 | 
					                    Odoo | 
				
			||||
 | 
					                    Consultancy | 
				
			||||
 | 
					                </h6> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | 
				
			||||
 | 
					                <div class="d-flex justify-content-center align-items-center mx-3 my-3" | 
				
			||||
 | 
					                     style="background-color: #f8a5c2 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | 
				
			||||
 | 
					                    <img src="assets/icons/training.png" class="img-responsive" | 
				
			||||
 | 
					                         height="48px" width="48px"> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <h6 class="text-center" | 
				
			||||
 | 
					                    style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | 
				
			||||
 | 
					                    Odoo Implementation | 
				
			||||
 | 
					                </h6> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-4 d-flex flex-column justify-content-center align-items-center my-4"> | 
				
			||||
 | 
					                <div class="d-flex justify-content-center align-items-center mx-3 my-3" | 
				
			||||
 | 
					                     style="background-color: #e6be26 !important; border-radius: 15px !important; height: 80px; width: 80px;"> | 
				
			||||
 | 
					                    <img src="assets/icons/license.png" class="img-responsive" | 
				
			||||
 | 
					                         height="48px" width="48px"> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <h6 class="text-center" | 
				
			||||
 | 
					                    style="font-family: Montserrat, 'sans-serif' !important; font-weight: bold;"> | 
				
			||||
 | 
					                    Odoo Licensing Consultancy | 
				
			||||
 | 
					                </h6> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </section> | 
				
			||||
 | 
					    <!-- END OF OUR SERVICES --> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <!-- OUR INDUSTRIES --> | 
				
			||||
 | 
					    <section class="container" style="margin-top: 6rem !important;"> | 
				
			||||
 | 
					        <div class="row"> | 
				
			||||
 | 
					            <div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> | 
				
			||||
 | 
					                <h2 style="color: #212529 !important;">Our Industries</h2> | 
				
			||||
 | 
					                <hr | 
				
			||||
 | 
					                        style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-3"> | 
				
			||||
 | 
					                <div class="my-4 d-flex flex-column justify-content-center" | 
				
			||||
 | 
					                     style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> | 
				
			||||
 | 
					                    <img src="./assets/icons/trading-black.png" | 
				
			||||
 | 
					                         class="img-responsive mb-3" height="48px" width="48px"> | 
				
			||||
 | 
					                    <h5 | 
				
			||||
 | 
					                            style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | 
				
			||||
 | 
					                        Trading | 
				
			||||
 | 
					                    </h5> | 
				
			||||
 | 
					                    <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                        Easily procure and sell your products | 
				
			||||
 | 
					                    </p> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-3"> | 
				
			||||
 | 
					                <div class="my-4 d-flex flex-column justify-content-center" | 
				
			||||
 | 
					                     style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> | 
				
			||||
 | 
					                    <img src="./assets/icons/pos-black.png" | 
				
			||||
 | 
					                         class="img-responsive mb-3" height="48px" width="48px"> | 
				
			||||
 | 
					                    <h5 | 
				
			||||
 | 
					                            style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | 
				
			||||
 | 
					                        POS | 
				
			||||
 | 
					                    </h5> | 
				
			||||
 | 
					                    <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                        Easy configuration and convivial experience | 
				
			||||
 | 
					                    </p> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-3"> | 
				
			||||
 | 
					                <div class="my-4 d-flex flex-column justify-content-center" | 
				
			||||
 | 
					                     style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> | 
				
			||||
 | 
					                    <img src="./assets/icons/education-black.png" | 
				
			||||
 | 
					                         class="img-responsive mb-3" height="48px" | 
				
			||||
 | 
					                         width="48px"> | 
				
			||||
 | 
					                    <h5 | 
				
			||||
 | 
					                            style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | 
				
			||||
 | 
					                        Education | 
				
			||||
 | 
					                    </h5> | 
				
			||||
 | 
					                    <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                        A platform for educational management | 
				
			||||
 | 
					                    </p> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-3"> | 
				
			||||
 | 
					                <div class="my-4 d-flex flex-column justify-content-center" | 
				
			||||
 | 
					                     style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> | 
				
			||||
 | 
					                    <img src="./assets/icons/manufacturing-black.png" | 
				
			||||
 | 
					                         class="img-responsive mb-3" height="48px" | 
				
			||||
 | 
					                         width="48px"> | 
				
			||||
 | 
					                    <h5 | 
				
			||||
 | 
					                            style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | 
				
			||||
 | 
					                        Manufacturing | 
				
			||||
 | 
					                    </h5> | 
				
			||||
 | 
					                    <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                        Plan, track and schedule your operations | 
				
			||||
 | 
					                    </p> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-3"> | 
				
			||||
 | 
					                <div class="my-4 d-flex flex-column justify-content-center" | 
				
			||||
 | 
					                     style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> | 
				
			||||
 | 
					                    <img src="./assets/icons/ecom-black.png" | 
				
			||||
 | 
					                         class="img-responsive mb-3" height="48px" width="48px"> | 
				
			||||
 | 
					                    <h5 | 
				
			||||
 | 
					                            style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | 
				
			||||
 | 
					                        E-commerce & Website | 
				
			||||
 | 
					                    </h5> | 
				
			||||
 | 
					                    <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                        Mobile friendly, awe-inspiring product pages | 
				
			||||
 | 
					                    </p> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-3"> | 
				
			||||
 | 
					                <div class="my-4 d-flex flex-column justify-content-center" | 
				
			||||
 | 
					                     style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> | 
				
			||||
 | 
					                    <img src="./assets/icons/service-black.png" | 
				
			||||
 | 
					                         class="img-responsive mb-3" height="48px" width="48px"> | 
				
			||||
 | 
					                    <h5 | 
				
			||||
 | 
					                            style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | 
				
			||||
 | 
					                        Service Management | 
				
			||||
 | 
					                    </h5> | 
				
			||||
 | 
					                    <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                        Keep track of services and invoice | 
				
			||||
 | 
					                    </p> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-3"> | 
				
			||||
 | 
					                <div class="my-4 d-flex flex-column justify-content-center" | 
				
			||||
 | 
					                     style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> | 
				
			||||
 | 
					                    <img src="./assets/icons/restaurant-black.png" | 
				
			||||
 | 
					                         class="img-responsive mb-3" height="48px" | 
				
			||||
 | 
					                         width="48px"> | 
				
			||||
 | 
					                    <h5 | 
				
			||||
 | 
					                            style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | 
				
			||||
 | 
					                        Restaurant | 
				
			||||
 | 
					                    </h5> | 
				
			||||
 | 
					                    <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                        Run your bar or restaurant methodically | 
				
			||||
 | 
					                    </p> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-3"> | 
				
			||||
 | 
					                <div class="my-4 d-flex flex-column justify-content-center" | 
				
			||||
 | 
					                     style="background-color: #f6f8f9 !important; border-radius: 10px; padding: 2rem !important; height: 250px !important;"> | 
				
			||||
 | 
					                    <img src="./assets/icons/hotel-black.png" | 
				
			||||
 | 
					                         class="img-responsive mb-3" height="48px" width="48px"> | 
				
			||||
 | 
					                    <h5 | 
				
			||||
 | 
					                            style="font-family: Montserrat, sans-serif !important; color: #000 !important; font-weight: bold;"> | 
				
			||||
 | 
					                        Hotel Management | 
				
			||||
 | 
					                    </h5> | 
				
			||||
 | 
					                    <p style="font-family: Montserrat, sans-serif !important; font-size: 0.9rem !important;"> | 
				
			||||
 | 
					                        An all-inclusive hotel management application | 
				
			||||
 | 
					                    </p> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </section> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <!-- END OF OUR INDUSTRIES --> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					    <!-- FOOTER --> | 
				
			||||
 | 
					    <!-- Footer Section --> | 
				
			||||
 | 
					    <section class="container" style="margin: 5rem auto 2rem;"> | 
				
			||||
 | 
					        <div class="row" style="max-width:1540px;"> | 
				
			||||
 | 
					            <div class="col-lg-12 d-flex flex-column justify-content-center align-items-center"> | 
				
			||||
 | 
					                <h2 style="color: #212529 !important;">Need Help?</h2> | 
				
			||||
 | 
					                <hr | 
				
			||||
 | 
					                        style="border: 3px solid #714B67 !important; background-color: #714B67 !important; width: 80px !important; margin-bottom: 2rem !important;"/> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        <!-- Contact Cards --> | 
				
			||||
 | 
					        <div class="row d-flex justify-content-center align-items-center" | 
				
			||||
 | 
					             style="max-width:1540px; margin: 0 auto 2rem auto;"> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					            <div class="col-lg-12" | 
				
			||||
 | 
					                 style="padding: 0rem 3rem 2rem; border-radius: 10px; margin-right: 3rem; "> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					                <div class="row mt-4"> | 
				
			||||
 | 
					                    <div class="col-lg-6"> | 
				
			||||
 | 
					                        <a href="mailto:odoo@cybrosys.com" target="_blank" | 
				
			||||
 | 
					                           class="btn btn-block mb-2 deep_hover" | 
				
			||||
 | 
					                           style="text-decoration: none;  background-color: #4d4d4d; color: #FFF;  border-radius: 4px;"> | 
				
			||||
 | 
					                            <i class="fa fa-envelope mr-2"></i>odoo@cybrosys.com | 
				
			||||
 | 
					                        </a> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                    <div class="col-lg-6"> | 
				
			||||
 | 
					                        <a href="https://api.whatsapp.com/send?phone=918606827707" | 
				
			||||
 | 
					                           target="_blank" | 
				
			||||
 | 
					                           class="btn btn-block mb-2 deep_hover" | 
				
			||||
 | 
					                           style="text-decoration: none;  background-color: #25D366; color: #FFF;  border-radius: 4px;"> | 
				
			||||
 | 
					                            <i class="fa fa-whatsapp mr-2"></i>WhatsApp | 
				
			||||
 | 
					                        </a> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					        <!-- End of Contact Cards --> | 
				
			||||
 | 
					    </section> | 
				
			||||
 | 
					    <!-- Footer --> | 
				
			||||
 | 
					    <section class="oe_container" style="padding: 2rem 3rem 1rem;"> | 
				
			||||
 | 
					        <div class="row" | 
				
			||||
 | 
					             style="max-width:1540px; margin: 0 auto; margin-right: 3rem; "> | 
				
			||||
 | 
					            <!-- Logo --> | 
				
			||||
 | 
					            <div class="col-lg-12 d-flex justify-content-center align-items-center" | 
				
			||||
 | 
					                 style="margin-top: 3rem;"> | 
				
			||||
 | 
					                <img src="https://www.cybrosys.com/images/logo.png" | 
				
			||||
 | 
					                     width="200px" height="auto"/> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					            <!-- End of Logo --> | 
				
			||||
 | 
					            <div class="col-lg-12"> | 
				
			||||
 | 
					                <hr | 
				
			||||
 | 
					                        style="margin-top: 3rem;background: linear-gradient(90deg, rgba(2,0,36,0) 0%, rgba(229,229,229,1) 33%, rgba(229,229,229,1) 58%, rgba(0,212,255,0) 100%); height: 2px; border-style: none;"> | 
				
			||||
 | 
					                <!-- End of Footer Section --> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </section> | 
				
			||||
 | 
					    <!-- END OF FOOTER --> | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					</div> | 
				
			||||
@ -0,0 +1,125 @@ | 
				
			|||||
 | 
					canvas { | 
				
			||||
 | 
					  border: 7px solid #666666; | 
				
			||||
 | 
					  background-color: white; | 
				
			||||
 | 
					  position: relative; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.customselect{ | 
				
			||||
 | 
					bottom: 744px; | 
				
			||||
 | 
					left: 44px; | 
				
			||||
 | 
					height: 25px; | 
				
			||||
 | 
					width: 150px; | 
				
			||||
 | 
					position: absolute; | 
				
			||||
 | 
					color: indigo; | 
				
			||||
 | 
					font-size: 15px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.rectangle { | 
				
			||||
 | 
					bottom: 650px; | 
				
			||||
 | 
					right: 7px; | 
				
			||||
 | 
					  height: 140px; | 
				
			||||
 | 
					  width: 180px; | 
				
			||||
 | 
					  position: absolute; | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.square1 { | 
				
			||||
 | 
					  height: 20px; | 
				
			||||
 | 
					  width: 20px; | 
				
			||||
 | 
					  background-color: #cc0000; | 
				
			||||
 | 
					  border-radius: 5px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.squareText1 { | 
				
			||||
 | 
					  height: 20px; | 
				
			||||
 | 
					  width: 170px; | 
				
			||||
 | 
					  color: black; | 
				
			||||
 | 
					  margin-top: -19px; | 
				
			||||
 | 
					  padding-left: 30px; | 
				
			||||
 | 
					  font-weight: 600; | 
				
			||||
 | 
					  font-size: 13px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.square2 { | 
				
			||||
 | 
					  height: 20px; | 
				
			||||
 | 
					  width: 20px; | 
				
			||||
 | 
					  background-color: #e6b800; | 
				
			||||
 | 
					  border-radius: 5px; | 
				
			||||
 | 
					  margin-top: 2px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.squareText2 { | 
				
			||||
 | 
					  height: 20px; | 
				
			||||
 | 
					  width: 170px; | 
				
			||||
 | 
					  color: black; | 
				
			||||
 | 
					  margin-top: -19px; | 
				
			||||
 | 
					  padding-left: 30px; | 
				
			||||
 | 
					  font-weight: 600; | 
				
			||||
 | 
					  font-size: 13px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.square3 { | 
				
			||||
 | 
					  height: 20px; | 
				
			||||
 | 
					  width: 20px; | 
				
			||||
 | 
					  background-color: #00802b; | 
				
			||||
 | 
					  border-radius: 5px; | 
				
			||||
 | 
					  margin-top: 2px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.squareText3 { | 
				
			||||
 | 
					  height: 20px; | 
				
			||||
 | 
					  width: 170px; | 
				
			||||
 | 
					  color: black; | 
				
			||||
 | 
					  margin-top: -19px; | 
				
			||||
 | 
					  padding-left: 30px; | 
				
			||||
 | 
					  font-weight: 600; | 
				
			||||
 | 
					  font-size: 13px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.square4 { | 
				
			||||
 | 
					  height: 20px; | 
				
			||||
 | 
					  width: 20px; | 
				
			||||
 | 
					  background-color: #8c8c8c; | 
				
			||||
 | 
					  border-radius: 5px; | 
				
			||||
 | 
					  margin-top: 2px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.square4blue { | 
				
			||||
 | 
					  height: 20px; | 
				
			||||
 | 
					  width: 20px; | 
				
			||||
 | 
					  background-color: #0066ff; | 
				
			||||
 | 
					  border-radius: 5px; | 
				
			||||
 | 
					  margin-top: 2px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.squareText4 { | 
				
			||||
 | 
					  height: 20px; | 
				
			||||
 | 
					  width: 170px; | 
				
			||||
 | 
					  color: black; | 
				
			||||
 | 
					  margin-top: -19px; | 
				
			||||
 | 
					  padding-left: 30px; | 
				
			||||
 | 
					  font-weight: 600; | 
				
			||||
 | 
					  font-size: 13px; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.closeBtn { | 
				
			||||
 | 
					    bottom: 759px; | 
				
			||||
 | 
					    left: 10px; | 
				
			||||
 | 
					  font-size: 33px; | 
				
			||||
 | 
					  font-weight: 600; | 
				
			||||
 | 
					  position: absolute; | 
				
			||||
 | 
					  color: indigo; | 
				
			||||
 | 
					  background: transparent; | 
				
			||||
 | 
					  border: none; | 
				
			||||
 | 
					   outline: none; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.closeBtn:focus { | 
				
			||||
 | 
					    outline: 0 !important; | 
				
			||||
 | 
					} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
					.closeBtn:hover { | 
				
			||||
 | 
					  animation: pulse 1s; | 
				
			||||
 | 
					  box-shadow: 0 0 0 2em rgba(#fff,0); | 
				
			||||
 | 
					} | 
				
			||||
@ -0,0 +1,387 @@ | 
				
			|||||
 | 
					odoo.define('stock_3d_view.action_open_form_3d_view', function(require) { | 
				
			||||
 | 
						'use strict'; | 
				
			||||
 | 
						var AbstractAction = require('web.AbstractAction'); | 
				
			||||
 | 
						var core = require('web.core'); | 
				
			||||
 | 
						var rpc = require('web.rpc'); | 
				
			||||
 | 
						var QWeb = core.qweb; | 
				
			||||
 | 
						var Dialog = require('web.Dialog'); | 
				
			||||
 | 
						var ajax = require('web.ajax'); | 
				
			||||
 | 
						var PositionDialog = Dialog.extend({ | 
				
			||||
 | 
							/** | 
				
			||||
 | 
							 * Initializes the PositionDialog instance. | 
				
			||||
 | 
							 * | 
				
			||||
 | 
							 * @constructor | 
				
			||||
 | 
							 * @param {Object} parent - The parent object. | 
				
			||||
 | 
							 * @param {Object} options - Configuration options. | 
				
			||||
 | 
							 * @param {Object} options.pointer - The pointer object. | 
				
			||||
 | 
							 * @param {Function} options.close - Callback function for closing the dialog. | 
				
			||||
 | 
							 */ | 
				
			||||
 | 
							init: function(parent, options) { | 
				
			||||
 | 
								var opt = options; | 
				
			||||
 | 
								this._super(...arguments) | 
				
			||||
 | 
								this.pointer = opt.pointer | 
				
			||||
 | 
								this.onClickClose = opt.close | 
				
			||||
 | 
							}, | 
				
			||||
 | 
							/** | 
				
			||||
 | 
							 * Renders the element and sets its position. | 
				
			||||
 | 
							 * | 
				
			||||
 | 
							 */ | 
				
			||||
 | 
							renderElement: function() { | 
				
			||||
 | 
								this._super() | 
				
			||||
 | 
								this.$modal.find('.modal-dialog').css({ | 
				
			||||
 | 
									position: 'absolute', | 
				
			||||
 | 
									left: this.pointer.x, | 
				
			||||
 | 
									top: this.pointer.y, | 
				
			||||
 | 
								}) | 
				
			||||
 | 
							} | 
				
			||||
 | 
						}) | 
				
			||||
 | 
						//Extends abstract action class to add event listener for 3D button.
 | 
				
			||||
 | 
						var open_form_3d_view = AbstractAction.extend({ | 
				
			||||
 | 
							template: 'Location3DFormView', | 
				
			||||
 | 
							events: _.extend({}, AbstractAction.prototype.events, { | 
				
			||||
 | 
								'click .breadcrumb-item a': 'onBreadcrumbClick' | 
				
			||||
 | 
							}), | 
				
			||||
 | 
							/** | 
				
			||||
 | 
							 * Handles the click event on breadcrumbs. | 
				
			||||
 | 
							 * | 
				
			||||
 | 
							 * @param {Event} ev - The click event object. | 
				
			||||
 | 
							 */ | 
				
			||||
 | 
							onBreadcrumbClick: function(ev) { | 
				
			||||
 | 
								let jsId = this.$(ev.target).attr('jsId'); | 
				
			||||
 | 
								this.actionService.restore(jsId); | 
				
			||||
 | 
							}, | 
				
			||||
 | 
							/** | 
				
			||||
 | 
							 * Initializes the open_form_3d_view instance. | 
				
			||||
 | 
							 * | 
				
			||||
 | 
							 * @constructor | 
				
			||||
 | 
							 * @param {Object} parent - The parent object. | 
				
			||||
 | 
							 * @param {Object} action - The action configuration. | 
				
			||||
 | 
							 */ | 
				
			||||
 | 
							init: function(parent, action) { | 
				
			||||
 | 
								this._super(...arguments) | 
				
			||||
 | 
								this.breadcrumbs = parent.wowlEnv.config.breadcrumbs | 
				
			||||
 | 
								this.actionService = parent.actionService; | 
				
			||||
 | 
							}, | 
				
			||||
 | 
							/** | 
				
			||||
 | 
							 * Starts the open_form_3d_view action. | 
				
			||||
 | 
							 */ | 
				
			||||
 | 
							start: function() { | 
				
			||||
 | 
								this.Open3DView(); | 
				
			||||
 | 
							}, | 
				
			||||
 | 
							/** | 
				
			||||
 | 
							 * Starts the process of displaying rendered 3D object of stock.location. | 
				
			||||
 | 
							 */ | 
				
			||||
 | 
							Open3DView: function() { | 
				
			||||
 | 
								var self = this; | 
				
			||||
 | 
								var wh_data; | 
				
			||||
 | 
								var data; | 
				
			||||
 | 
								var loc_quant; | 
				
			||||
 | 
								let controls, renderer, clock, scene, camera, pointer, raycaster; | 
				
			||||
 | 
								var mesh, group; | 
				
			||||
 | 
								var material; | 
				
			||||
 | 
								var loc_color; | 
				
			||||
 | 
								var loc_opacity = 0.5; | 
				
			||||
 | 
								var textSize; | 
				
			||||
 | 
								let selectedObject = null; | 
				
			||||
 | 
								var dialogs = null; | 
				
			||||
 | 
								var wh_id; | 
				
			||||
 | 
								var location_id = self.searchModel.config.context.loc_id || localStorage.getItem("location_id"); | 
				
			||||
 | 
								//sets location_id and company_id in local storage
 | 
				
			||||
 | 
								if (self.searchModel.config.context.loc_id != null) { | 
				
			||||
 | 
									localStorage.setItem("location_id", self.searchModel.config.context.loc_id); | 
				
			||||
 | 
									localStorage.setItem("company_id", self.searchModel.config.context.company_id); | 
				
			||||
 | 
								} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								var colorDiv = document.createElement("div"); | 
				
			||||
 | 
								colorDiv.classList.add("rectangle"); | 
				
			||||
 | 
								var color1 = document.createElement("div"); | 
				
			||||
 | 
								color1.classList.add("square1"); | 
				
			||||
 | 
								colorDiv.appendChild(color1); | 
				
			||||
 | 
								var colorText1 = document.createElement("div"); | 
				
			||||
 | 
								colorText1.classList.add("squareText1"); | 
				
			||||
 | 
								colorText1.innerHTML = "Overload"; | 
				
			||||
 | 
								colorDiv.appendChild(colorText1); | 
				
			||||
 | 
								var color2 = document.createElement("div"); | 
				
			||||
 | 
								color2.classList.add("square2"); | 
				
			||||
 | 
								colorDiv.appendChild(color2); | 
				
			||||
 | 
								var colorText2 = document.createElement("div"); | 
				
			||||
 | 
								colorText2.classList.add("squareText2"); | 
				
			||||
 | 
								colorText2.innerHTML = "Almost Full"; | 
				
			||||
 | 
								colorDiv.appendChild(colorText2); | 
				
			||||
 | 
								var color3 = document.createElement("div"); | 
				
			||||
 | 
								color3.classList.add("square3"); | 
				
			||||
 | 
								colorDiv.appendChild(color3); | 
				
			||||
 | 
								var colorText3 = document.createElement("div"); | 
				
			||||
 | 
								colorText3.classList.add("squareText3"); | 
				
			||||
 | 
								colorText3.innerHTML = "Free Space Available"; | 
				
			||||
 | 
								colorDiv.appendChild(colorText3); | 
				
			||||
 | 
								var color4 = document.createElement("div"); | 
				
			||||
 | 
								color4.classList.add("square4blue"); | 
				
			||||
 | 
								colorDiv.appendChild(color4); | 
				
			||||
 | 
								var colorText4 = document.createElement("div"); | 
				
			||||
 | 
								colorText4.classList.add("squareText4"); | 
				
			||||
 | 
								colorText4.innerHTML = "No Product/Load"; | 
				
			||||
 | 
								colorDiv.appendChild(colorText4); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								start(); | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * The complete working of fetching data from stock.location and displaying them in the form of 3d objects. | 
				
			||||
 | 
								 * | 
				
			||||
 | 
								 * @async | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								async function start() { | 
				
			||||
 | 
									/** | 
				
			||||
 | 
									 * Make a jsonRpc call to fetch location details. | 
				
			||||
 | 
									 * | 
				
			||||
 | 
									 * @await | 
				
			||||
 | 
									 * @param {integer} company_id | 
				
			||||
 | 
									 * @param {integer} loc_id | 
				
			||||
 | 
									 */ | 
				
			||||
 | 
									await ajax.jsonRpc('/3Dstock/data/standalone', 'call', { | 
				
			||||
 | 
										'company_id': self.searchModel.config.context.company_id || localStorage.getItem("company_id"), | 
				
			||||
 | 
										'loc_id': self.searchModel.config.context.loc_id || localStorage.getItem("location_id"), | 
				
			||||
 | 
									}).then(function(incoming_data) { | 
				
			||||
 | 
										data = incoming_data; | 
				
			||||
 | 
									}); | 
				
			||||
 | 
									//creating a new three.scene
 | 
				
			||||
 | 
									scene = new THREE.Scene(); | 
				
			||||
 | 
									scene.background = new THREE.Color(0xdfdfdf); | 
				
			||||
 | 
									clock = new THREE.Clock(); | 
				
			||||
 | 
									camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.5, 6000); | 
				
			||||
 | 
									camera.position.set(0, 200, 300) | 
				
			||||
 | 
									renderer = new THREE.WebGLRenderer({ | 
				
			||||
 | 
										antialias: true | 
				
			||||
 | 
									}); | 
				
			||||
 | 
									//setting size and pixel ratio for the renderer.
 | 
				
			||||
 | 
									renderer.setSize(window.innerWidth, window.innerHeight / 1.163); | 
				
			||||
 | 
									renderer.setPixelRatio(window.devicePixelRatio); | 
				
			||||
 | 
									renderer.render(scene, camera); | 
				
			||||
 | 
									var o_content = self.$('.o_content') | 
				
			||||
 | 
									o_content.append(renderer.domElement); | 
				
			||||
 | 
									self.$el.find('.o_content').append(colorDiv); | 
				
			||||
 | 
									controls = new THREE.OrbitControls(camera, renderer.domElement); | 
				
			||||
 | 
									const baseGeometry = new THREE.BoxGeometry(800, 0, 800); | 
				
			||||
 | 
									const baseMaterial = new THREE.MeshBasicMaterial({ | 
				
			||||
 | 
										color: 0xffffff, | 
				
			||||
 | 
										transparent: false, | 
				
			||||
 | 
										opacity: 1, | 
				
			||||
 | 
										side: THREE.FrontSide, | 
				
			||||
 | 
									}); | 
				
			||||
 | 
									const baseCube = new THREE.Mesh(baseGeometry, baseMaterial); | 
				
			||||
 | 
									scene.add(baseCube); | 
				
			||||
 | 
									group = new THREE.Group(); | 
				
			||||
 | 
									//traversing through each location object
 | 
				
			||||
 | 
									for (let [key, value] of Object.entries(data)) { | 
				
			||||
 | 
										//checks if the dimension values of the location are non zero
 | 
				
			||||
 | 
										if ((value[0] > 0) || (value[1] > 0) || (value[2] > 0) || (value[3] > 0) || (value[4] > 0) || (value[5] > 0)) { | 
				
			||||
 | 
											const geometry = new THREE.BoxGeometry(value[3], value[5], value[4]); | 
				
			||||
 | 
											geometry.translate(0, (value[5] / 2), 0); | 
				
			||||
 | 
											const edges = new THREE.EdgesGeometry(geometry); | 
				
			||||
 | 
											/** | 
				
			||||
 | 
											 * Make a jsonRpc call to fetch the stock details of particular location. | 
				
			||||
 | 
											 * | 
				
			||||
 | 
											 * @await | 
				
			||||
 | 
											 * @param {integer} loc_code | 
				
			||||
 | 
											 */ | 
				
			||||
 | 
											await ajax.jsonRpc('/3Dstock/data/quantity', 'call', { | 
				
			||||
 | 
												'loc_code': key, | 
				
			||||
 | 
											}).then(function(quant_data) { | 
				
			||||
 | 
												loc_quant = quant_data; | 
				
			||||
 | 
											}); | 
				
			||||
 | 
											//checking the quantity and capacity of the location to determine the color of the location
 | 
				
			||||
 | 
											if (localStorage.getItem("location_id") == value[6]) { | 
				
			||||
 | 
												if (loc_quant[0] > 0) { | 
				
			||||
 | 
													if (loc_quant[1] > 100) { | 
				
			||||
 | 
														loc_color = 0xcc0000; | 
				
			||||
 | 
														loc_opacity = 0.8; | 
				
			||||
 | 
													} else if (loc_quant[1] > 50) { | 
				
			||||
 | 
														loc_color = 0xe6b800; | 
				
			||||
 | 
														loc_opacity = 0.8; | 
				
			||||
 | 
													} else { | 
				
			||||
 | 
														loc_color = 0x00802b; | 
				
			||||
 | 
														loc_opacity = 0.8; | 
				
			||||
 | 
													} | 
				
			||||
 | 
												} else { | 
				
			||||
 | 
													if (loc_quant[1] == -1) { | 
				
			||||
 | 
														loc_color = 0x00802b; | 
				
			||||
 | 
														loc_opacity = 0.8; | 
				
			||||
 | 
													} else { | 
				
			||||
 | 
														loc_color = 0x0066ff; | 
				
			||||
 | 
														loc_opacity = 0.8; | 
				
			||||
 | 
													} | 
				
			||||
 | 
												} | 
				
			||||
 | 
											} else { | 
				
			||||
 | 
												loc_color = 0x8c8c8c; | 
				
			||||
 | 
												loc_opacity = 0.5; | 
				
			||||
 | 
											} | 
				
			||||
 | 
											//creating a 3D box geometry for each location
 | 
				
			||||
 | 
											material = new THREE.MeshBasicMaterial({ | 
				
			||||
 | 
												color: loc_color, | 
				
			||||
 | 
												transparent: true, | 
				
			||||
 | 
												opacity: loc_opacity | 
				
			||||
 | 
											}); | 
				
			||||
 | 
											mesh = new THREE.Mesh(geometry, material); | 
				
			||||
 | 
											const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ | 
				
			||||
 | 
												color: 0x404040 | 
				
			||||
 | 
											})); | 
				
			||||
 | 
											line.position.x = value[0]; | 
				
			||||
 | 
											line.position.y = value[1]; | 
				
			||||
 | 
											line.position.z = value[2]; | 
				
			||||
 | 
											mesh.position.x = value[0]; | 
				
			||||
 | 
											mesh.position.y = value[1]; | 
				
			||||
 | 
											mesh.position.z = value[2]; | 
				
			||||
 | 
											const loader = new THREE.FontLoader(); | 
				
			||||
 | 
											loader.load('https://threejs.org/examples/fonts/droid/droid_sans_bold.typeface.json', function(font) { | 
				
			||||
 | 
												const textcolor = 0x000000; | 
				
			||||
 | 
												const textMat = new THREE.MeshBasicMaterial({ | 
				
			||||
 | 
													color: textcolor, | 
				
			||||
 | 
													side: THREE.DoubleSide, | 
				
			||||
 | 
												}); | 
				
			||||
 | 
												const textmessage = key; | 
				
			||||
 | 
												if (value[3] > value[4]) { | 
				
			||||
 | 
													textSize = (value[4] / 2) - (value[4] / 2.9); | 
				
			||||
 | 
												} else { | 
				
			||||
 | 
													textSize = (value[3] / 2) - (value[3] / 2.9); | 
				
			||||
 | 
												} | 
				
			||||
 | 
												const textshapes = font.generateShapes(textmessage, textSize); | 
				
			||||
 | 
												const textgeometry = new THREE.ShapeGeometry(textshapes); | 
				
			||||
 | 
												textgeometry.translate(0, ((value[5] / 2) - (textSize / (textSize - 1.5))), 0); | 
				
			||||
 | 
												const text = new THREE.Mesh(textgeometry, textMat); | 
				
			||||
 | 
												if (value[4] > value[3]) { | 
				
			||||
 | 
													text.rotation.y = Math.PI / 2; | 
				
			||||
 | 
													text.position.x = value[0]; | 
				
			||||
 | 
													text.position.y = value[1]; | 
				
			||||
 | 
													text.position.z = value[2] + (textSize * 2) + ((value[3] / 3.779 / 2) / 2) + (textSize / 2); | 
				
			||||
 | 
												} else { | 
				
			||||
 | 
													text.position.x = value[0] - (textSize * 2) - ((value[4] / 3.779 / 2) / 2) - (textSize / 2); | 
				
			||||
 | 
													text.position.y = value[1]; | 
				
			||||
 | 
													text.position.z = value[2]; | 
				
			||||
 | 
												} | 
				
			||||
 | 
												scene.add(text); | 
				
			||||
 | 
											}); | 
				
			||||
 | 
											scene.add(mesh); | 
				
			||||
 | 
											scene.add(line); | 
				
			||||
 | 
											mesh.name = key; | 
				
			||||
 | 
											mesh.userData = { | 
				
			||||
 | 
												color: loc_color, | 
				
			||||
 | 
												loc_id: value[6], | 
				
			||||
 | 
											}; | 
				
			||||
 | 
											group.add(mesh); | 
				
			||||
 | 
										} | 
				
			||||
 | 
									} | 
				
			||||
 | 
									scene.add(group); | 
				
			||||
 | 
									raycaster = new THREE.Raycaster(); | 
				
			||||
 | 
									pointer = new THREE.Vector3(); | 
				
			||||
 | 
									animate(); | 
				
			||||
 | 
								} | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * Handles the resizing and setting the pixel ration on window resize. | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								function onWindowResize() { | 
				
			||||
 | 
									camera.aspect = window.innerWidth / window.innerHeight; | 
				
			||||
 | 
									camera.updateProjectionMatrix(); | 
				
			||||
 | 
									renderer.setSize(window.innerWidth, window.innerHeight / 1.163); | 
				
			||||
 | 
								} | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * Animates and renders the three.renderer object to make changes on the scene. | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								function animate() { | 
				
			||||
 | 
									requestAnimationFrame(animate); | 
				
			||||
 | 
									const delta = clock.getDelta(); | 
				
			||||
 | 
									renderer.render(scene, camera); | 
				
			||||
 | 
									var canvas = document.getElementsByTagName("canvas")[0]; | 
				
			||||
 | 
									var colorBox = document.querySelector(".rectangle"); | 
				
			||||
 | 
									//checking the canvas element adding event listener on canvas.
 | 
				
			||||
 | 
									if (canvas == null) { | 
				
			||||
 | 
										window.removeEventListener('dblclick', onPointerMove); | 
				
			||||
 | 
										window.removeEventListener('resize', onWindowResize); | 
				
			||||
 | 
										if (colorBox) { | 
				
			||||
 | 
											colorBox.style.display = "none"; | 
				
			||||
 | 
										} | 
				
			||||
 | 
									} else { | 
				
			||||
 | 
										window.addEventListener('dblclick', onPointerMove); | 
				
			||||
 | 
										window.addEventListener('resize', onWindowResize); | 
				
			||||
 | 
										if (colorBox) { | 
				
			||||
 | 
											colorBox.style.display = "block"; | 
				
			||||
 | 
										} | 
				
			||||
 | 
									} | 
				
			||||
 | 
								} | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * gets the coordinates of the mouse point and checks for any objects. | 
				
			||||
 | 
								 * | 
				
			||||
 | 
								 * @async | 
				
			||||
 | 
								 * @param {object} event | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								async function onPointerMove(event) { | 
				
			||||
 | 
									var products; | 
				
			||||
 | 
									var button; | 
				
			||||
 | 
									if (dialogs == null) { | 
				
			||||
 | 
										if (selectedObject) { | 
				
			||||
 | 
											selectedObject.material.color.set(selectedObject.userData.color); | 
				
			||||
 | 
											selectedObject = null; | 
				
			||||
 | 
										} else { | 
				
			||||
 | 
											pointer.x = (event.clientX / window.innerWidth) * 2 - 1; | 
				
			||||
 | 
											pointer.y = -(event.clientY / (window.innerHeight)) * 2 + 1 + 0.13; | 
				
			||||
 | 
											raycaster.setFromCamera(pointer, camera); | 
				
			||||
 | 
											const intersects = raycaster.intersectObject(group, true); | 
				
			||||
 | 
											if (intersects.length > 0) { | 
				
			||||
 | 
												const res = intersects.filter(function(res) { | 
				
			||||
 | 
													return res && res.object; | 
				
			||||
 | 
												})[0]; | 
				
			||||
 | 
												if (res && res.object) { | 
				
			||||
 | 
													if (res.object.userData.loc_id == location_id) { | 
				
			||||
 | 
														/** | 
				
			||||
 | 
														 * Make a jsonRpc call to fetch the details of products and their quantity of selected location. | 
				
			||||
 | 
														 * | 
				
			||||
 | 
														 * @await | 
				
			||||
 | 
														 * @param {integer} loc_code | 
				
			||||
 | 
														 */ | 
				
			||||
 | 
														await ajax.jsonRpc('/3Dstock/data/product', 'call', { | 
				
			||||
 | 
															'loc_code': res.object.name, | 
				
			||||
 | 
														}).then(function(product_data) { | 
				
			||||
 | 
															products = product_data; | 
				
			||||
 | 
														}); | 
				
			||||
 | 
														selectedObject = res.object; | 
				
			||||
 | 
														selectedObject.material.color.set(0x00ffcc); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
														function onClickClose() { | 
				
			||||
 | 
															if (selectedObject) { | 
				
			||||
 | 
																selectedObject.material.color.set(selectedObject.userData.color); | 
				
			||||
 | 
																selectedObject = null; | 
				
			||||
 | 
																dialogs.close(); | 
				
			||||
 | 
																dialogs = null; | 
				
			||||
 | 
															} | 
				
			||||
 | 
														} | 
				
			||||
 | 
														//opens a new dialogbox with proeduct and quantity details
 | 
				
			||||
 | 
														dialogs = new PositionDialog(this, { | 
				
			||||
 | 
															title: ('Location: ' + res.object.name), | 
				
			||||
 | 
															size: 'small', | 
				
			||||
 | 
															$content: $(QWeb.render('ViewLocationData', { | 
				
			||||
 | 
																data: products, | 
				
			||||
 | 
															})), | 
				
			||||
 | 
															placement: 'bottom', | 
				
			||||
 | 
															renderFooter: false, | 
				
			||||
 | 
															pointer: { | 
				
			||||
 | 
																x: event.clientX, | 
				
			||||
 | 
																y: event.clientY, | 
				
			||||
 | 
															}, | 
				
			||||
 | 
															close: onClickClose, | 
				
			||||
 | 
														}).open(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
														if (dialogs) { | 
				
			||||
 | 
															window.addEventListener('click', onClickClose); | 
				
			||||
 | 
														} else { | 
				
			||||
 | 
															window.removeEventListener('click', onClickClose); | 
				
			||||
 | 
														} | 
				
			||||
 | 
													} | 
				
			||||
 | 
												} | 
				
			||||
 | 
											} | 
				
			||||
 | 
										} | 
				
			||||
 | 
									} | 
				
			||||
 | 
								} | 
				
			||||
 | 
							} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
						}); | 
				
			||||
 | 
						core.action_registry.add("open_form_3d_view", open_form_3d_view); | 
				
			||||
 | 
						return open_form_3d_view; | 
				
			||||
 | 
					}); | 
				
			||||
@ -0,0 +1,412 @@ | 
				
			|||||
 | 
					odoo.define('button_near_create.tree_button', function(require) { | 
				
			||||
 | 
						"use strict"; | 
				
			||||
 | 
						var ListController = require('web.ListController'); | 
				
			||||
 | 
						var ListView = require('web.ListView'); | 
				
			||||
 | 
						var viewRegistry = require('web.view_registry'); | 
				
			||||
 | 
						var core = require('web.core'); | 
				
			||||
 | 
						var session = require('web.session'); | 
				
			||||
 | 
						var Dialog = require('web.Dialog'); | 
				
			||||
 | 
						var QWeb = core.qweb; | 
				
			||||
 | 
						var rpc = require('web.rpc'); | 
				
			||||
 | 
						var ajax = require('web.ajax'); | 
				
			||||
 | 
						var PositionDialog = Dialog.extend({ | 
				
			||||
 | 
							/** | 
				
			||||
 | 
							 * Initialize the PositionDialog. | 
				
			||||
 | 
							 * | 
				
			||||
 | 
							 * @param {Object} parent - The parent object. | 
				
			||||
 | 
							 * @param {Object} options - Dialog options. | 
				
			||||
 | 
							 * @param {Object} pointer - Object containing x and y coordinates. | 
				
			||||
 | 
							 * @param {Function} close - Function to be called on dialog close. | 
				
			||||
 | 
							 */ | 
				
			||||
 | 
							init: function(parent, options) { | 
				
			||||
 | 
								var opt = options; | 
				
			||||
 | 
								this._super(...arguments) | 
				
			||||
 | 
								this.pointer = opt.pointer | 
				
			||||
 | 
								this.onClickClose = opt.close | 
				
			||||
 | 
							}, | 
				
			||||
 | 
							/** | 
				
			||||
 | 
							 * Render the PositionDialog element. | 
				
			||||
 | 
							 * Set the dialog's position based on the provided coordinates. | 
				
			||||
 | 
							 */ | 
				
			||||
 | 
							renderElement: function() { | 
				
			||||
 | 
								this._super() | 
				
			||||
 | 
								this.$modal.find('.modal-dialog').css({ | 
				
			||||
 | 
									position: 'absolute', | 
				
			||||
 | 
									left: this.pointer.x, | 
				
			||||
 | 
									top: this.pointer.y, | 
				
			||||
 | 
								}) | 
				
			||||
 | 
							} | 
				
			||||
 | 
						}) | 
				
			||||
 | 
						//Extends list controller class to add event listener for 3D button.
 | 
				
			||||
 | 
						var TreeButton = ListController.extend({ | 
				
			||||
 | 
							buttons_template: 'StockLocationListView.buttons', | 
				
			||||
 | 
							events: _.extend({}, ListController.prototype.events, { | 
				
			||||
 | 
								'click .open_3d_view': '_Open3DView', | 
				
			||||
 | 
							}), | 
				
			||||
 | 
							/** | 
				
			||||
 | 
							 * Starts the process of displaying rendered 3D object of stock.location. | 
				
			||||
 | 
							 */ | 
				
			||||
 | 
							_Open3DView: async function(ev) { | 
				
			||||
 | 
								var self = this; | 
				
			||||
 | 
								var wh_data; | 
				
			||||
 | 
								var data; | 
				
			||||
 | 
								var loc_quant; | 
				
			||||
 | 
								let controls, renderer, clock, scene, camera, pointer, raycaster; | 
				
			||||
 | 
								var mesh, group; | 
				
			||||
 | 
								var material; | 
				
			||||
 | 
								var loc_color; | 
				
			||||
 | 
								var loc_opacity = 0.5; | 
				
			||||
 | 
								var textSize; | 
				
			||||
 | 
								let selectedObject = null; | 
				
			||||
 | 
								var dialogs = null; | 
				
			||||
 | 
								var wh_id; | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * Make a jsonRpc call to fetch available warehouses and list it in the dropdown. | 
				
			||||
 | 
								 * | 
				
			||||
 | 
								 * @await | 
				
			||||
 | 
								 * @param {integer} company_id | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								await ajax.jsonRpc('/3Dstock/warehouse', 'call', { | 
				
			||||
 | 
									'company_id': session.user_context.allowed_company_ids[0], | 
				
			||||
 | 
								}).then(function(incoming_data) { | 
				
			||||
 | 
									wh_data = incoming_data; | 
				
			||||
 | 
								}); | 
				
			||||
 | 
								wh_id = wh_data[0][0]; | 
				
			||||
 | 
								var select = document.createElement("select"); | 
				
			||||
 | 
								select.name = "mySelect"; | 
				
			||||
 | 
								for (let i = 0; i < wh_data.length; i++) { | 
				
			||||
 | 
									var option = document.createElement("option"); | 
				
			||||
 | 
									option.value = wh_data[i][0]; | 
				
			||||
 | 
									option.text = wh_data[i][1]; | 
				
			||||
 | 
									select.appendChild(option); | 
				
			||||
 | 
									select.classList.add("customselect"); | 
				
			||||
 | 
								} | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								var closeDiv = document.createElement("button"); | 
				
			||||
 | 
								closeDiv.classList.add("closeBtn"); | 
				
			||||
 | 
								closeDiv.innerHTML = "×" | 
				
			||||
 | 
								var colorDiv = document.createElement("div"); | 
				
			||||
 | 
								colorDiv.classList.add("rectangle"); | 
				
			||||
 | 
								var color1 = document.createElement("div"); | 
				
			||||
 | 
								color1.classList.add("square1"); | 
				
			||||
 | 
								colorDiv.appendChild(color1); | 
				
			||||
 | 
								var colorText1 = document.createElement("div"); | 
				
			||||
 | 
								colorText1.classList.add("squareText1"); | 
				
			||||
 | 
								colorText1.innerHTML = "Overload"; | 
				
			||||
 | 
								colorDiv.appendChild(colorText1); | 
				
			||||
 | 
								var color2 = document.createElement("div"); | 
				
			||||
 | 
								color2.classList.add("square2"); | 
				
			||||
 | 
								colorDiv.appendChild(color2); | 
				
			||||
 | 
								var colorText2 = document.createElement("div"); | 
				
			||||
 | 
								colorText2.classList.add("squareText2"); | 
				
			||||
 | 
								colorText2.innerHTML = "Almost Full"; | 
				
			||||
 | 
								colorDiv.appendChild(colorText2); | 
				
			||||
 | 
								var color3 = document.createElement("div"); | 
				
			||||
 | 
								color3.classList.add("square3"); | 
				
			||||
 | 
								colorDiv.appendChild(color3); | 
				
			||||
 | 
								var colorText3 = document.createElement("div"); | 
				
			||||
 | 
								colorText3.classList.add("squareText3"); | 
				
			||||
 | 
								colorText3.innerHTML = "Free Space Available"; | 
				
			||||
 | 
								colorDiv.appendChild(colorText3); | 
				
			||||
 | 
								var color4 = document.createElement("div"); | 
				
			||||
 | 
								color4.classList.add("square4"); | 
				
			||||
 | 
								colorDiv.appendChild(color4); | 
				
			||||
 | 
								var colorText4 = document.createElement("div"); | 
				
			||||
 | 
								colorText4.classList.add("squareText4"); | 
				
			||||
 | 
								colorText4.innerHTML = "No Product/Load"; | 
				
			||||
 | 
								colorDiv.appendChild(colorText4); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
								start(); | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * The complete working of fetching data from stock.location and displaying them in the form of 3d objects. | 
				
			||||
 | 
								 * | 
				
			||||
 | 
								 * @async | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								async function start() { | 
				
			||||
 | 
									/** | 
				
			||||
 | 
									 * Make a jsonRpc call to fetch location details of corresponding warehouse. | 
				
			||||
 | 
									 * | 
				
			||||
 | 
									 * @await | 
				
			||||
 | 
									 * @param {integer} company_id | 
				
			||||
 | 
									 * @param {integer} wh_id | 
				
			||||
 | 
									 */ | 
				
			||||
 | 
									await ajax.jsonRpc('/3Dstock/data', 'call', { | 
				
			||||
 | 
										'company_id': session.user_context.allowed_company_ids[0], | 
				
			||||
 | 
										'wh_id': wh_id, | 
				
			||||
 | 
									}).then(function(incoming_data) { | 
				
			||||
 | 
										data = incoming_data; | 
				
			||||
 | 
									}); | 
				
			||||
 | 
									scene = new THREE.Scene(); | 
				
			||||
 | 
									scene.background = new THREE.Color(0xdfdfdf); | 
				
			||||
 | 
									clock = new THREE.Clock(); | 
				
			||||
 | 
									camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.5, 6000); | 
				
			||||
 | 
									camera.position.set(0, 200, 300) | 
				
			||||
 | 
									renderer = new THREE.WebGLRenderer({ | 
				
			||||
 | 
										antialias: true | 
				
			||||
 | 
									}); | 
				
			||||
 | 
									renderer.setSize(window.innerWidth, window.innerHeight / 1.164); | 
				
			||||
 | 
									renderer.setPixelRatio(window.devicePixelRatio); | 
				
			||||
 | 
									renderer.render(scene, camera); | 
				
			||||
 | 
									self.$el.find('.o_content').html(renderer.domElement); | 
				
			||||
 | 
									self.$el.find('.o_content').append(select); | 
				
			||||
 | 
									self.$el.find('.o_content').append(colorDiv); | 
				
			||||
 | 
									self.$el.find('.o_content').append(closeDiv); | 
				
			||||
 | 
									var dropdown = document.querySelector(".customselect"); | 
				
			||||
 | 
									if (dropdown) { | 
				
			||||
 | 
										dropdown.addEventListener("change", warehouseChange); | 
				
			||||
 | 
									} | 
				
			||||
 | 
									var closeBtn = document.querySelector(".closeBtn"); | 
				
			||||
 | 
									if (closeBtn) { | 
				
			||||
 | 
										closeBtn.addEventListener("click", onWindowClose); | 
				
			||||
 | 
									} | 
				
			||||
 | 
									controls = new THREE.OrbitControls(camera, renderer.domElement); | 
				
			||||
 | 
									const baseGeometry = new THREE.BoxGeometry(800, 0, 800); | 
				
			||||
 | 
									const baseMaterial = new THREE.MeshBasicMaterial({ | 
				
			||||
 | 
										color: 0xffffff, | 
				
			||||
 | 
										transparent: false, | 
				
			||||
 | 
										opacity: 1, | 
				
			||||
 | 
										side: THREE.BackSide, | 
				
			||||
 | 
									}); | 
				
			||||
 | 
									const baseCube = new THREE.Mesh(baseGeometry, baseMaterial); | 
				
			||||
 | 
									scene.add(baseCube); | 
				
			||||
 | 
									group = new THREE.Group(); | 
				
			||||
 | 
									//traversing through each location object
 | 
				
			||||
 | 
									for (let [key, value] of Object.entries(data)) { | 
				
			||||
 | 
										//checks if the dimension values of the location are non zero
 | 
				
			||||
 | 
										if ((value[0] > 0) || (value[1] > 0) || (value[2] > 0) || (value[3] > 0) || (value[4] > 0) || (value[5] > 0)) { | 
				
			||||
 | 
											const geometry = new THREE.BoxGeometry(value[3], value[5], value[4]); | 
				
			||||
 | 
											geometry.translate(0, (value[5] / 2), 0); | 
				
			||||
 | 
											const edges = new THREE.EdgesGeometry(geometry); | 
				
			||||
 | 
											/** | 
				
			||||
 | 
											 * Make a jsonRpc call to fetch the stock details of particular location. | 
				
			||||
 | 
											 * | 
				
			||||
 | 
											 * @await | 
				
			||||
 | 
											 * @param {integer} loc_code | 
				
			||||
 | 
											 */ | 
				
			||||
 | 
											await ajax.jsonRpc('/3Dstock/data/quantity', 'call', { | 
				
			||||
 | 
												'loc_code': key, | 
				
			||||
 | 
											}).then(function(quant_data) { | 
				
			||||
 | 
												loc_quant = quant_data; | 
				
			||||
 | 
											}); | 
				
			||||
 | 
											//checking the quantity and capacity of the location to determine the color of the location
 | 
				
			||||
 | 
											if (loc_quant[0] > 0) { | 
				
			||||
 | 
												if (loc_quant[1] > 100) { | 
				
			||||
 | 
													loc_color = 0xcc0000; | 
				
			||||
 | 
													loc_opacity = 0.8; | 
				
			||||
 | 
												} else if (loc_quant[1] > 50) { | 
				
			||||
 | 
													loc_color = 0xe6b800; | 
				
			||||
 | 
													loc_opacity = 0.8; | 
				
			||||
 | 
												} else { | 
				
			||||
 | 
													loc_color = 0x00802b; | 
				
			||||
 | 
													loc_opacity = 0.8; | 
				
			||||
 | 
												} | 
				
			||||
 | 
											} else { | 
				
			||||
 | 
												if (loc_quant[1] == -1) { | 
				
			||||
 | 
													loc_color = 0x00802b; | 
				
			||||
 | 
													loc_opacity = 0.8; | 
				
			||||
 | 
												} else { | 
				
			||||
 | 
													loc_color = 0x8c8c8c; | 
				
			||||
 | 
													loc_opacity = 0.5; | 
				
			||||
 | 
												} | 
				
			||||
 | 
											} | 
				
			||||
 | 
											//creating a 3D box geometry for each location
 | 
				
			||||
 | 
											material = new THREE.MeshBasicMaterial({ | 
				
			||||
 | 
												color: loc_color, | 
				
			||||
 | 
												transparent: true, | 
				
			||||
 | 
												opacity: loc_opacity | 
				
			||||
 | 
											}); | 
				
			||||
 | 
											mesh = new THREE.Mesh(geometry, material); | 
				
			||||
 | 
											const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ | 
				
			||||
 | 
												color: 0x404040 | 
				
			||||
 | 
											})); | 
				
			||||
 | 
											line.position.x = value[0]; | 
				
			||||
 | 
											line.position.y = value[1]; | 
				
			||||
 | 
											line.position.z = value[2]; | 
				
			||||
 | 
											mesh.position.x = value[0]; | 
				
			||||
 | 
											mesh.position.y = value[1]; | 
				
			||||
 | 
											mesh.position.z = value[2]; | 
				
			||||
 | 
											const loader = new THREE.FontLoader(); | 
				
			||||
 | 
											loader.load('https://threejs.org/examples/fonts/droid/droid_sans_bold.typeface.json', function(font) { | 
				
			||||
 | 
												const textcolor = 0x000000; | 
				
			||||
 | 
												const textMat = new THREE.MeshBasicMaterial({ | 
				
			||||
 | 
													color: textcolor, | 
				
			||||
 | 
													side: THREE.DoubleSide, | 
				
			||||
 | 
												}); | 
				
			||||
 | 
												const textmessage = key; | 
				
			||||
 | 
												if (value[3] > value[4]) { | 
				
			||||
 | 
													textSize = (value[4] / 2) - (value[4] / 2.9); | 
				
			||||
 | 
												} else { | 
				
			||||
 | 
													textSize = (value[3] / 2) - (value[3] / 2.9); | 
				
			||||
 | 
												} | 
				
			||||
 | 
												const textshapes = font.generateShapes(textmessage, textSize); | 
				
			||||
 | 
												const textgeometry = new THREE.ShapeGeometry(textshapes); | 
				
			||||
 | 
												textgeometry.translate(0, ((value[5] / 2) - (textSize / (textSize - 1.5))), 0); | 
				
			||||
 | 
												const text = new THREE.Mesh(textgeometry, textMat); | 
				
			||||
 | 
												if (value[4] > value[3]) { | 
				
			||||
 | 
													text.rotation.y = Math.PI / 2; | 
				
			||||
 | 
													text.position.x = value[0]; | 
				
			||||
 | 
													text.position.y = value[1]; | 
				
			||||
 | 
													text.position.z = value[2] + (textSize * 2) + ((value[3] / 3.779 / 2) / 2) + (textSize / 2); | 
				
			||||
 | 
												} else { | 
				
			||||
 | 
													text.position.x = value[0] - (textSize * 2) - ((value[4] / 3.779 / 2) / 2) - (textSize / 2); | 
				
			||||
 | 
													text.position.y = value[1]; | 
				
			||||
 | 
													text.position.z = value[2]; | 
				
			||||
 | 
												} | 
				
			||||
 | 
												scene.add(text); | 
				
			||||
 | 
											}); | 
				
			||||
 | 
											scene.add(mesh); | 
				
			||||
 | 
											scene.add(line); | 
				
			||||
 | 
											mesh.name = key; | 
				
			||||
 | 
											mesh.userData = { | 
				
			||||
 | 
												color: loc_color | 
				
			||||
 | 
											}; | 
				
			||||
 | 
											group.add(mesh); | 
				
			||||
 | 
										} | 
				
			||||
 | 
									} | 
				
			||||
 | 
									scene.add(group); | 
				
			||||
 | 
									raycaster = new THREE.Raycaster(); | 
				
			||||
 | 
									pointer = new THREE.Vector3(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
									animate(); | 
				
			||||
 | 
								} | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * Triggered when users change warehouse and calls the start() function with the latest warehouse id. | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								function warehouseChange() { | 
				
			||||
 | 
									var selectedBox = document.querySelector(".customselect"); | 
				
			||||
 | 
									var selectValue = selectedBox.value; | 
				
			||||
 | 
									wh_id = selectValue; | 
				
			||||
 | 
									start(); | 
				
			||||
 | 
								} | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * Handles the resizing and setting the pixel ration on window resize. | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								function onWindowResize() { | 
				
			||||
 | 
									camera.aspect = window.innerWidth / window.innerHeight; | 
				
			||||
 | 
									camera.updateProjectionMatrix(); | 
				
			||||
 | 
									renderer.setSize(window.innerWidth, window.innerHeight / 1.164); | 
				
			||||
 | 
								} | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * Triggered when user clicks on close button. | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								function onWindowClose() { | 
				
			||||
 | 
									window.location.reload(); | 
				
			||||
 | 
								} | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * Animates and renders the three.renderer object to make changes on the scene. | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								function animate() { | 
				
			||||
 | 
									requestAnimationFrame(animate); | 
				
			||||
 | 
									const delta = clock.getDelta(); | 
				
			||||
 | 
									renderer.render(scene, camera); | 
				
			||||
 | 
									var canvas = document.getElementsByTagName("canvas")[0]; | 
				
			||||
 | 
									var selectedBox = document.querySelector(".customselect"); | 
				
			||||
 | 
									var colorBox = document.querySelector(".rectangle"); | 
				
			||||
 | 
									var closeDiv = document.querySelector(".closeBtn"); | 
				
			||||
 | 
									//checking the canvas element adding event listener on canvas.
 | 
				
			||||
 | 
									if (canvas == null) { | 
				
			||||
 | 
										window.removeEventListener('dblclick', onPointerMove); | 
				
			||||
 | 
										window.removeEventListener('resize', onWindowResize); | 
				
			||||
 | 
										if (selectedBox) { | 
				
			||||
 | 
											selectedBox.style.display = "none"; | 
				
			||||
 | 
										} | 
				
			||||
 | 
										if (colorBox) { | 
				
			||||
 | 
											colorBox.style.display = "none"; | 
				
			||||
 | 
										} | 
				
			||||
 | 
										if (closeDiv) { | 
				
			||||
 | 
											closeDiv.style.display = "none"; | 
				
			||||
 | 
										} | 
				
			||||
 | 
									} else { | 
				
			||||
 | 
										window.addEventListener('dblclick', onPointerMove); | 
				
			||||
 | 
										window.addEventListener('resize', onWindowResize); | 
				
			||||
 | 
										if (selectedBox) { | 
				
			||||
 | 
											selectedBox.style.display = "block"; | 
				
			||||
 | 
										} | 
				
			||||
 | 
										if (colorBox) { | 
				
			||||
 | 
											colorBox.style.display = "block"; | 
				
			||||
 | 
										} | 
				
			||||
 | 
										if (closeDiv) { | 
				
			||||
 | 
											closeDiv.style.display = "block"; | 
				
			||||
 | 
										} | 
				
			||||
 | 
									} | 
				
			||||
 | 
								} | 
				
			||||
 | 
								/** | 
				
			||||
 | 
								 * gets the coordinates of the mouse point and checks for any objects. | 
				
			||||
 | 
								 * | 
				
			||||
 | 
								 * @async | 
				
			||||
 | 
								 * @param {object} event | 
				
			||||
 | 
								 */ | 
				
			||||
 | 
								async function onPointerMove(event) { | 
				
			||||
 | 
									var products; | 
				
			||||
 | 
									var button; | 
				
			||||
 | 
									if (dialogs == null) { | 
				
			||||
 | 
										if (selectedObject) { | 
				
			||||
 | 
											selectedObject.material.color.set(selectedObject.userData.color); | 
				
			||||
 | 
											selectedObject = null; | 
				
			||||
 | 
										} else { | 
				
			||||
 | 
											pointer.x = (event.clientX / window.innerWidth) * 2 - 1; | 
				
			||||
 | 
											pointer.y = -(event.clientY / (window.innerHeight)) * 2 + 1 + 0.13; | 
				
			||||
 | 
											raycaster.setFromCamera(pointer, camera); | 
				
			||||
 | 
											const intersects = raycaster.intersectObject(group, true); | 
				
			||||
 | 
											if (intersects.length > 0) { | 
				
			||||
 | 
												const res = intersects.filter(function(res) { | 
				
			||||
 | 
													return res && res.object; | 
				
			||||
 | 
												})[0]; | 
				
			||||
 | 
												if (res && res.object) { | 
				
			||||
 | 
													/** | 
				
			||||
 | 
													 * Make a jsonRpc call to fetch the details of products and their quantity of selected location. | 
				
			||||
 | 
													 * | 
				
			||||
 | 
													 * @await | 
				
			||||
 | 
													 * @param {integer} loc_code | 
				
			||||
 | 
													 */ | 
				
			||||
 | 
													await ajax.jsonRpc('/3Dstock/data/product', 'call', { | 
				
			||||
 | 
														'loc_code': res.object.name, | 
				
			||||
 | 
													}).then(function(product_data) { | 
				
			||||
 | 
														products = product_data; | 
				
			||||
 | 
													}); | 
				
			||||
 | 
													selectedObject = res.object; | 
				
			||||
 | 
													selectedObject.material.color.set(0x00ffcc); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
													function onClickClose() { | 
				
			||||
 | 
														if (selectedObject) { | 
				
			||||
 | 
															selectedObject.material.color.set(selectedObject.userData.color); | 
				
			||||
 | 
															selectedObject = null; | 
				
			||||
 | 
															dialogs.close(); | 
				
			||||
 | 
															dialogs = null; | 
				
			||||
 | 
														} | 
				
			||||
 | 
													} | 
				
			||||
 | 
													//opens a new dialogbox with proeduct and quantity details
 | 
				
			||||
 | 
													dialogs = new PositionDialog(this, { | 
				
			||||
 | 
														title: ('Location: ' + res.object.name), | 
				
			||||
 | 
														size: 'small', | 
				
			||||
 | 
														$content: $(QWeb.render('ViewLocationData', { | 
				
			||||
 | 
															data: products, | 
				
			||||
 | 
														})), | 
				
			||||
 | 
														placement: 'bottom', | 
				
			||||
 | 
														renderFooter: false, | 
				
			||||
 | 
														pointer: { | 
				
			||||
 | 
															x: event.clientX, | 
				
			||||
 | 
															y: event.clientY, | 
				
			||||
 | 
														}, | 
				
			||||
 | 
														close: onClickClose, | 
				
			||||
 | 
													}).open(); | 
				
			||||
 | 
					
 | 
				
			||||
 | 
													if (dialogs) { | 
				
			||||
 | 
														window.addEventListener('click', onClickClose); | 
				
			||||
 | 
													} else { | 
				
			||||
 | 
														window.removeEventListener('click', onClickClose); | 
				
			||||
 | 
													} | 
				
			||||
 | 
												} | 
				
			||||
 | 
											} | 
				
			||||
 | 
										} | 
				
			||||
 | 
									} | 
				
			||||
 | 
								} | 
				
			||||
 | 
							} | 
				
			||||
 | 
						}); | 
				
			||||
 | 
						var StockLocationTreeView = ListView.extend({ | 
				
			||||
 | 
							config: _.extend({}, ListView.prototype.config, { | 
				
			||||
 | 
								Controller: TreeButton, | 
				
			||||
 | 
							}), | 
				
			||||
 | 
						}); | 
				
			||||
 | 
						viewRegistry.add('3d_button_in_stock', StockLocationTreeView); | 
				
			||||
 | 
					}); | 
				
			||||
@ -0,0 +1,12 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="UTF-8"?> | 
				
			||||
 | 
					<templates> | 
				
			||||
 | 
					    <!--extending listview button template to add 3D action button--> | 
				
			||||
 | 
					    <t t-extend="ListView.buttons" t-name="StockLocationListView.buttons"> | 
				
			||||
 | 
					        <t t-jquery="button.o_list_button_add" t-operation="after"> | 
				
			||||
 | 
					            <button type="button" class="btn btn-primary fa fa-lg fa-cubes open_3d_view" | 
				
			||||
 | 
					                    style="margin-left: 3px; margin-right: 3px;"> | 
				
			||||
 | 
					                3D | 
				
			||||
 | 
					            </button> | 
				
			||||
 | 
					        </t> | 
				
			||||
 | 
					    </t> | 
				
			||||
 | 
					</templates> | 
				
			||||
@ -0,0 +1,30 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="utf-8" ?> | 
				
			||||
 | 
					<template> | 
				
			||||
 | 
					    <!--adding breadcrumbs manually in stock.location form view.--> | 
				
			||||
 | 
					    <t t-name="Location3DFormView"> | 
				
			||||
 | 
					        <div class="o_action"> | 
				
			||||
 | 
					            <div class="o_control_panel"> | 
				
			||||
 | 
					                <div class="o_cp_top"> | 
				
			||||
 | 
					                    <div class="o_cp_top_left"> | 
				
			||||
 | 
					                        <t t-slot="control-panel-top-left"> | 
				
			||||
 | 
					                            <ol class="breadcrumb"> | 
				
			||||
 | 
					                                <t t-foreach="widget.breadcrumbs" t-as="breadcrumb"> | 
				
			||||
 | 
					                                    <li class="breadcrumb-item"> | 
				
			||||
 | 
					                                        <a href="#" t-att-jsId="breadcrumb.jsId"> | 
				
			||||
 | 
					                                            <t t-esc="breadcrumb.name"/> | 
				
			||||
 | 
					                                        </a> | 
				
			||||
 | 
					                                    </li> | 
				
			||||
 | 
					                                </t> | 
				
			||||
 | 
					                                <li class="breadcrumb-item active"> | 
				
			||||
 | 
					                                    <span class="text-muted">3D view</span> | 
				
			||||
 | 
					                                </li> | 
				
			||||
 | 
					                            </ol> | 
				
			||||
 | 
					                        </t> | 
				
			||||
 | 
					                    </div> | 
				
			||||
 | 
					                </div> | 
				
			||||
 | 
					                <div class="o_cp_bottom"/> | 
				
			||||
 | 
					            </div> | 
				
			||||
 | 
					            <div class="o_content"/> | 
				
			||||
 | 
					        </div> | 
				
			||||
 | 
					    </t> | 
				
			||||
 | 
					</template> | 
				
			||||
@ -0,0 +1,41 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="UTF-8" ?> | 
				
			||||
 | 
					<templates xml:space="preserve"> | 
				
			||||
 | 
					<!--template to display location details such as product and its quantity--> | 
				
			||||
 | 
					    <div t-name="ViewLocationData"> | 
				
			||||
 | 
					        <t t-if="data['capacity'] > 0"> | 
				
			||||
 | 
					            <center><h6>Total Capacity: <span t-esc="data['capacity']"/> Units</h6></center> | 
				
			||||
 | 
					            <center><h6>Available Space: <span t-esc="data['space']"/> Units</h6></center> | 
				
			||||
 | 
					        </t> | 
				
			||||
 | 
					        <t t-if="data['product_list'].length > 0"> | 
				
			||||
 | 
					        <table> | 
				
			||||
 | 
					            <thead> | 
				
			||||
 | 
					                <tr> | 
				
			||||
 | 
					                    <th>#</th> | 
				
			||||
 | 
					                    <th style="padding-left: 10px;">Product</th> | 
				
			||||
 | 
					                    <th style="padding-left: 10px;">Quantity</th> | 
				
			||||
 | 
					                </tr> | 
				
			||||
 | 
					            </thead> | 
				
			||||
 | 
					            <tbody> | 
				
			||||
 | 
					                <t t-set="num" t-value="1"/> | 
				
			||||
 | 
					                <t t-foreach="data['product_list']" t-as="i"> | 
				
			||||
 | 
					                    <tr> | 
				
			||||
 | 
					                        <td> | 
				
			||||
 | 
					                            <span t-esc="num"/> | 
				
			||||
 | 
					                        </td> | 
				
			||||
 | 
					                        <td style="padding-left: 10px;"> | 
				
			||||
 | 
					                            <span t-esc="i['0']"/> | 
				
			||||
 | 
					                        </td> | 
				
			||||
 | 
					                        <td style="padding-left: 10px;"> | 
				
			||||
 | 
					                            <span t-esc="i['1']"/> | 
				
			||||
 | 
					                        </td> | 
				
			||||
 | 
					                    </tr> | 
				
			||||
 | 
					                    <t t-set="num" t-value="num + 1"/> | 
				
			||||
 | 
					                </t> | 
				
			||||
 | 
					            </tbody> | 
				
			||||
 | 
					        </table> | 
				
			||||
 | 
					        </t> | 
				
			||||
 | 
					        <t t-else=""> | 
				
			||||
 | 
					            <center><span>No Products Stored Here..!</span></center> | 
				
			||||
 | 
					        </t> | 
				
			||||
 | 
					    </div> | 
				
			||||
 | 
					</templates> | 
				
			||||
@ -0,0 +1,75 @@ | 
				
			|||||
 | 
					<?xml version="1.0" encoding="UTF-8" ?> | 
				
			||||
 | 
					<odoo> | 
				
			||||
 | 
					    <record id="view_location_form" model="ir.ui.view"> | 
				
			||||
 | 
					        <field name="name">stock.location.view.form.inherit.stock_3d_view | 
				
			||||
 | 
					        </field> | 
				
			||||
 | 
					        <field name="model">stock.location</field> | 
				
			||||
 | 
					        <field name="inherit_id" ref="stock.view_location_form"/> | 
				
			||||
 | 
					        <field name="arch" type="xml"> | 
				
			||||
 | 
					            <!--adding a 3D button in stock.location form view.--> | 
				
			||||
 | 
					            <xpath expr="//sheet" position="before"> | 
				
			||||
 | 
					                <header> | 
				
			||||
 | 
					                    <button type="object" name="action_view_location_3d_button" | 
				
			||||
 | 
					                            string="3D" id="view_location_3d_button" | 
				
			||||
 | 
					                            class="btn btn-primary fa fa-lg fa-cubes" | 
				
			||||
 | 
					                            attrs="{'invisible':['|',('location_id', '=', False),('length','=',0),('width','=',0)]}"/> | 
				
			||||
 | 
					                </header> | 
				
			||||
 | 
					            </xpath> | 
				
			||||
 | 
					            <!--adding location dimension fields in stock.location form view.--> | 
				
			||||
 | 
					            <xpath expr="//sheet" position="inside"> | 
				
			||||
 | 
					                <notebook> | 
				
			||||
 | 
					                    <page string="3D Properties" | 
				
			||||
 | 
					                          attrs="{'invisible': [('usage', '!=', 'internal')]}"> | 
				
			||||
 | 
					                        <group> | 
				
			||||
 | 
					                            <group string="Dimension"> | 
				
			||||
 | 
					                                <field name="length" | 
				
			||||
 | 
					                                       attrs="{'required': [('usage', '=', 'internal')]}"/> | 
				
			||||
 | 
					                                <field name="width" | 
				
			||||
 | 
					                                       attrs="{'required': [('usage', '=', 'internal')]}"/> | 
				
			||||
 | 
					                                <field name="height" | 
				
			||||
 | 
					                                       attrs="{'required': [('usage', '=', 'internal')]}"/> | 
				
			||||
 | 
					                            </group> | 
				
			||||
 | 
					                            <group string="Position"> | 
				
			||||
 | 
					                                <field name="pos_x" | 
				
			||||
 | 
					                                       attrs="{'required': [('usage', '=', 'internal')]}"/> | 
				
			||||
 | 
					                                <field name="pos_y" | 
				
			||||
 | 
					                                       attrs="{'required': [('usage', '=', 'internal')]}"/> | 
				
			||||
 | 
					                                <field name="pos_z" | 
				
			||||
 | 
					                                       attrs="{'required': [('usage', '=', 'internal')]}"/> | 
				
			||||
 | 
					                            </group> | 
				
			||||
 | 
					                        </group> | 
				
			||||
 | 
					                    </page> | 
				
			||||
 | 
					                </notebook> | 
				
			||||
 | 
					            </xpath> | 
				
			||||
 | 
					            <!--adding unique code field of the location inside the stock.location form view.--> | 
				
			||||
 | 
					            <xpath expr="//field[@name='usage']" position="after"> | 
				
			||||
 | 
					                <field name="unique_code" | 
				
			||||
 | 
					                       attrs="{'invisible': [('usage', '!=', 'internal')], 'required': [('usage', '=', 'internal')]}"/> | 
				
			||||
 | 
					            </xpath> | 
				
			||||
 | 
					            <!--adding maximum capacity field of the location inside the stock.location form view.--> | 
				
			||||
 | 
					            <xpath expr="//field[@name='storage_category_id']" position="after"> | 
				
			||||
 | 
					                <field name="max_capacity" | 
				
			||||
 | 
					                       attrs="{'invisible': [('usage', '!=', 'internal')]}"/> | 
				
			||||
 | 
					            </xpath> | 
				
			||||
 | 
					        </field> | 
				
			||||
 | 
					    </record> | 
				
			||||
 | 
					    <!--client action for 3d view of locations.--> | 
				
			||||
 | 
					    <record id="stock_location_3d_action" model="ir.actions.client"> | 
				
			||||
 | 
					        <field name="name">Location 3D View</field> | 
				
			||||
 | 
					        <field name="tag">open_form_3d_view</field> | 
				
			||||
 | 
					    </record> | 
				
			||||
 | 
					    <data> | 
				
			||||
 | 
					        <!--adding button to open 3d view in stock.location tree view--> | 
				
			||||
 | 
					        <record id="view_location_tree2" model="ir.ui.view"> | 
				
			||||
 | 
					            <field name="name">stock.location.view.tree.inherit.stock_3d_view | 
				
			||||
 | 
					            </field> | 
				
			||||
 | 
					            <field name="model">stock.location</field> | 
				
			||||
 | 
					            <field name="inherit_id" ref="stock.view_location_tree2"/> | 
				
			||||
 | 
					            <field name="arch" type="xml"> | 
				
			||||
 | 
					                <xpath expr="//tree" position="attributes"> | 
				
			||||
 | 
					                    <attribute name="js_class">3d_button_in_stock</attribute> | 
				
			||||
 | 
					                </xpath> | 
				
			||||
 | 
					            </field> | 
				
			||||
 | 
					        </record> | 
				
			||||
 | 
					    </data> | 
				
			||||
 | 
					</odoo> | 
				
			||||