Skip to Content
Odoo Menu
  • Prisijungti
  • Išbandykite nemokamai
  • Programėlės
    Finansai
    • Apskaita
    • Pateikimas apmokėjimui
    • Sąnaudos
    • Skaičiuoklė (BI)
    • Dokumentai
    • Pasirašymas
    Pardavimai
    • CRM
    • Pardavimai
    • Kasų sistema - Parduotuvė
    • Kasų sistema - Restoranas
    • Prenumeratos
    • Nuoma
    Svetainės
    • Svetainių kūrėjimo įrankis
    • El. Prekyba
    • Internetinis Tinklaraštis
    • Forumas
    • Tiesioginis pokalbis
    • eMokymasis
    Tiekimo grandinė
    • Atsarga
    • Gamyba
    • PLM
    • Įsigijimai
    • Priežiūra
    • Kokybė
    Žmogaus ištekliai
    • Darbuotojai
    • Įdarbinimas
    • Atostogos
    • Įvertinimai
    • Rekomendacijos
    • Transporto priemonės
    Rinkodara
    • Socialinė rinkodara
    • Rinkodara el. paštu
    • SMS rinkodara
    • Renginiai
    • Rinkodaros automatizavimas
    • Apklausos
    Paslaugos
    • Projektas
    • Darbo laiko žiniaraščiai
    • Priežiūros tarnyba
    • Pagalbos tarnyba
    • Planavimas
    • Rezervacijos
    Produktyvumas
    • Diskucija
    • Patvirtinimai
    • IoT
    • VoIP
    • Žinių biblioteka
    • WhatsApp
    Trečiųjų šalių programos Odoo Studija Odoo debesijos platforma
  • Pramonės šakos
    Mažmeninė prekyba
    • Knygynas
    • Drabužių parduotuvė
    • Baldų parduotuvė
    • Maisto prekių parduotuvė
    • Techninės įrangos parduotuvė
    • Žaislų parduotuvė
    Food & Hospitality
    • Barai ir pub'ai
    • Restoranas
    • Greitasis maistas
    • Guest House
    • Gėrimų platintojas
    • Hotel
    Nekilnojamasis turtas
    • Real Estate Agency
    • Architektūros įmonė
    • Konstrukcija
    • Estate Managament
    • Sodininkauti
    • Turto savininkų asociacija
    Konsultavimas
    • Accounting Firm
    • Odoo Partneris
    • Marketing Agency
    • Teisinė firma
    • Talentų paieška
    • Auditai & sertifikavimas
    Gamyba
    • Textile
    • Metal
    • Furnitures
    • Maistas
    • Brewery
    • Įmonių dovanos
    Sveikata & Fitnesas
    • Sporto klubas
    • Akinių parduotuvė
    • Fitneso Centras
    • Sveikatos praktikai
    • Vaistinė
    • Kirpėjas
    Trades
    • Handyman
    • IT įranga ir palaikymas
    • Saulės energijos sistemos
    • Shoe Maker
    • Cleaning Services
    • HVAC Services
    Kiti
    • Nonprofit Organization
    • Aplinkos agentūra
    • Reklaminių stendų nuoma
    • Fotografavimas
    • Dviračių nuoma
    • Programinės įrangos perpardavėjas
    Browse all Industries
  • Bendrija
    Mokykitės
    • Mokomosios medžiagos
    • Dokumentacija
    • Sertifikatai
    • Mokymai
    • Internetinis Tinklaraštis
    • Tinklalaidės
    Skatinkite švietinimą
    • Švietimo programa
    • Scale Up! Verslo žaidimas
    • Aplankykite Odoo
    Gaukite programinę įrangą
    • Atsisiųsti
    • Palyginkite versijas
    • Leidimai
    Bendradarbiauti
    • Github
    • Forumas
    • Renginiai
    • Vertimai
    • Tapkite partneriu
    • Services for Partners
    • Registruokite jūsų apskaitos įmonę
    Gaukite paslaugas
    • Susiraskite partnerį
    • Susirask buhalterį
    • Susitikti su konsultantu
    • Diegimo paslaugos
    • Klientų rekomendavimas
    • Palaikymas
    • Atnaujinimai
    Github Youtube Twitter Linkedin Instagram Facebook Spotify
    +1 (650) 691-3277
    Gaukite demo
  • Kainodara
  • Pagalba

Odoo is the world's easiest all-in-one management software.
It includes hundreds of business apps:

  • CRM
  • e-Commerce
  • Apskaita
  • Atsarga
  • PoS
  • Projektas
  • MRP
All apps
You need to be registered to interact with the community.
All Posts People Badges
Žymos (View all)
odoo accounting v14 pos v15
About this forum
You need to be registered to interact with the community.
All Posts People Badges
Žymos (View all)
odoo accounting v14 pos v15
About this forum
Pagalba

Migrating Javascript from Odoo 15 to Odoo 17.

Prenumeruoti

Get notified when there's activity on this post

This question has been flagged
odoo1715
1 Atsakyti
4620 Rodiniai
Portretas
Jay

I am getting errors while migrating this code to odoo 17:
getting this error: 
The following modules are needed by other modules but have not been defined, they may not be present in the correct asset bundle: @web/core/actions/action @web/views/view_registry The following modules could not be loaded because they have unmet dependencies, this is a secondary error which is likely caused by one of the above problems: @stock_3d_view/js/form_3d_view @stock_3d_view/js/listview_3d


Original code:

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 = "&times;"
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);
});


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.

no of users
-
*/
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;
});


My code:

/** @odoo-module **/

//import { registry } from '@web/core/registry';
import { Dialog } from '@web/core/dialog/dialog';
import { Component } from '@odoo/owl';
import ajax from 'web.ajax';
import * as THREE from 'three';
import { whenNextTick } from '@web/core/utils/timing';

class PositionDialog extends Dialog {
setup() {
super.setup();
this.pointer = this.props.pointer;
}
patched() {
super.patched();
// Adjust dialog position
const dialog = this.el.querySelector('.modal-dialog');
dialog.style.position = 'absolute';
dialog.style.left = `${this.pointer.x}px`;
dialog.style.top = `${this.pointer.y}px`;
}
}

class OpenForm3DView extends Component {
setup() {
super.setup();
this.actionService = this.env.services.action;
this.searchModel = this.env.searchModel;
this.companyId = this.env.searchModel.config.context.company_id;
this.locationId = this.env.searchModel.config.context.loc_id || localStorage.getItem("location_id");

if (this.locationId) {
localStorage.setItem("location_id", this.locationId);
localStorage.setItem("company_id", this.companyId);
}

this.breadcrumbs = this.env.config.breadcrumbs;
this.pointer = new THREE.Vector3();
this.dialog = null;
this.scene = new THREE.Scene();
this.scene.background = new THREE.Color(0xdfdfdf);
this.camera = new THREE.PerspectiveCamera(60, window.innerWidth / window.innerHeight, 0.5, 6000);
this.camera.position.set(0, 200, 300);
this.clock = new THREE.Clock();
this.renderer = new THREE.WebGLRenderer({ antialias: true });
this.raycaster = new THREE.Raycaster();
this.group = new THREE.Group();
}

async willStart() {
this._createColorLegend();
await this._fetchData();
}

mounted() {
this.renderer.setSize(window.innerWidth, window.innerHeight / 1.163);
this.renderer.setPixelRatio(window.devicePixelRatio);
this.renderer.render(this.scene, this.camera);

this.el.appendChild(this.renderer.domElement);
this.el.appendChild(this.colorDiv);

this.controls = new THREE.OrbitControls(this.camera, this.renderer.domElement);
this._createBaseCube();
this._createLocationObjects();
this._addEventListeners();
this._animate();
}

willUnmount() {
this._removeEventListeners();
}

// Event listener for breadcrumbs
onBreadcrumbClick(event) {
const jsId = event.target.getAttribute('jsId');
this.actionService.restore(jsId);
}

_addEventListeners() {
window.addEventListener('resize', this._onWindowResize.bind(this));
this.renderer.domElement.addEventListener('dblclick', this._onPointerMove.bind(this));
}

_removeEventListeners() {
window.removeEventListener('resize', this._onWindowResize.bind(this));
this.renderer.domElement.removeEventListener('dblclick', this._onPointerMove.bind(this));
}

async _fetchData() {
// Fetch location and stock data for 3D rendering
const locationData = await ajax.jsonRpc('/3Dstock/data/standalone', 'call', {
company_id: this.companyId,
loc_id: this.locationId,
});
this.locationData = locationData;
}

_createColorLegend() {
this.colorDiv = document.createElement("div");
this.colorDiv.classList.add("rectangle");
// Color squares with labels
const labels = [
{ color: 'square1', text: 'Overload' },
{ color: 'square2', text: 'Almost Full' },
{ color: 'square3', text: 'Free Space Available' },
{ color: 'square4blue', text: 'No Product/Load' },
];
labels.forEach(label => {
const square = document.createElement("div");
square.classList.add(label.color);
const text = document.createElement("div");
text.classList.add(`squareText${label.color.slice(-1)}`);
text.innerHTML = label.text;
this.colorDiv.appendChild(square);
this.colorDiv.appendChild(text);
});
}

_createBaseCube() {
const baseGeometry = new THREE.BoxGeometry(800, 0, 800);
const baseMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, opacity: 1 });
const baseCube = new THREE.Mesh(baseGeometry, baseMaterial);
this.scene.add(baseCube);
}

async _createLocationObjects() {
for (const [key, value] of Object.entries(this.locationData)) {
const [x, y, z, width, height, depth, locId] = value;

if (width > 0 || height > 0 || depth > 0) {
const geometry = new THREE.BoxGeometry(width, height, depth);
geometry.translate(0, height / 2, 0);

const edges = new THREE.EdgesGeometry(geometry);
const locationData = await ajax.jsonRpc('/3Dstock/data/quantity', 'call', { loc_code: key });

const locColor = this._determineLocationColor(locationData, locId);
const material = new THREE.MeshBasicMaterial({ color: locColor, transparent: true, opacity: 0.8 });

const mesh = new THREE.Mesh(geometry, material);
mesh.position.set(x, y, z);
mesh.userData = { locId, color: locColor };
this.scene.add(new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0x404040 })));

this._addLocationText(mesh, key, width, height, depth);
this.group.add(mesh);
}
}
this.scene.add(this.group);
}

_determineLocationColor(locationData, locId) {
let locColor;
const quantity = locationData[1];

if (this.locationId === locId) {
if (quantity > 100) {
locColor = 0xcc0000;
} else if (quantity > 50) {
locColor = 0xe6b800;
} else {
locColor = 0x00802b;
}
} else {
locColor = 0x8c8c8c;
}
return locColor;
}

_addLocationText(mesh, key, width, height, depth) {
const loader = new THREE.FontLoader();
loader.load('https://threejs.org/examples/fonts/droid/droid_sans_bold.typeface.json', (font) => {
const textSize = Math.min(width, depth) / 3;
const textShapes = font.generateShapes(key, textSize);
const textGeometry = new THREE.ShapeGeometry(textShapes);
const textMaterial = new THREE.MeshBasicMaterial({ color: 0x000000 });
const textMesh = new THREE.Mesh(textGeometry, textMaterial);
textGeometry.translate(0, height / 2, 0);
textMesh.position.set(mesh.position.x, mesh.position.y, mesh.position.z);
this.scene.add(textMesh);
});
}

_onWindowResize() {
this.camera.aspect = window.innerWidth / window.innerHeight;
this.camera.updateProjectionMatrix();
this.renderer.setSize(window.innerWidth, window.innerHeight / 1.163);
}

_onPointerMove(event) {
const canvasBounds = this.renderer.domElement.getBoundingClientRect();
this.pointer.x = ((event.clientX - canvasBounds.left) / canvasBounds.width) * 2 - 1;
this.pointer.y = -((event.clientY - canvasBounds.top) / canvasBounds.height) * 2 + 1;

this.raycaster.setFromCamera(this.pointer, this.camera);
const intersects = this.raycaster.intersectObjects(this.group.children);

if (intersects.length > 0) {
const selectedObject = intersects[0].object;
if (selectedObject.userData.locId) {
this.dialog = new PositionDialog(this, {
pointer: { x: event.clientX, y: event.clientY },
close: () => this.dialog.close()
});
this.dialog.mount(this.el);
}
}
}

_animate() {
requestAnimationFrame(this._animate.bind(this));
this.renderer.render(this.scene, this.camera);
}
}

registry.category('actions').add('open_form_3d_view', OpenForm3DView);


/** @odoo-module **/
import { ListController } from '@web/views/list/list_controller';
import { registry } from '@web/core/registry';
import { ajax, rpc } from '@web/core/network/rpc_service';
import { Dialog } from '@web/core/dialog/dialog';
import { useService } from '@web/core/utils/hooks';
import { QWeb } from '@web/core/qweb';
import { session } from '@web/session';

const { Component } = owl;
const THREE = require('three');
require('three/examples/js/controls/OrbitControls');

class PositionDialog extends Dialog {
setup() {
super.setup();
this.pointer = this.props.pointer;
this.onClickClose = this.props.close;
}

mounted() {
this.el.querySelector('.modal-dialog').style.position = 'absolute';
this.el.querySelector('.modal-dialog').style.left = `${this.pointer.x}px`;
this.el.querySelector('.modal-dialog').style.top = `${this.pointer.y}px`;
}
}

class TreeButton extends ListController {
setup() {
super.setup();
this.dialogService = useService('dialog');
}

async _Open3DView(ev) {
let wh_data, data, loc_quant, controls, renderer, clock, scene, camera, pointer, raycaster;
let group, loc_color, loc_opacity = 0.5;
let wh_id;
let selectedObject = null;

await ajax.jsonRpc('/3Dstock/warehouse', 'call', {
'company_id': session.user_context.allowed_company_ids[0],
}).then(incoming_data => {
wh_data = incoming_data;
});

wh_id = wh_data[0][0];
const select = document.createElement("select");
select.classList.add("customselect");

wh_data.forEach(([id, name]) => {
const option = document.createElement("option");
option.value = id;
option.text = name;
select.appendChild(option);
});

const closeDiv = document.createElement("button");
closeDiv.classList.add("closeBtn");
closeDiv.innerHTML = "&times;";
const colorDiv = this._createColorLegend();

this._start3DView({ select, closeDiv, colorDiv, wh_id });
}

_createColorLegend() {
const colorDiv = document.createElement("div");
colorDiv.classList.add("rectangle");

const colors = [
{ class: 'square1', text: 'Overload' },
{ class: 'square2', text: 'Almost Full' },
{ class: 'square3', text: 'Free Space Available' },
{ class: 'square4', text: 'No Product/Load' },
];

colors.forEach(({ class: className, text }) => {
const square = document.createElement("div");
square.classList.add(className);
colorDiv.appendChild(square);

const textDiv = document.createElement("div");
textDiv.classList.add(`${className}Text`);
textDiv.innerHTML = text;
colorDiv.appendChild(textDiv);
});

return colorDiv;
}

async _start3DView({ select, closeDiv, colorDiv, wh_id }) {
let data, loc_quant, controls, renderer, clock, scene, camera, group, loc_color, loc_opacity = 0.5;

await ajax.jsonRpc('/3Dstock/data', 'call', {
'company_id': session.user_context.allowed_company_ids[0],
'wh_id': wh_id,
}).then(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);

this.el.querySelector('.o_content').append(renderer.domElement, select, colorDiv, closeDiv);

const dropdown = document.querySelector(".customselect");
dropdown.addEventListener("change", this._warehouseChange.bind(this));

closeDiv.addEventListener("click", () => window.location.reload());
controls = new THREE.OrbitControls(camera, renderer.domElement);

const baseGeometry = new THREE.BoxGeometry(800, 0, 800);
const baseMaterial = new THREE.MeshBasicMaterial({ color: 0xffffff, side: THREE.BackSide });
const baseCube = new THREE.Mesh(baseGeometry, baseMaterial);
scene.add(baseCube);

group = new THREE.Group();
for (const [key, value] of Object.entries(data)) {
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);

await ajax.jsonRpc('/3Dstock/data/quantity', 'call', { 'loc_code': key }).then(quant_data => {
loc_quant = quant_data;
});

loc_color = this._getLocationColor(loc_quant);
loc_opacity = loc_quant[1] > 0 ? 0.8 : 0.5;

const material = new THREE.MeshBasicMaterial({
color: loc_color,
transparent: true,
opacity: loc_opacity
});
const mesh = new THREE.Mesh(geometry, material);
const line = new THREE.LineSegments(edges, new THREE.LineBasicMaterial({ color: 0x404040 }));

line.position.set(value[0], value[1], value[2]);
mesh.position.set(value[0], value[1], value[2]);

this._addTextLabel({ key, value, textSize: Math.min(value[3], value[4]) / 2, scene });
scene.add(mesh, line);
group.add(mesh);
}
}

scene.add(group);
this._animate({ renderer, scene, camera, clock });
}

_getLocationColor(loc_quant) {
if (loc_quant[0] > 0) {
if (loc_quant[1] > 100) return 0xcc0000;
else if (loc_quant[1] > 50) return 0xe6b800;
else return 0x00802b;
}
return loc_quant[1] === -1 ? 0x00802b : 0x8c8c8c;
}

_addTextLabel({ key, value, textSize, scene }) {
const loader = new THREE.FontLoader();
loader.load('https://threejs.org/examples/fonts/droid/droid_sans_bold.typeface.json', function(font) {
const textMat = new THREE.MeshBasicMaterial({ color: 0x000000, side: THREE.DoubleSide });
const textshapes = font.generateShapes(key, 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.set(value[0], value[1], value[2] + (textSize * 2));
} else {
text.position.set(value[0] - (textSize * 2), value[1], value[2]);
}
scene.add(text);
});
}

_animate({ renderer, scene, camera, clock }) {
const animate = () => {
requestAnimationFrame(animate);
renderer.render(scene, camera);
};
animate();
}

_warehouseChange() {
const selectedBox = document.querySelector(".customselect");
const selectValue = selectedBox.value;
this._start3DView({ wh_id: selectValue });
}
}

registry.category('views').add('button_near_create.tree_button', {
Controller: TreeButton,
});





0
Portretas
Atmesti
Portretas
Cybrosys Techno Solutions Pvt.Ltd
Best Answer

Hi,


To update your Odoo 17 component with the new OWL patterns:


1) Add new imports for Odoo 17 features like useState, useService and remove deprecated imports like web.ajax :


// Old imports

import { Dialog } from '@web/core/dialog/dialog';

import { Component } from '@odoo/owl';

import ajax from 'web.ajax';


// New imports

import { Dialog } from "@web/core/dialog/dialog";

import { Component, useState } from "@odoo/owl";

import { useService } from "@web/core/utils/hooks";


2) Update component structure to include static properties for template and components, in line with the new OWL standard:


// Old

class OpenForm3DView extends Component {

setup() {

super.setup();

// ...

}

}


// New

export class OpenForm3DView extends Component {

static template = "stock_3d_view.OpenForm3DView";

static components = { Dialog };


setup() {

super.setup();

// ...

}

}


3) Replace access to services via this.env.services with useService:


// Old

setup() {

    this.actionService = this.env.services.action;

    // ...

}


// New

setup() {

    this.actionService = useService("action");

    this.orm = useService("orm");

    // ...

}


4) Update data fetching to use orm.call instead of ajax.jsonRpc.


// Old

async _fetchData() {

    const locationData = await ajax.jsonRpc('/3Dstock/data/standalone', 'call', {

        company_id: this.companyId,

        loc_id: this.locationId,

    });

    this.locationData = locationData;

}


// New

async _fetchData() {

    this.locationData = await this.orm.call(

        "stock.location",

        "get_3d_stock_data",

        [this.companyId, this.locationId]

    );

}


Hope it helps

0
Portretas
Atmesti
Enjoying the discussion? Don't just read, join in!

Create an account today to enjoy exclusive features and engage with our awesome community!

Registracija
Related Posts Replies Rodiniai Veikla
Error while posting invoice to ZATCA odoo sh Solved
odoo17
Portretas
Portretas
Portretas
Portretas
3
liep. 25
3301
How to send a real-time notification to POS UI using bus.bus in Odoo 17?
odoo17
Portretas
Portretas
1
birž. 25
5745
Odoo time-sheets rights to add
odoo17
Portretas
Portretas
2
geg. 25
3209
POS is not recognizing short barcodes like "95" or "96" (Code 39 or custom short codes)
odoo17
Portretas
1
geg. 25
2202
Odoo 17
odoo17
Portretas
1
vas. 25
40
Bendrija
  • Mokomosios medžiagos
  • Dokumentacija
  • Forumas
Atvirasis kodas
  • Atsisiųsti
  • Github
  • Runbot
  • Vertimai
Paslaugos
  • Odoo.sh talpinimas
  • Palaikymas
  • Atnaujinti
  • Pritaikytas programavimo kūrimas
  • Švietimas
  • Susirask buhalterį
  • Susiraskite partnerį
  • Tapkite partneriu
Apie mus
  • Mūsų įmonė
  • Prekės ženklo turtas
  • Susisiekite su mumis
  • Darbo pasiūlymai
  • Renginiai
  • Tinklalaidės
  • Internetinis Tinklaraštis
  • Klientai
  • Teisinis • Privatumas
  • Saugumas
الْعَرَبيّة Català 简体中文 繁體中文 (台灣) Čeština Dansk Nederlands English Suomi Français Deutsch हिंदी Bahasa Indonesia Italiano 日本語 한국어 (KR) Lietuvių kalba Język polski Português (BR) română русский язык Slovenský jazyk slovenščina Español (América Latina) Español ภาษาไทย Türkçe українська Tiếng Việt

Odoo yra atvirojo kodo verslo programų rinkinys, kuris apima visas įmonės poreikius: CRM, El. Prekybą, Apskaitą, Atsargų, Kasų sistemą, Projektų valdymą ir kt.

Unikali Odoo vertės pasiūla – būti tuo pačiu metu labai lengvai naudojama ir visiškai integruota sistema.

Website made with

Odoo Experience on YouTube

1. Use the live chat to ask your questions.
2. The operator answers within a few minutes.

Live support on Youtube
Watch now