Zum Inhalt springen
Odoo Menü
  • Anmelden
  • Jetzt gratis testen
  • Apps
    Finanzen
    • Buchhaltung
    • Rechnungsstellung
    • Spesenabrechnung
    • Tabellenkalkulation (BI)
    • Dokumente
    • E-Signatur
    Vertrieb
    • CRM
    • Vertrieb
    • Kassensystem – Shop
    • Kassensystem – Restaurant
    • Abonnements
    • Vermietung
    Websites
    • Website-Builder
    • E-Commerce
    • Blog
    • Forum
    • Livechat
    • E-Learning
    Lieferkette
    • Lager
    • Fertigung
    • PLM
    • Einkauf
    • Wartung
    • Qualität
    Personalwesen
    • Mitarbeiter
    • Personalbeschaffung
    • Abwesenheiten
    • Mitarbeiterbeurteilung
    • Personalempfehlungen
    • Fuhrpark
    Marketing-
    • Social Marketing
    • E-Mail-Marketing
    • SMS-Marketing
    • Veranstaltungen
    • Marketing-Automatisierung
    • Umfragen
    Dienstleistungen
    • Projekte
    • Zeiterfassung
    • Außendienst
    • Kundendienst
    • Planung
    • Termine
    Produktivität
    • Dialog
    • Genehmigungen
    • IoT
    • VoIP
    • Wissensdatenbank
    • WhatsApp
    Apps von Drittanbietern Odoo Studio Odoo Cloud-Plattform
  • Branchen
    Einzelhandel
    • Buchladen
    • Kleidergeschäft
    • Möbelhaus
    • Lebensmittelgeschäft
    • Baumarkt
    • Spielwarengeschäft
    Essen & Gastgewerbe
    • Bar und Kneipe
    • Restaurant
    • Fast Food
    • Gästehaus
    • Getränkehändler
    • Hotel
    Immobilien
    • Immobilienagentur
    • Architekturbüro
    • Baugewerbe
    • Immobilienverwaltung
    • Gartenarbeit
    • Eigentümervereinigung
    Beratung
    • Buchhaltungsfirma
    • Odoo-Partner
    • Marketingagentur
    • Anwaltskanzlei
    • Talentakquise
    • Prüfung & Zertifizierung
    Fertigung
    • Textil
    • Metall
    • Möbel
    • Speisen
    • Brauerei
    • Firmengeschenke
    Gesundheit & Fitness
    • Sportklub
    • Brillengeschäft
    • Fitnessstudio
    • Therapeut
    • Apotheke
    • Friseursalon
    Handel
    • Handyman
    • IT-Hardware & -Support
    • Solarenergiesysteme
    • Schuster
    • Reinigungsdienstleistungen
    • HLK-Dienstleistungen
    Sonstiges
    • Gemeinnützige Organisation
    • Umweltschutzagentur
    • Plakatwandvermietung
    • Fotostudio
    • Fahrrad-Leasing
    • Software-Händler
    Alle Branchen ansehen
  • Community
    Lernen
    • Tutorials
    • Dokumentation
    • Zertifizierungen
    • Schulung
    • Blog
    • Podcast
    Bildung fördern
    • Bildungsprogramm
    • Scale-Up! Planspiel
    • Odoo besuchen
    Software anfragen
    • Herunterladen
    • Editionen vergleichen
    • Releases
    Zusammenarbeiten
    • Github
    • Forum
    • Veranstaltungen
    • Übersetzungen
    • Partner werden
    • Dienstleistungen für Partner
    • Buchhaltungsfirma registrieren
    Services anfragen
    • Partner finden
    • Buchhalter finden
    • Einen Experten treffen
    • Implementierungsservices
    • Kundenreferenzen
    • Support
    • Upgrades
    Github Youtube Twitter Linkedin Instagram Facebook Spotify
    +1 (650) 691-3277
    Eine Demo erhalten
  • Preiskalkulation
  • Hilfe

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

  • CRM
  • e-Commerce
  • Buchhaltung
  • Lager
  • PoS
  • Projekte
  • MRP
All apps
Sie müssen registriert sein, um mit der Community zu interagieren.
Alle Beiträge Personen Abzeichen
Stichwörter (Alle anzeigen)
odoo accounting v14 pos v15
Über dieses Forum
Sie müssen registriert sein, um mit der Community zu interagieren.
Alle Beiträge Personen Abzeichen
Stichwörter (Alle anzeigen)
odoo accounting v14 pos v15
Über dieses Forum
Hilfe

Migrating Javascript from Odoo 15 to Odoo 17.

Abonnieren

Erhalten Sie eine Benachrichtigung, wenn es eine Aktivität zu diesem Beitrag gibt

Diese Frage wurde gekennzeichnet
odoo1715
1 Antworten
4626 Ansichten
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
Verwerfen
Avatar
Cybrosys Techno Solutions Pvt.Ltd
Beste Antwort

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
Verwerfen
Diskutieren Sie gerne? Treten Sie bei, statt nur zu lesen!

Erstellen Sie heute ein Konto, um exklusive Funktionen zu nutzen und mit unserer tollen Community zu interagieren!

Registrieren
Verknüpfte Beiträge Antworten Ansichten Aktivität
Error while posting invoice to ZATCA odoo sh Gelöst
odoo17
Avatar
Avatar
Avatar
Avatar
3
Juli 25
3301
How to send a real-time notification to POS UI using bus.bus in Odoo 17?
odoo17
Avatar
Avatar
1
Juni 25
5749
Odoo time-sheets rights to add
odoo17
Avatar
Avatar
2
Mai 25
3210
POS is not recognizing short barcodes like "95" or "96" (Code 39 or custom short codes)
odoo17
Avatar
1
Mai 25
2202
Odoo 17
odoo17
Avatar
1
Feb. 25
40
Community
  • Tutorials
  • Dokumentation
  • Forum
Open Source
  • Herunterladen
  • Github
  • Runbot
  • Übersetzungen
Dienstleistungen
  • Odoo.sh-Hosting
  • Support
  • Upgrade
  • Individuelle Entwicklungen
  • Bildung
  • Buchhalter finden
  • Partner finden
  • Partner werden
Über uns
  • Unsere Firma
  • Markenwerte
  • Kontakt
  • Karriere
  • Veranstaltungen
  • Podcast
  • Blog
  • Kunden
  • Rechtliches • Datenschutz
  • Sicherheit
الْعَرَبيّة 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 ist eine Suite von Open-Source-Betriebsanwendungen, die alle Bedürfnisse Ihres Unternehmens abdecken: CRM, E-Commerce, Buchhaltung, Lager, Kassensystem, Projektmanagement etc.

Das einzigartige Wertversprechen von Odoo ist, dass es gleichzeitig sehr einfach zu bedienen und voll integriert ist.

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