Passa al contenuto
Odoo Menu
  • Accedi
  • Provalo gratis
  • App
    Finanze
    • Contabilità
    • Fatturazione
    • Note spese
    • Fogli di calcolo (BI)
    • Documenti
    • Firma
    Vendite
    • CRM
    • Vendite
    • Punto vendita Negozio
    • Punto vendita Ristorante
    • Abbonamenti
    • Noleggi
    Siti web
    • Configuratore sito web
    • E-commerce
    • Blog
    • Forum
    • Live chat
    • E-learning
    Supply chain
    • Magazzino
    • Produzione
    • PLM
    • Acquisti
    • Manutenzione
    • Qualità
    Risorse umane
    • Dipendenti
    • Assunzioni
    • Ferie
    • Valutazioni
    • Referral dipendenti
    • Parco veicoli
    Marketing
    • Social marketing
    • E-mail marketing
    • SMS marketing
    • Eventi
    • Marketing automation
    • Sondaggi
    Servizi
    • Progetti
    • Fogli ore
    • Assistenza sul campo
    • Helpdesk
    • Pianificazione
    • Appuntamenti
    Produttività
    • Comunicazioni
    • Approvazioni
    • IoT
    • VoIP
    • Knowledge
    • WhatsApp
    App di terze parti Odoo Studio Piattaforma cloud Odoo
  • Settori
    Retail
    • Libreria
    • Negozio di abbigliamento
    • Negozio di arredamento
    • Alimentari
    • Ferramenta
    • Negozio di giocattoli
    Cibo e ospitalità
    • Bar e pub
    • Ristorante
    • Fast food
    • Pensione
    • Grossista di bevande
    • Hotel
    Agenzia immobiliare
    • Agenzia immobiliare
    • Studio di architettura
    • Edilizia
    • Gestione immobiliare
    • Impresa di giardinaggio
    • Associazione di proprietari immobiliari
    Consulenza
    • Società di contabilità
    • Partner Odoo
    • Agenzia di marketing
    • Studio legale
    • Selezione del personale
    • Audit e certificazione
    Produzione
    • Tessile
    • Metallo
    • Arredamenti
    • Alimentare
    • Birrificio
    • Ditta di regalistica aziendale
    Benessere e sport
    • Club sportivo
    • Negozio di ottica
    • Centro fitness
    • Centro benessere
    • Farmacia
    • Parrucchiere
    Commercio
    • Tuttofare
    • Hardware e assistenza IT
    • Ditta di installazione di pannelli solari
    • Calzolaio
    • Servizi di pulizia
    • Servizi di climatizzazione
    Altro
    • Organizzazione non profit
    • Ente per la tutela ambientale
    • Agenzia di cartellonistica pubblicitaria
    • Studio fotografico
    • Punto noleggio di biciclette
    • Rivenditore di software
    Carica tutti i settori
  • Community
    Apprendimento
    • Tutorial
    • Documentazione
    • Certificazioni 
    • Formazione
    • Blog
    • Podcast
    Potenzia la tua formazione
    • Programma educativo
    • Scale Up! Business Game
    • Visita Odoo
    Ottieni il software
    • Scarica
    • Versioni a confronto
    • Note di versione
    Collabora
    • Github
    • Forum
    • Eventi
    • Traduzioni
    • Diventa nostro partner
    • Servizi per partner
    • Registra la tua società di contabilità
    Ottieni servizi
    • Trova un partner
    • Trova un contabile
    • Incontra un esperto
    • Servizi di implementazione
    • Testimonianze dei clienti
    • Supporto
    • Aggiornamenti
    GitHub Youtube Twitter Linkedin Instagram Facebook Spotify
    +1 (650) 691-3277
    Richiedi una demo
  • Prezzi
  • Aiuto

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

  • CRM
  • e-Commerce
  • Contabilità
  • Magazzino
  • PoS
  • Progetti
  • MRP
All apps
È necessario essere registrati per interagire con la community.
Tutti gli articoli Persone Badge
Etichette (Mostra tutto)
odoo accounting v14 pos v15
Sul forum
È necessario essere registrati per interagire con la community.
Tutti gli articoli Persone Badge
Etichette (Mostra tutto)
odoo accounting v14 pos v15
Sul forum
Assistenza

Migrating Javascript from Odoo 15 to Odoo 17.

Iscriviti

Ricevi una notifica quando c'è un'attività per questo post

La domanda è stata contrassegnata
odoo1715
1 Rispondi
4636 Visualizzazioni
Avatar
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
Avatar
Abbandona
Avatar
Cybrosys Techno Solutions Pvt.Ltd
Risposta migliore

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
Avatar
Abbandona
Ti stai godendo la conversazione? Non leggere soltanto, partecipa anche tu!

Crea un account oggi per scoprire funzionalità esclusive ed entrare a far parte della nostra fantastica community!

Registrati
Post correlati Risposte Visualizzazioni Attività
Error while posting invoice to ZATCA odoo sh Risolto
odoo17
Avatar
Avatar
Avatar
Avatar
3
lug 25
3305
How to send a real-time notification to POS UI using bus.bus in Odoo 17?
odoo17
Avatar
Avatar
1
giu 25
5757
Odoo time-sheets rights to add
odoo17
Avatar
Avatar
2
mag 25
3213
POS is not recognizing short barcodes like "95" or "96" (Code 39 or custom short codes)
odoo17
Avatar
1
mag 25
2205
Odoo 17
odoo17
Avatar
1
feb 25
40
Community
  • Tutorial
  • Documentazione
  • Forum
Open source
  • Scarica
  • Github
  • Runbot
  • Traduzioni
Servizi
  • Hosting Odoo.sh
  • Supporto
  • Aggiornamenti
  • Sviluppi personalizzati
  • Formazione
  • Trova un contabile
  • Trova un partner
  • Diventa nostro partner
Chi siamo
  • La nostra azienda
  • Branding
  • Contattaci
  • Lavora con noi
  • Eventi
  • Podcast
  • Blog
  • Clienti
  • Note legali • Privacy
  • Sicurezza
الْعَرَبيّة 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 è un gestionale di applicazioni aziendali open source pensato per coprire tutte le esigenze della tua azienda: CRM, Vendite, E-commerce, Magazzino, Produzione, Fatturazione elettronica, Project Management e molto altro.

Il punto di forza di Odoo è quello di offrire un ecosistema unico di app facili da usare, intuitive e completamente integrate tra loro.

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