@ -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> |