تخطي للذهاب إلى المحتوى
أودو القائمة
  • تسجيل الدخول
  • جرب مجاناً
  • التطبيقات
    المالية
    • المحاسبة
    • فوترة
    • النفقات
    • جدول البيانات (BI)
    • المستندات
    • توقيع إلكتروني
    المبيعات
    • إدارة علاقات العملاء
    • المبيعات
    • نقطة البيع للمتاجر
    • نقطة البيع للمطاعم
    • الاشتراكات
    • تأجير
    المواقع الإلكترونية
    • أداة بناء المواقع الإلكترونية
    • متاجر إلكترونية
    • مدونة
    • المنتدى
    • دردشة مباشرة
    • التعليم الإلكتروني
    سلسلة التوريد
    • المستودعات
    • التصنيع
    • إدارة دورة حياة المنتج
    • المشتريات
    • الصيانة
    • الجودة
    الموارد البشرية
    • موظفون
    • التوظيف
    • إجازة عمل
    • التقييمات
    • الإحالات
    • تطبيق الأسطول
    التسويق
    • التسويق الإجتماعي
    • التسويق عبر البريد الإلكتروني
    • التسويق عبر الرسائل النصية
    • فعاليات
    • أتمتة التسويق
    • الاستطلاعات
    الخدمات
    • المشاريع
    • الجداول الزمنية
    • الخدمة الميدانية
    • مكتب المساعدة
    • التخطيط
    • مواعيد
    اﻹنتاجية
    • مناقشة
    • الموافقات
    • إنترنت الأشياء "IoT"
    • بروتوكول ربط المحادثات الصوتية عبر الإنترنت
    • المعرفة
    • WhatsApp
    التطبيقات الخارجية ستوديو أودو منصة أودو السحابية
  • قطاعات الأعمال
    البيع بالتجزئة
    • متجر كتب
    • متجر ملابس
    • متجر أثاث
    • متجر بقالة
    • متجر معدات
    • متجر ألعاب
    الطعام والضيافة
    • بار وحانة
    • المطعم
    • مطعم للوجبات السريعة
    • نزل للضيوف
    • موزّع مشروبات
    • فندق
    العقارات
    • وكالة عقارات
    • شركة هندسة معمارية
    • البناء
    • إدارة العقارات
    • العناية بالحدائق
    • اتحاد مُلاّك العقارات
    استشارة
    • مؤسسة محاسبية
    • شريك أودو
    • وكالة تسويقية
    • منشأة قانونية
    • استقطاب المواهب
    • التدقيق والتوثيق
    التصنيع
    • الأقمشة
    • معدني
    • الأثاث
    • الطعام
    • مصنع خمور
    • هدايا الشركات
    الصحة واللياقة البدنية
    • نادي رياضي
    • متجر نظارات
    • مركز لياقة بدنية
    • الممارسون الصحيون
    • صيدلية
    • صالون تصفيف الشعر
    التجارة
    • عامل صيانة
    • الأجهزة والمعدات التقنية ودعمها
    • أنظمة الطاقة الشمسية
    • صانع أحذية
    • خدمات التنظيف
    • خدمات التكييف (HVAC)
    غير ذلك
    • منظمة غير ربحية
    • وكالة بيئية
    • تأجير لوحات إعلانية
    • تصوير
    • تأجير دراجات
    • بائع وسيط للبرمجيات
    تصفح كافة قطاعات الأعمال
  • مجتمع أودو
    تعلم
    • دروس
    • التوثيق
    • شهادات
    • التدريب
    • مدونة
    • بودكاست
    قم بتعزيز التعليم
    • برنامج تعليم
    • Scale UP! لعبة الأعمال
    • قم بزيارة أودو
    احصل على البرنامج
    • تحميل
    • قارنْ الإصدارات
    • إطلاق
    تعاون
    • جيت هاب "Github"
    • المنتدى
    • فعاليات
    • الترجمات
    • كنْ شريكاً
    • خدمات الشركاء
    • سجل مكتب المحاسبة الخاص بك
    احصل على الخدمات
    • اعثر على شريك
    • اعثر على محاسب
    • قابل أحد مرشدي الأعمال
    • خدمات التنفيذ
    • مراجع العملاء
    • الدعم
    • الترقيات
    Github Youtube Twitter Linkedin Instagram Facebook Spotify
    +1 (650) 691-3277
    الحصول على عرض توضيحي
  • الأسعار
  • المساعدة

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

  • إدارة علاقات العملاء
  • e-Commerce
  • المحاسبة
  • المخزون
  • PoS
  • المشروع
  • MRP
All apps
يجب أن تكون مسجلاً حتى تتفاعل مع المجتمع.
كافة المنشورات الأفراد الشارات
علامات التصنيف (عرض الكل)
odoo accounting v14 pos v15
حول هذا المنتدى
يجب أن تكون مسجلاً حتى تتفاعل مع المجتمع.
كافة المنشورات الأفراد الشارات
علامات التصنيف (عرض الكل)
odoo accounting v14 pos v15
حول هذا المنتدى
المساعدة

Migrating Javascript from Odoo 15 to Odoo 17.

اشتراك

تسلم الإشعارات عندما يكون هناك نشاط في هذا المنشور

لقد تم الإبلاغ عن هذا السؤال
odoo1715
1 الرد
4649 أدوات العرض
الصورة الرمزية
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
الصورة الرمزية
إهمال
الصورة الرمزية
Cybrosys Techno Solutions Pvt.Ltd
أفضل إجابة

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
الصورة الرمزية
إهمال
هل أعجبك النقاش؟ لا تكن مستمعاً فقط. شاركنا!

أنشئ حساباً اليوم لتستمتع بالخصائص الحصرية، وتفاعل مع مجتمعنا الرائع!

تسجيل
المنشورات ذات الصلة الردود أدوات العرض النشاط
Error while posting invoice to ZATCA odoo sh تم الحل
odoo17
الصورة الرمزية
الصورة الرمزية
الصورة الرمزية
الصورة الرمزية
3
يوليو 25
3308
How to send a real-time notification to POS UI using bus.bus in Odoo 17?
odoo17
الصورة الرمزية
الصورة الرمزية
1
يونيو 25
5761
Odoo time-sheets rights to add
odoo17
الصورة الرمزية
الصورة الرمزية
2
مايو 25
3214
POS is not recognizing short barcodes like "95" or "96" (Code 39 or custom short codes)
odoo17
الصورة الرمزية
1
مايو 25
2207
Odoo 17
odoo17
الصورة الرمزية
1
فبراير 25
40
المجتمع
  • دروس
  • التوثيق
  • المنتدى
مصدر مفتوح
  • تحميل
  • جيت هاب "Github"
  • المشغل الآلي رنبوت
  • الترجمات
خدماتنا
  • استضافة أودو إس إتش
  • الدعم
  • الترقية
  • التطويرات المخصصة
  • التعليم
  • اعثر على محاسب
  • اعثر على شريك
  • كنْ شريكاً
معلومات عنا
  • شركتنا
  • أصول العلامة التجارية
  • اتصلْ بنا
  • الوظائف
  • فعاليات
  • بودكاست
  • مدونة
  • عملاء
  • قانوني • الخصوصية
  • الحماية
الْعَرَبيّة 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

أودو هو عبارة عن مجموعة من تطبيقات الأعمال مفتوحة المصدر التي تغطي جميع احتياجات شركتك، مثل: إدارة علاقات العملاء والتجارة الإلكترونية والمحاسبة والمخزون ونقاط البيع وإدارة المشاريع وما إلى ذلك.

ما يجعل من أودو مميزاً هو هدفه بأن يكون سهل الاستخدام للغاية ومتكاملاً تمامًا في الوقت ذاته.

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