sf新增表面工艺参数同步接口和基础对象,新增dockerfile和requirements.txt文件
This commit is contained in:
32
Dockerfile
Normal file
32
Dockerfile
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
FROM jikimo-hn-docker.pkg.coding.net/jikimo_sfs/odoo-sf/odoo-sf:1.0
|
||||||
|
USER root:root
|
||||||
|
|
||||||
|
ADD . /app
|
||||||
|
|
||||||
|
WORKDIR /app
|
||||||
|
|
||||||
|
COPY ./requirements.txt /app
|
||||||
|
|
||||||
|
RUN sed -i 's#http://deb.debian.org#http://mirrors.aliyun.com#g' /etc/apt/sources.list
|
||||||
|
# Install some deps, lessc and less-plugin-clean-css, and wkhtmltopdf
|
||||||
|
|
||||||
|
# 系统更新
|
||||||
|
RUN apt-get update
|
||||||
|
# RUN apt-get do-release-upgrade
|
||||||
|
|
||||||
|
# 更新python的依赖
|
||||||
|
#RUN pip3 install --upgrade pip
|
||||||
|
RUN pip3 install -r requirements.txt -i https://mirrors.aliyun.com/pypi/simple
|
||||||
|
|
||||||
|
# 设置时区
|
||||||
|
RUN rm -rf /etc/localtime
|
||||||
|
RUN ln -s /usr/share/zoneinfo/Asia/Shanghai /etc/localtime
|
||||||
|
|
||||||
|
# 拷贝代码到工作目录
|
||||||
|
COPY . /mnt/extra-addons
|
||||||
|
|
||||||
|
# 拷贝配置文件到配置目录
|
||||||
|
COPY ./odoo.conf /etc/odoo
|
||||||
|
|
||||||
|
# 启动odoo
|
||||||
|
#COPY ./entrypoint.sh /
|
||||||
Binary file not shown.
@@ -15,5 +15,4 @@
|
|||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -1 +0,0 @@
|
|||||||
from . import controllers
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
"name": "OWL开发演示",
|
|
||||||
"summary": "示例OWL开发模块。",
|
|
||||||
"description": "用于演示OWL模块的开发。",
|
|
||||||
"author": "Van",
|
|
||||||
"website": "https://topodoo.com",
|
|
||||||
"category": "Tutorials",
|
|
||||||
"version": "15.0.0.1",
|
|
||||||
"depends": ["sale", "sale_management","web_widget_model_viewer"],
|
|
||||||
"demo": [],
|
|
||||||
"data": [
|
|
||||||
#'report/test_sale_report.xml',
|
|
||||||
'views/views.xml',
|
|
||||||
],
|
|
||||||
'assets': {
|
|
||||||
'web.assets_qweb': [
|
|
||||||
# 'owl_demo/static/src/xml/MyComponent.xml',
|
|
||||||
|
|
||||||
#'owl_demo/static/src/js/html_template/template_demo_field.xml',
|
|
||||||
'owl_demo/static/src/js/3d_viewer/3d_viewer.xml',
|
|
||||||
],
|
|
||||||
'web.assets_backend': [
|
|
||||||
# 'owl_demo/static/src/xml/MyComponent.xml',
|
|
||||||
# 'owl_demo/static/src/js/components/MyComponent.js',
|
|
||||||
# 'owl_demo/static/src/js/services/*',
|
|
||||||
|
|
||||||
#'owl_demo/static/src/js/html_template/*',
|
|
||||||
'owl_demo/static/src/js/3d_viewer/*',
|
|
||||||
'owl_demo/static/src/lib/model-viewer.min.js',
|
|
||||||
],
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
from . import main
|
|
||||||
@@ -1,266 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
|
||||||
import base64
|
|
||||||
import io
|
|
||||||
import json
|
|
||||||
import os
|
|
||||||
|
|
||||||
from odoo import _
|
|
||||||
from odoo import http
|
|
||||||
from odoo.http import request
|
|
||||||
|
|
||||||
|
|
||||||
class Viewer3d(http.Controller):
|
|
||||||
|
|
||||||
@http.route(['/Viewer3d/<int:attachment_id>'], type='http', auth="None")
|
|
||||||
def viewer3d(self, attachment_id, **kwargs):
|
|
||||||
attachment = self._attachment_get(attachment_id)
|
|
||||||
return attachment
|
|
||||||
|
|
||||||
def _attachment_get(self, attachment_id):
|
|
||||||
attachment = request.env['ir.attachment'].sudo().browse(attachment_id)
|
|
||||||
if not attachment:
|
|
||||||
return
|
|
||||||
return attachment.datas
|
|
||||||
|
|
||||||
def stl_to_gltf(binary_stl_path, out_path, is_binary):
|
|
||||||
import struct
|
|
||||||
|
|
||||||
gltf2 = '''
|
|
||||||
{
|
|
||||||
"scenes" : [
|
|
||||||
{
|
|
||||||
"nodes" : [ 0 ]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nodes" : [
|
|
||||||
{
|
|
||||||
"mesh" : 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meshes" : [
|
|
||||||
{
|
|
||||||
"primitives" : [ {
|
|
||||||
"attributes" : {
|
|
||||||
"POSITION" : 1
|
|
||||||
},
|
|
||||||
"indices" : 0
|
|
||||||
} ]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"buffers" : [
|
|
||||||
{
|
|
||||||
%s
|
|
||||||
"byteLength" : %d
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"bufferViews" : [
|
|
||||||
{
|
|
||||||
"buffer" : 0,
|
|
||||||
"byteOffset" : 0,
|
|
||||||
"byteLength" : %d,
|
|
||||||
"target" : 34963
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"buffer" : 0,
|
|
||||||
"byteOffset" : %d,
|
|
||||||
"byteLength" : %d,
|
|
||||||
"target" : 34962
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"accessors" : [
|
|
||||||
{
|
|
||||||
"bufferView" : 0,
|
|
||||||
"byteOffset" : 0,
|
|
||||||
"componentType" : 5125,
|
|
||||||
"count" : %d,
|
|
||||||
"type" : "SCALAR",
|
|
||||||
"max" : [ %d ],
|
|
||||||
"min" : [ 0 ]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"bufferView" : 1,
|
|
||||||
"byteOffset" : 0,
|
|
||||||
"componentType" : 5126,
|
|
||||||
"count" : %d,
|
|
||||||
"type" : "VEC3",
|
|
||||||
"min" : [%f, %f, %f],
|
|
||||||
"max" : [%f, %f, %f]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"asset" : {
|
|
||||||
"version" : "2.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
|
|
||||||
header_bytes = 80
|
|
||||||
unsigned_long_int_bytes = 4
|
|
||||||
float_bytes = 4
|
|
||||||
vec3_bytes = 4 * 3
|
|
||||||
spacer_bytes = 2
|
|
||||||
num_vertices_in_face = 3
|
|
||||||
|
|
||||||
vertices = {}
|
|
||||||
indices = []
|
|
||||||
|
|
||||||
if not is_binary:
|
|
||||||
out_bin = os.path.join(out_path, "out.bin")
|
|
||||||
out_gltf = os.path.join(out_path, "out.gltf")
|
|
||||||
else:
|
|
||||||
out_bin = out_path
|
|
||||||
|
|
||||||
unpack_face = struct.Struct("<12fH").unpack
|
|
||||||
face_bytes = float_bytes * 12 + 2
|
|
||||||
|
|
||||||
with open(path_to_stl, "rb") as f:
|
|
||||||
f.seek(header_bytes) # skip 80 bytes headers
|
|
||||||
|
|
||||||
num_faces_bytes = f.read(unsigned_long_int_bytes)
|
|
||||||
number_faces = struct.unpack("<I", num_faces_bytes)[0]
|
|
||||||
|
|
||||||
# the vec3_bytes is for normal
|
|
||||||
stl_assume_bytes = header_bytes + unsigned_long_int_bytes + number_faces * (
|
|
||||||
vec3_bytes * 3 + spacer_bytes + vec3_bytes)
|
|
||||||
assert stl_assume_bytes == os.path.getsize(path_to_stl), "stl is not binary or ill formatted"
|
|
||||||
|
|
||||||
minx, maxx = [9999999, -9999999]
|
|
||||||
miny, maxy = [9999999, -9999999]
|
|
||||||
minz, maxz = [9999999, -9999999]
|
|
||||||
|
|
||||||
vertices_length_counter = 0
|
|
||||||
|
|
||||||
data = struct.unpack("<" + "12fH" * number_faces, f.read())
|
|
||||||
len_data = len(data)
|
|
||||||
|
|
||||||
for i in range(0, len_data, 13):
|
|
||||||
for j in range(3, 12, 3):
|
|
||||||
x, y, z = data[i + j:i + j + 3]
|
|
||||||
|
|
||||||
x = int(x * 100000) / 100000
|
|
||||||
y = int(y * 100000) / 100000
|
|
||||||
z = int(z * 100000) / 100000
|
|
||||||
|
|
||||||
tuple_xyz = (x, y, z);
|
|
||||||
|
|
||||||
try:
|
|
||||||
indices.append(vertices[tuple_xyz])
|
|
||||||
except KeyError:
|
|
||||||
vertices[tuple_xyz] = vertices_length_counter
|
|
||||||
vertices_length_counter += 1
|
|
||||||
indices.append(vertices[tuple_xyz])
|
|
||||||
|
|
||||||
if x < minx: minx = x
|
|
||||||
if x > maxx: maxx = x
|
|
||||||
if y < miny: miny = y
|
|
||||||
if y > maxy: maxy = y
|
|
||||||
if z < minz: minz = z
|
|
||||||
if z > maxz: maxz = z
|
|
||||||
|
|
||||||
# f.seek(spacer_bytes, 1) # skip the spacer
|
|
||||||
|
|
||||||
number_vertices = len(vertices)
|
|
||||||
vertices_bytelength = number_vertices * vec3_bytes # each vec3 has 3 floats, each float is 4 bytes
|
|
||||||
unpadded_indices_bytelength = number_vertices * unsigned_long_int_bytes
|
|
||||||
|
|
||||||
out_number_vertices = len(vertices)
|
|
||||||
out_number_indices = len(indices)
|
|
||||||
|
|
||||||
unpadded_indices_bytelength = out_number_indices * unsigned_long_int_bytes
|
|
||||||
indices_bytelength = (unpadded_indices_bytelength + 3) & ~3
|
|
||||||
|
|
||||||
out_bin_bytelength = vertices_bytelength + indices_bytelength
|
|
||||||
|
|
||||||
if is_binary:
|
|
||||||
out_bin_uir = ""
|
|
||||||
else:
|
|
||||||
out_bin_uir = '"uri": "out.bin",'
|
|
||||||
|
|
||||||
gltf2 = gltf2 % (out_bin_uir,
|
|
||||||
# buffer
|
|
||||||
out_bin_bytelength,
|
|
||||||
|
|
||||||
# bufferViews[0]
|
|
||||||
indices_bytelength,
|
|
||||||
|
|
||||||
# bufferViews[1]
|
|
||||||
indices_bytelength,
|
|
||||||
vertices_bytelength,
|
|
||||||
|
|
||||||
# accessors[0]
|
|
||||||
out_number_indices,
|
|
||||||
out_number_vertices - 1,
|
|
||||||
|
|
||||||
# accessors[1]
|
|
||||||
out_number_vertices,
|
|
||||||
minx, miny, minz,
|
|
||||||
maxx, maxy, maxz
|
|
||||||
)
|
|
||||||
|
|
||||||
glb_out = bytearray()
|
|
||||||
if is_binary:
|
|
||||||
gltf2 = gltf2.replace(" ", "")
|
|
||||||
gltf2 = gltf2.replace("\n", "")
|
|
||||||
|
|
||||||
scene = bytearray(gltf2.encode())
|
|
||||||
|
|
||||||
scene_len = len(scene)
|
|
||||||
padded_scene_len = (scene_len + 3) & ~3
|
|
||||||
body_offset = padded_scene_len + 12 + 8
|
|
||||||
|
|
||||||
file_len = body_offset + out_bin_bytelength + 8
|
|
||||||
|
|
||||||
# 12-byte header
|
|
||||||
glb_out.extend(struct.pack('<I', 0x46546C67)) # magic number for glTF
|
|
||||||
glb_out.extend(struct.pack('<I', 2))
|
|
||||||
glb_out.extend(struct.pack('<I', file_len))
|
|
||||||
|
|
||||||
# chunk 0
|
|
||||||
glb_out.extend(struct.pack('<I', padded_scene_len))
|
|
||||||
glb_out.extend(struct.pack('<I', 0x4E4F534A)) # magic number for JSON
|
|
||||||
glb_out.extend(scene)
|
|
||||||
|
|
||||||
while len(glb_out) < body_offset:
|
|
||||||
glb_out.extend(b' ')
|
|
||||||
|
|
||||||
# chunk 1
|
|
||||||
glb_out.extend(struct.pack('<I', out_bin_bytelength))
|
|
||||||
glb_out.extend(struct.pack('<I', 0x004E4942)) # magin number for BIN
|
|
||||||
|
|
||||||
# print('<%dI' % len(indices))
|
|
||||||
# print(struct.pack('<%dI' % len(indices), *indices))
|
|
||||||
glb_out.extend(struct.pack('<%dI' % len(indices), *indices))
|
|
||||||
|
|
||||||
for i in range(indices_bytelength - unpadded_indices_bytelength):
|
|
||||||
glb_out.extend(b' ')
|
|
||||||
|
|
||||||
vertices = dict((v, k) for k, v in vertices.items())
|
|
||||||
|
|
||||||
# glb_out.extend(struct.pack('f',
|
|
||||||
# print([each_v for vertices[v_counter] for v_counter in range(number_vertices)]) # magin number for BIN
|
|
||||||
vertices = [vertices[i] for i in range(number_vertices)]
|
|
||||||
flatten = lambda l: [item for sublist in l for item in sublist]
|
|
||||||
|
|
||||||
# for v_counter in :
|
|
||||||
# v_3f = vertices[v_counter]
|
|
||||||
# all_floats_in_vertices.append(v_3f[0])
|
|
||||||
# all_floats_in_vertices.append(v_3f[1])
|
|
||||||
# all_floats_in_vertices.append(v_3f[2])
|
|
||||||
|
|
||||||
# for v_counter in range(number_vertices):
|
|
||||||
glb_out.extend(struct.pack('%df' % number_vertices * 3, *flatten(vertices))) # magin number for BIN
|
|
||||||
|
|
||||||
# for v_counter in range(number_vertices):
|
|
||||||
# glb_out.extend(struct.pack('3f', *vertices[v_counter])) # magin number for BIN
|
|
||||||
|
|
||||||
# for (v_x, v_y, v_z), _ in sorted(vertices.items(), key=lambda x: x[1]):
|
|
||||||
# glb_out.extend(struct.pack('3f', v_x, v_y, v_z)) # magin number for BIN
|
|
||||||
# # glb_out.extend(struct.pack('f', v_y)) # magin number for BIN
|
|
||||||
# # glb_out.extend(struct.pack('f', v_z)) # magin number for BIN
|
|
||||||
|
|
||||||
with open(out_bin, "wb") as out:
|
|
||||||
out.write(glb_out)
|
|
||||||
|
|
||||||
if not is_binary:
|
|
||||||
with open(out_gltf, "w") as out:
|
|
||||||
out.write(gltf2)
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<odoo>
|
|
||||||
<template id="sale.report_saleorder_document" inherit_id="sale.report_saleorder_document">
|
|
||||||
<t t-call="web.external_layout">
|
|
||||||
<h1>hello jacker!</h1>
|
|
||||||
</t>
|
|
||||||
</template>
|
|
||||||
</odoo>
|
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
.o_int_colorpicker {
|
|
||||||
.o_color_pill {
|
|
||||||
display: inline-block;
|
|
||||||
height: 25px;
|
|
||||||
width: 25px;
|
|
||||||
margin: 4px;
|
|
||||||
border-radius: 25px;
|
|
||||||
position: relative;
|
|
||||||
@for $size from 1 through length($o-colors) {
|
|
||||||
&.o_color_#{$size - 1} {
|
|
||||||
background-color: nth($o-colors, $size);
|
|
||||||
&:not(.readonly):hover {
|
|
||||||
transform: scale(1.2);
|
|
||||||
transition: 0.3s;
|
|
||||||
cursor: pointer;
|
|
||||||
}
|
|
||||||
&.active:after{
|
|
||||||
content: "\f00c";
|
|
||||||
display: inline-block;
|
|
||||||
font: normal normal normal 14px/1 FontAwesome;
|
|
||||||
font-size: inherit;
|
|
||||||
color: #fff;
|
|
||||||
position: absolute;
|
|
||||||
padding: 4px;
|
|
||||||
font-size: 16px;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,127 +0,0 @@
|
|||||||
/** @odoo-module **/
|
|
||||||
|
|
||||||
import { registry } from "@web/core/registry";
|
|
||||||
import { _lt } from "@web/core/l10n/translation";
|
|
||||||
import { standardFieldProps } from "@web/views/fields/standard_field_props";
|
|
||||||
import { useInputField } from "@web/views/fields/input_field_hook";
|
|
||||||
import { FileUploader } from "@web/views/fields/file_handler";
|
|
||||||
import { session } from "@web/session";
|
|
||||||
import { useService } from "@web/core/utils/hooks";
|
|
||||||
import { isBinarySize } from "@web/core/utils/binary";
|
|
||||||
import { download } from "@web/core/network/download";
|
|
||||||
import utils from 'web.utils';
|
|
||||||
|
|
||||||
import core from 'web.core';
|
|
||||||
import rpc from 'web.rpc';
|
|
||||||
|
|
||||||
var QWeb = core.qweb;
|
|
||||||
|
|
||||||
import { Component, onWillUpdateProps, useState, useRef, useEffect } from "@odoo/owl";
|
|
||||||
|
|
||||||
export class StepViewer extends Component {
|
|
||||||
setup() {
|
|
||||||
this.notification = useService("notification");
|
|
||||||
this.state = useState({
|
|
||||||
fileName: this.props.record.data[this.props.fileNameField] || "",
|
|
||||||
});
|
|
||||||
onWillUpdateProps((nextProps) => {
|
|
||||||
if (nextProps.readonly) {
|
|
||||||
this.state.fileName = nextProps.record.data[nextProps.fileNameField] || "";
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
this.show_template = useRef('showStepViewer')
|
|
||||||
useInputField({
|
|
||||||
getValue: () => this.props.value || ""
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(
|
|
||||||
(el) => {
|
|
||||||
if (!el) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.formatTemplate($(el));
|
|
||||||
},
|
|
||||||
() => [this.show_template.el],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
formatTemplate($el) {
|
|
||||||
console.log($el)
|
|
||||||
var self=this;
|
|
||||||
if (this.props.readonly && this.props.value) {
|
|
||||||
var url = "/owl_demo/static/src/js/3d_viewer/test.glb";
|
|
||||||
// var session = this.getSession();
|
|
||||||
// if (this.props.value) {
|
|
||||||
// if (utils.is_bin_size(this.props.value)) {
|
|
||||||
// url = session.url("/web/content", {
|
|
||||||
// model: this.model,
|
|
||||||
// id: JSON.stringify(this.props.record.res_id),
|
|
||||||
// field: this.props.record.name,
|
|
||||||
// });
|
|
||||||
// } else {
|
|
||||||
// url = "data:model/gltf-binary;base64," + this.propsvalue.value;
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
return $el.html(QWeb.render("owl_demo.StepViewer",{'url':url}))
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
get fileName() {
|
|
||||||
return this.state.fileName || this.props.value || "";
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
update({ data, name }) {
|
|
||||||
this.state.fileName = name || "";
|
|
||||||
const { fileNameField, record } = this.props;
|
|
||||||
const changes = { [this.props.name]: data || false };
|
|
||||||
if (fileNameField in record.fields && record.data[fileNameField] !== name) {
|
|
||||||
changes[fileNameField] = name || false;
|
|
||||||
}
|
|
||||||
return this.props.record.update(changes);
|
|
||||||
}
|
|
||||||
|
|
||||||
async onFileDownload() {
|
|
||||||
await download({
|
|
||||||
data: {
|
|
||||||
model: this.props.record.resModel,
|
|
||||||
id: this.props.record.resId,
|
|
||||||
field: this.props.name,
|
|
||||||
filename_field: this.fileName,
|
|
||||||
filename: this.fileName || "",
|
|
||||||
download: true,
|
|
||||||
data: isBinarySize(this.props.value) ? null : this.props.value,
|
|
||||||
},
|
|
||||||
url: "/web/content",
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
StepViewer.template = "owl_demo.BinaryField3d";
|
|
||||||
|
|
||||||
StepViewer.displayName = _lt("3D File");
|
|
||||||
StepViewer.supportedTypes = ["binary"];
|
|
||||||
|
|
||||||
StepViewer.components = {
|
|
||||||
FileUploader,
|
|
||||||
};
|
|
||||||
StepViewer.props = {
|
|
||||||
...standardFieldProps,
|
|
||||||
acceptedFileExtensions: { type: String, optional: true },
|
|
||||||
fileNameField: { type: String, optional: true },
|
|
||||||
};
|
|
||||||
StepViewer.defaultProps = {
|
|
||||||
acceptedFileExtensions: "*.stp",
|
|
||||||
};
|
|
||||||
|
|
||||||
StepViewer.extractProps = ({ attrs }) => {
|
|
||||||
return {
|
|
||||||
acceptedFileExtensions: attrs.options.accepted_file_extensions,
|
|
||||||
fileNameField: attrs.filename,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
registry.category("fields").add("Viewer3D", StepViewer);
|
|
||||||
@@ -1,88 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<templates xml:space="preserve">
|
|
||||||
|
|
||||||
<t t-name="owl_demo.BinaryField3d" owl="1">
|
|
||||||
<t t-if="!props.readonly">
|
|
||||||
<t t-if="props.value">
|
|
||||||
<div class="w-100 d-inline-flex">
|
|
||||||
<FileUploader
|
|
||||||
acceptedFileExtensions="props.acceptedFileExtensions"
|
|
||||||
file="{ data: props.value, name: fileName }"
|
|
||||||
onUploaded.bind="update"
|
|
||||||
>
|
|
||||||
<t if="props.record.resId">
|
|
||||||
<button
|
|
||||||
class="btn btn-secondary fa fa-download"
|
|
||||||
data-tooltip="Download"
|
|
||||||
aria-label="Download"
|
|
||||||
t-on-click="onFileDownload"
|
|
||||||
/>
|
|
||||||
</t>
|
|
||||||
<t t-set-slot="toggler">
|
|
||||||
<input type="text" class="o_input" t-att-value="fileName" readonly="readonly" />
|
|
||||||
<button
|
|
||||||
class="btn btn-secondary fa fa-pencil o_select_file_button"
|
|
||||||
data-tooltip="Edit"
|
|
||||||
aria-label="Edit"
|
|
||||||
/>
|
|
||||||
</t>
|
|
||||||
<button
|
|
||||||
class="btn btn-secondary fa fa-trash o_clear_file_button"
|
|
||||||
data-tooltip="Clear"
|
|
||||||
aria-label="Clear"
|
|
||||||
t-on-click="() => this.update({})"
|
|
||||||
/>
|
|
||||||
</FileUploader>
|
|
||||||
</div>
|
|
||||||
</t>
|
|
||||||
<t t-else="">
|
|
||||||
<label class="o_select_file_button btn btn-primary">
|
|
||||||
<FileUploader
|
|
||||||
acceptedFileExtensions="props.acceptedFileExtensions"
|
|
||||||
onUploaded.bind="update"
|
|
||||||
>
|
|
||||||
<t t-set-slot="toggler">
|
|
||||||
Upload your file
|
|
||||||
</t>
|
|
||||||
</FileUploader>
|
|
||||||
</label>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
<t t-elif="props.record.resId and props.value">
|
|
||||||
<!-- <div t-ref="showStepViewer"/>-->
|
|
||||||
<model-viewer urc="/owl_demo/static/src/js/3d_viewer/test.glb" ar-modes="scene-viewer webxr quick-look" poster="poster.webp" shadow-intensity="1" camera-orbit="180deg 72.29deg 12640m" field-of-view="30deg">
|
|
||||||
<div class="progress-bar hide" slot="progress-bar">
|
|
||||||
<div class="update-bar"></div>
|
|
||||||
</div>
|
|
||||||
</model-viewer>
|
|
||||||
</t>
|
|
||||||
</t>
|
|
||||||
|
|
||||||
<t t-name="owl_demo.StepViewer">
|
|
||||||
<model-viewer
|
|
||||||
t-att-src='url'
|
|
||||||
name="3D model"
|
|
||||||
alt="3D model"
|
|
||||||
auto-rotate="1"
|
|
||||||
camera-controls="1"
|
|
||||||
>
|
|
||||||
<div class="text-center mt-4 mb-4 mr-4">
|
|
||||||
<span
|
|
||||||
id="model-viewer-fullscreen"
|
|
||||||
title="View fullscreen"
|
|
||||||
role="img"
|
|
||||||
aria-label="Fullscreen"
|
|
||||||
>
|
|
||||||
<i class="fa fa-arrows-alt fa-2x" />
|
|
||||||
</span>
|
|
||||||
</div>
|
|
||||||
<!-- <span style="position: absolute;top: 85%;left: 0%;font-size: 9px;" t-if="widget.model == 'jikimo.process.order.line'">-->
|
|
||||||
<!-- L:<t t-esc="widget.recordData.model_length"/>,-->
|
|
||||||
<!-- W:<t t-esc="widget.recordData.model_width"/>,-->
|
|
||||||
<!-- H:<t t-esc="widget.recordData.model_height"/>,-->
|
|
||||||
<!-- V:<t t-esc="widget.recordData.model_volume"/>-->
|
|
||||||
<!-- </span>-->
|
|
||||||
</model-viewer>
|
|
||||||
</t>
|
|
||||||
|
|
||||||
</templates>
|
|
||||||
@@ -1,277 +0,0 @@
|
|||||||
import os
|
|
||||||
|
|
||||||
def stl_to_gltf(binary_stl_path, out_path, is_binary):
|
|
||||||
import struct
|
|
||||||
|
|
||||||
gltf2 = '''
|
|
||||||
{
|
|
||||||
"scenes" : [
|
|
||||||
{
|
|
||||||
"nodes" : [ 0 ]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"nodes" : [
|
|
||||||
{
|
|
||||||
"mesh" : 0
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"meshes" : [
|
|
||||||
{
|
|
||||||
"primitives" : [ {
|
|
||||||
"attributes" : {
|
|
||||||
"POSITION" : 1
|
|
||||||
},
|
|
||||||
"indices" : 0
|
|
||||||
} ]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"buffers" : [
|
|
||||||
{
|
|
||||||
%s
|
|
||||||
"byteLength" : %d
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"bufferViews" : [
|
|
||||||
{
|
|
||||||
"buffer" : 0,
|
|
||||||
"byteOffset" : 0,
|
|
||||||
"byteLength" : %d,
|
|
||||||
"target" : 34963
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"buffer" : 0,
|
|
||||||
"byteOffset" : %d,
|
|
||||||
"byteLength" : %d,
|
|
||||||
"target" : 34962
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"accessors" : [
|
|
||||||
{
|
|
||||||
"bufferView" : 0,
|
|
||||||
"byteOffset" : 0,
|
|
||||||
"componentType" : 5125,
|
|
||||||
"count" : %d,
|
|
||||||
"type" : "SCALAR",
|
|
||||||
"max" : [ %d ],
|
|
||||||
"min" : [ 0 ]
|
|
||||||
},
|
|
||||||
{
|
|
||||||
"bufferView" : 1,
|
|
||||||
"byteOffset" : 0,
|
|
||||||
"componentType" : 5126,
|
|
||||||
"count" : %d,
|
|
||||||
"type" : "VEC3",
|
|
||||||
"min" : [%f, %f, %f],
|
|
||||||
"max" : [%f, %f, %f]
|
|
||||||
}
|
|
||||||
],
|
|
||||||
"asset" : {
|
|
||||||
"version" : "2.0"
|
|
||||||
}
|
|
||||||
}
|
|
||||||
'''
|
|
||||||
|
|
||||||
header_bytes = 80
|
|
||||||
unsigned_long_int_bytes = 4
|
|
||||||
float_bytes = 4
|
|
||||||
vec3_bytes = 4 * 3
|
|
||||||
spacer_bytes = 2
|
|
||||||
num_vertices_in_face = 3
|
|
||||||
|
|
||||||
vertices = {}
|
|
||||||
indices = []
|
|
||||||
|
|
||||||
if not is_binary:
|
|
||||||
out_bin = os.path.join(out_path, "out.bin")
|
|
||||||
out_gltf = os.path.join(out_path, "out.gltf")
|
|
||||||
else:
|
|
||||||
out_bin = out_path
|
|
||||||
|
|
||||||
unpack_face = struct.Struct("<12fH").unpack
|
|
||||||
face_bytes = float_bytes*12 + 2
|
|
||||||
|
|
||||||
with open(path_to_stl, "rb") as f:
|
|
||||||
f.seek(header_bytes) # skip 80 bytes headers
|
|
||||||
|
|
||||||
num_faces_bytes = f.read(unsigned_long_int_bytes)
|
|
||||||
number_faces = struct.unpack("<I", num_faces_bytes)[0]
|
|
||||||
|
|
||||||
# the vec3_bytes is for normal
|
|
||||||
stl_assume_bytes = header_bytes + unsigned_long_int_bytes + number_faces * (vec3_bytes*3 + spacer_bytes + vec3_bytes)
|
|
||||||
assert stl_assume_bytes == os.path.getsize(path_to_stl), "stl is not binary or ill formatted"
|
|
||||||
|
|
||||||
minx, maxx = [9999999, -9999999]
|
|
||||||
miny, maxy = [9999999, -9999999]
|
|
||||||
minz, maxz = [9999999, -9999999]
|
|
||||||
|
|
||||||
vertices_length_counter = 0
|
|
||||||
|
|
||||||
data = struct.unpack("<" + "12fH"*number_faces, f.read())
|
|
||||||
len_data = len(data)
|
|
||||||
|
|
||||||
for i in range(0, len_data, 13):
|
|
||||||
for j in range(3, 12, 3):
|
|
||||||
x, y, z = data[i+j:i+j+3]
|
|
||||||
|
|
||||||
x = int(x*100000)/100000
|
|
||||||
y = int(y*100000)/100000
|
|
||||||
z = int(z*100000)/100000
|
|
||||||
|
|
||||||
tuple_xyz = (x, y, z);
|
|
||||||
|
|
||||||
try:
|
|
||||||
indices.append(vertices[tuple_xyz])
|
|
||||||
except KeyError:
|
|
||||||
vertices[tuple_xyz] = vertices_length_counter
|
|
||||||
vertices_length_counter += 1
|
|
||||||
indices.append(vertices[tuple_xyz])
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
if x < minx: minx = x
|
|
||||||
if x > maxx: maxx = x
|
|
||||||
if y < miny: miny = y
|
|
||||||
if y > maxy: maxy = y
|
|
||||||
if z < minz: minz = z
|
|
||||||
if z > maxz: maxz = z
|
|
||||||
|
|
||||||
# f.seek(spacer_bytes, 1) # skip the spacer
|
|
||||||
|
|
||||||
number_vertices = len(vertices)
|
|
||||||
vertices_bytelength = number_vertices * vec3_bytes # each vec3 has 3 floats, each float is 4 bytes
|
|
||||||
unpadded_indices_bytelength = number_vertices * unsigned_long_int_bytes
|
|
||||||
|
|
||||||
out_number_vertices = len(vertices)
|
|
||||||
out_number_indices = len(indices)
|
|
||||||
|
|
||||||
unpadded_indices_bytelength = out_number_indices * unsigned_long_int_bytes
|
|
||||||
indices_bytelength = (unpadded_indices_bytelength + 3) & ~3
|
|
||||||
|
|
||||||
out_bin_bytelength = vertices_bytelength + indices_bytelength
|
|
||||||
|
|
||||||
if is_binary:
|
|
||||||
out_bin_uir = ""
|
|
||||||
else:
|
|
||||||
out_bin_uir = '"uri": "out.bin",'
|
|
||||||
|
|
||||||
gltf2 = gltf2 % ( out_bin_uir,
|
|
||||||
#buffer
|
|
||||||
out_bin_bytelength,
|
|
||||||
|
|
||||||
# bufferViews[0]
|
|
||||||
indices_bytelength,
|
|
||||||
|
|
||||||
# bufferViews[1]
|
|
||||||
indices_bytelength,
|
|
||||||
vertices_bytelength,
|
|
||||||
|
|
||||||
# accessors[0]
|
|
||||||
out_number_indices,
|
|
||||||
out_number_vertices - 1,
|
|
||||||
|
|
||||||
# accessors[1]
|
|
||||||
out_number_vertices,
|
|
||||||
minx, miny, minz,
|
|
||||||
maxx, maxy, maxz
|
|
||||||
)
|
|
||||||
|
|
||||||
glb_out = bytearray()
|
|
||||||
if is_binary:
|
|
||||||
gltf2 = gltf2.replace(" ", "")
|
|
||||||
gltf2 = gltf2.replace("\n", "")
|
|
||||||
|
|
||||||
scene = bytearray(gltf2.encode())
|
|
||||||
|
|
||||||
scene_len = len(scene)
|
|
||||||
padded_scene_len = (scene_len + 3) & ~3
|
|
||||||
body_offset = padded_scene_len + 12 + 8
|
|
||||||
|
|
||||||
file_len = body_offset + out_bin_bytelength + 8
|
|
||||||
|
|
||||||
# 12-byte header
|
|
||||||
glb_out.extend(struct.pack('<I', 0x46546C67)) # magic number for glTF
|
|
||||||
glb_out.extend(struct.pack('<I', 2))
|
|
||||||
glb_out.extend(struct.pack('<I', file_len))
|
|
||||||
|
|
||||||
# chunk 0
|
|
||||||
glb_out.extend(struct.pack('<I', padded_scene_len))
|
|
||||||
glb_out.extend(struct.pack('<I', 0x4E4F534A)) # magic number for JSON
|
|
||||||
glb_out.extend(scene)
|
|
||||||
|
|
||||||
while len(glb_out) < body_offset:
|
|
||||||
glb_out.extend(b' ')
|
|
||||||
|
|
||||||
# chunk 1
|
|
||||||
glb_out.extend(struct.pack('<I', out_bin_bytelength))
|
|
||||||
glb_out.extend(struct.pack('<I', 0x004E4942)) # magin number for BIN
|
|
||||||
|
|
||||||
# print('<%dI' % len(indices))
|
|
||||||
# print(struct.pack('<%dI' % len(indices), *indices))
|
|
||||||
glb_out.extend(struct.pack('<%dI' % len(indices), *indices))
|
|
||||||
|
|
||||||
for i in range(indices_bytelength - unpadded_indices_bytelength):
|
|
||||||
glb_out.extend(b' ')
|
|
||||||
|
|
||||||
vertices = dict((v, k) for k,v in vertices.items())
|
|
||||||
|
|
||||||
# glb_out.extend(struct.pack('f',
|
|
||||||
# print([each_v for vertices[v_counter] for v_counter in range(number_vertices)]) # magin number for BIN
|
|
||||||
vertices = [vertices[i] for i in range(number_vertices)]
|
|
||||||
flatten = lambda l: [item for sublist in l for item in sublist]
|
|
||||||
|
|
||||||
# for v_counter in :
|
|
||||||
# v_3f = vertices[v_counter]
|
|
||||||
# all_floats_in_vertices.append(v_3f[0])
|
|
||||||
# all_floats_in_vertices.append(v_3f[1])
|
|
||||||
# all_floats_in_vertices.append(v_3f[2])
|
|
||||||
|
|
||||||
# for v_counter in range(number_vertices):
|
|
||||||
glb_out.extend(struct.pack('%df' % number_vertices*3, *flatten(vertices))) # magin number for BIN
|
|
||||||
|
|
||||||
# for v_counter in range(number_vertices):
|
|
||||||
# glb_out.extend(struct.pack('3f', *vertices[v_counter])) # magin number for BIN
|
|
||||||
|
|
||||||
# for (v_x, v_y, v_z), _ in sorted(vertices.items(), key=lambda x: x[1]):
|
|
||||||
# glb_out.extend(struct.pack('3f', v_x, v_y, v_z)) # magin number for BIN
|
|
||||||
# # glb_out.extend(struct.pack('f', v_y)) # magin number for BIN
|
|
||||||
# # glb_out.extend(struct.pack('f', v_z)) # magin number for BIN
|
|
||||||
|
|
||||||
with open(out_bin, "wb") as out:
|
|
||||||
out.write(glb_out)
|
|
||||||
|
|
||||||
if not is_binary:
|
|
||||||
with open(out_gltf, "w") as out:
|
|
||||||
out.write(gltf2)
|
|
||||||
|
|
||||||
print("Done! Exported to %s" %out_path)
|
|
||||||
|
|
||||||
if __name__ == '__main__':
|
|
||||||
import sys
|
|
||||||
|
|
||||||
if len(sys.argv) < 3:
|
|
||||||
print("use it like python3 stl_to_gltf.py /path/to/stl /path/to/gltf/folder")
|
|
||||||
print("or python3 stl_to_gltf.py /path/to/stl /path/to/glb/file -b")
|
|
||||||
sys.exit(1)
|
|
||||||
|
|
||||||
path_to_stl = sys.argv[1]
|
|
||||||
out_path = sys.argv[2]
|
|
||||||
if len(sys.argv) > 3:
|
|
||||||
is_binary = True
|
|
||||||
else:
|
|
||||||
is_binary = False
|
|
||||||
|
|
||||||
if out_path.lower().endswith(".glb"):
|
|
||||||
print("Use binary mode since output file has glb extension")
|
|
||||||
is_binary = True
|
|
||||||
else:
|
|
||||||
if is_binary:
|
|
||||||
print("output file should have glb extension but not %s", out_path)
|
|
||||||
|
|
||||||
if not os.path.exists(path_to_stl):
|
|
||||||
print("stl file does not exists %s" % path_to_stl)
|
|
||||||
|
|
||||||
if not is_binary:
|
|
||||||
if not os.path.isdir(out_path):
|
|
||||||
os.mkdir(out_path)
|
|
||||||
|
|
||||||
stl_to_gltf(path_to_stl, out_path, is_binary)
|
|
||||||
Binary file not shown.
@@ -1,25 +0,0 @@
|
|||||||
/** @odoo-module **/
|
|
||||||
|
|
||||||
const { Component, useState, mount, whenReady, xml } = owl;
|
|
||||||
|
|
||||||
export class MyComponent extends Component {
|
|
||||||
static template = 'owl_demo.my_component'
|
|
||||||
|
|
||||||
|
|
||||||
setup() {
|
|
||||||
this.state = useState({ is_show:true});
|
|
||||||
}
|
|
||||||
|
|
||||||
onRemove(ev) {
|
|
||||||
this.state.is_show = false;
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
//MyComponent.template = 'owl_demo.MyComponent';
|
|
||||||
|
|
||||||
whenReady(() => {
|
|
||||||
var my_component = new MyComponent();
|
|
||||||
mount(my_component, document.body);
|
|
||||||
//$("#myModal").modal('show');
|
|
||||||
});
|
|
||||||
@@ -1,84 +0,0 @@
|
|||||||
/** @odoo-module **/
|
|
||||||
|
|
||||||
const { Component, useState, mount, xml } = owl;
|
|
||||||
|
|
||||||
import { registry } from "@web/core/registry";
|
|
||||||
import { formView } from "@web/views/form/form_view";
|
|
||||||
import { FormCompiler } from "@web/views/form/form_compiler";
|
|
||||||
import { FormRenderer } from '@web/views/form/form_renderer';
|
|
||||||
|
|
||||||
class PartnerOrderSummary extends Component {
|
|
||||||
partner = useState({});
|
|
||||||
constructor(self, partner) {
|
|
||||||
super();
|
|
||||||
this.partner = partner;
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
PartnerOrderSummary.template = "owl_demo.PartnerOrderSummary";
|
|
||||||
|
|
||||||
|
|
||||||
function compilePartner(el, params) {
|
|
||||||
// this._rpc({
|
|
||||||
// model: "res.partner",
|
|
||||||
// method: "read",
|
|
||||||
// args: [[this.state.data.partner_id.res_id]]
|
|
||||||
// }).then(data => {
|
|
||||||
// (new ComponentWrapper(this,
|
|
||||||
// PartnerOrderSummary,
|
|
||||||
// useState(data[0])
|
|
||||||
// )).mount(element);
|
|
||||||
// });
|
|
||||||
|
|
||||||
return "<h1>hello world</h1>";
|
|
||||||
}
|
|
||||||
|
|
||||||
function compileForm() {
|
|
||||||
const res = this.compileForm(...arguments);
|
|
||||||
res.classList.append("test111");
|
|
||||||
return res;
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SaleOrderFormCompiler extends FormCompiler {
|
|
||||||
setup() {
|
|
||||||
super.setup();
|
|
||||||
this.compilers.unshift(
|
|
||||||
{ selector: "form", fn: compileForm },
|
|
||||||
{ selector: "div .o_partner_order_summary", fn: compilePartner }
|
|
||||||
);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
export class SaleOrderFormRenderer extends FormRenderer { }
|
|
||||||
|
|
||||||
SaleOrderFormRenderer.components = {
|
|
||||||
...FormRenderer.components,
|
|
||||||
PartnerOrderSummary,
|
|
||||||
};
|
|
||||||
|
|
||||||
registry.category('views').add('sale.view_order_form', {
|
|
||||||
...formView,
|
|
||||||
Compiler: SaleOrderFormCompiler,
|
|
||||||
Renderer: SaleOrderFormRenderer,
|
|
||||||
});
|
|
||||||
|
|
||||||
|
|
||||||
/*** 重载表单渲染器,对任何包含o_partner_order_summary这一class 的div挂载当前组件 */
|
|
||||||
//FormRenderer.include({
|
|
||||||
// _render: async function() {
|
|
||||||
// await this._super(...arguments);
|
|
||||||
// for (const element of this.el.querySelectorAll(".o_partner_order_summary")) {
|
|
||||||
// this._rpc({
|
|
||||||
// model: "res.partner",
|
|
||||||
// method: "read",
|
|
||||||
// args: [[this.state.data.partner_id.res_id]]
|
|
||||||
// }).then(data => {
|
|
||||||
// (new ComponentWrapper(this,
|
|
||||||
// PartnerOrderSummary,
|
|
||||||
// useState(data[0])
|
|
||||||
// )).mount(element);
|
|
||||||
// });
|
|
||||||
// }
|
|
||||||
// }
|
|
||||||
//});
|
|
||||||
|
|
||||||
@@ -1,64 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<templates xml:space="preserve">
|
|
||||||
|
|
||||||
<t t-name="owl_demo.field_team_id">
|
|
||||||
<ul class="list-group">
|
|
||||||
<li class="list-group-item active">Cras justo odio</li>
|
|
||||||
<li class="list-group-item">Dapibus ac facilisis in</li>
|
|
||||||
<li class="list-group-item">Morbi leo risus</li>
|
|
||||||
<li class="list-group-item">Porta ac consectetur ac</li>
|
|
||||||
<li class="list-group-item">Vestibulum at eros</li>
|
|
||||||
</ul>
|
|
||||||
</t>
|
|
||||||
<!-- 不要加 owl="1" -->
|
|
||||||
<t t-name="owl_demo.field_order_line">
|
|
||||||
<!-- <t t-foreach="current_field" t-as="order_line">-->
|
|
||||||
<!-- <h6><t t-out="order_line.name"/>-->
|
|
||||||
<!-- <span class="badge rounded-pill dropdown o_tag o_tag_color_7"><t t-out="order_line.product_uom_qty"/></span></h6>-->
|
|
||||||
<!-- -->
|
|
||||||
<!-- </t>-->
|
|
||||||
|
|
||||||
<table class="table table-bordered">
|
|
||||||
<!-- <thead>-->
|
|
||||||
<!-- <tr>-->
|
|
||||||
<!-- <th scope="col">#</th>-->
|
|
||||||
<!-- <th scope="col">product</th>-->
|
|
||||||
<!-- <th scope="col">qty</th>-->
|
|
||||||
<!-- <th scope="col">subtotal</th>-->
|
|
||||||
<!-- </tr>-->
|
|
||||||
<!-- </thead>-->
|
|
||||||
<tbody>
|
|
||||||
<t t-set="index" t-value="1"/>
|
|
||||||
<t t-foreach="current_field" t-as="order_line">
|
|
||||||
<tr class="o_tag o_tag_color_{{index}}">
|
|
||||||
<th scope="row"><t t-out="index"/></th>
|
|
||||||
<td><t t-out="order_line.name.substr(0,20)"/></td>
|
|
||||||
<td><t t-out="order_line.product_uom_qty"/></td>
|
|
||||||
<td><t t-out="order_line.price_subtotal"/></td>
|
|
||||||
</tr>
|
|
||||||
<t t-set="index" t-value="index+1"/>
|
|
||||||
</t>
|
|
||||||
</tbody>
|
|
||||||
</table>
|
|
||||||
</t>
|
|
||||||
|
|
||||||
<t t-name="owl_demo.field_partner_id">
|
|
||||||
<h5><t t-out="current_field.name"/></h5>
|
|
||||||
|
|
||||||
|
|
||||||
<span class="badge rounded-pill dropdown o_tag o_tag_color_3"><t t-out="current_field.phone"/></span>
|
|
||||||
</t>
|
|
||||||
|
|
||||||
<!-- <t t-name="owl_demo.field_order_line">-->
|
|
||||||
<!--<!– <h3><t t-out="record.data.name"/></h3>–>-->
|
|
||||||
<!-- <ul class="list-group">-->
|
|
||||||
<!-- <t t-foreach="record.data.order_line.records" t-as="order_line">-->
|
|
||||||
<!-- <li class="list-group-item d-flex justify-content-between align-items-center">-->
|
|
||||||
<!-- <t t-out="order_line.id"/>-->
|
|
||||||
<!-- <span class="badge rounded-pill">14</span>-->
|
|
||||||
<!-- </li>-->
|
|
||||||
<!-- </t>-->
|
|
||||||
<!-- </ul>-->
|
|
||||||
<!-- </t>-->
|
|
||||||
|
|
||||||
</templates>
|
|
||||||
@@ -1,97 +0,0 @@
|
|||||||
/** @odoo-module **/
|
|
||||||
|
|
||||||
import { registry } from "@web/core/registry";
|
|
||||||
import { _lt } from "@web/core/l10n/translation";
|
|
||||||
import { standardFieldProps } from "@web/views/fields/standard_field_props";
|
|
||||||
import { useInputField } from "@web/views/fields/input_field_hook";
|
|
||||||
import { session } from "@web/session";
|
|
||||||
import core from 'web.core';
|
|
||||||
import rpc from 'web.rpc';
|
|
||||||
|
|
||||||
var QWeb = core.qweb;
|
|
||||||
|
|
||||||
import { Component,useRef,useEffect } from "@odoo/owl";
|
|
||||||
|
|
||||||
export class CTemplateField extends Component {
|
|
||||||
setup() {
|
|
||||||
this.show_template = useRef('showTemplate')
|
|
||||||
useInputField({
|
|
||||||
getValue: () => this.props.value || ""
|
|
||||||
});
|
|
||||||
|
|
||||||
useEffect(
|
|
||||||
(el) => {
|
|
||||||
if (!el) {
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
return this.formatTemplate($(el));
|
|
||||||
},
|
|
||||||
() => [this.show_template.el],
|
|
||||||
)
|
|
||||||
}
|
|
||||||
|
|
||||||
formatTemplate($el) {
|
|
||||||
console.log($el)
|
|
||||||
var self=this;
|
|
||||||
if (this.props.readonly && this.props.value) {
|
|
||||||
//value = this.props.value + ' | ' + this.props.template_xml_id;
|
|
||||||
if (this.props.type == 'one2many' || this.props.type == 'many2many'){
|
|
||||||
// 如果是one2many或many2many,就重新获取对象列表
|
|
||||||
rpc.query({
|
|
||||||
model: this.props.value.resModel,
|
|
||||||
method: 'read',
|
|
||||||
args: [this.props.value.currentIds,[]],
|
|
||||||
}).then((result) => {
|
|
||||||
console.log(result);
|
|
||||||
return $el.html(QWeb.render(this.props.template_xml_id,{'record':this.props.record,'current_field':result}))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else if (this.props.type == 'many2one'){
|
|
||||||
// 如果是one2many或many2many,就重新获取对象列表
|
|
||||||
rpc.query({
|
|
||||||
model: this.props.record.fields[this.props.name].relation,
|
|
||||||
method: 'read',
|
|
||||||
args: [this.props.value[0],[]],
|
|
||||||
}).then((result) => {
|
|
||||||
console.log(result);
|
|
||||||
return $el.html(QWeb.render(this.props.template_xml_id,{'record':this.props.record,'current_field':result[0]}))
|
|
||||||
});
|
|
||||||
}
|
|
||||||
else{
|
|
||||||
if (this.props.template_xml_id === undefined)
|
|
||||||
{
|
|
||||||
return $el.html(this.props.value);
|
|
||||||
}else{
|
|
||||||
return $el.html(QWeb.render(this.props.template_xml_id,{'record':this.props.record,'current_field':this.props.value}));
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
|
||||||
}
|
|
||||||
|
|
||||||
}
|
|
||||||
|
|
||||||
CTemplateField.template = "owl_demo.CTemplateField";
|
|
||||||
CTemplateField.props = {
|
|
||||||
...standardFieldProps,
|
|
||||||
template_xml_id: { type: String, optional: true },
|
|
||||||
placeholder: { type: String, optional: true },
|
|
||||||
};
|
|
||||||
CTemplateField.defaultProps = {
|
|
||||||
// hideSymbol: false,
|
|
||||||
// inputType: "text",
|
|
||||||
};
|
|
||||||
|
|
||||||
CTemplateField.supportedTypes = ["many2one","char"];
|
|
||||||
CTemplateField.displayName = _lt("CTemplate");
|
|
||||||
|
|
||||||
CTemplateField.extractProps = ({ attrs }) => {
|
|
||||||
return {
|
|
||||||
template_xml_id: attrs.options.template,
|
|
||||||
placeholder: attrs.placeholder,
|
|
||||||
};
|
|
||||||
};
|
|
||||||
|
|
||||||
registry.category("fields").add("CTemplate", CTemplateField);
|
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
.o_field_widget.o_field_template {
|
|
||||||
display: block;
|
|
||||||
}
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<templates xml:space="preserve">
|
|
||||||
|
|
||||||
<t t-name="owl_demo.CTemplateField" owl="1">
|
|
||||||
<div t-ref="showTemplate"/>
|
|
||||||
</t>
|
|
||||||
|
|
||||||
</templates>
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
/** @odoo-module **/
|
|
||||||
|
|
||||||
import { registry } from "@web/core/registry";
|
|
||||||
|
|
||||||
const serviceRegistry = registry.category("services");
|
|
||||||
|
|
||||||
const myService = {
|
|
||||||
dependencies: ["notification","title","effect"],
|
|
||||||
start(env, { notification, title,effect }) {
|
|
||||||
|
|
||||||
// let counter = 1;
|
|
||||||
// setInterval(() => {
|
|
||||||
// var tik_str = `Tick Tock ${counter++}`;
|
|
||||||
// notification.add(tik_str);
|
|
||||||
// title.setParts({ odoo: tik_str, fruit: tik_str });
|
|
||||||
// effect.add({
|
|
||||||
// type: "rainbow_man", // can be omitted, default type is already "rainbow_man"
|
|
||||||
// message: "Boom! Team record for the past 30 days." + tik_str,
|
|
||||||
// });
|
|
||||||
// }, 5000);
|
|
||||||
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
serviceRegistry.add("myService", myService);
|
|
||||||
@@ -1,50 +0,0 @@
|
|||||||
/** @odoo-module **/
|
|
||||||
|
|
||||||
import AbstractField from 'web.AbstractField';
|
|
||||||
import fieldRegistry from 'web.field_registry';
|
|
||||||
|
|
||||||
export const ShowUnitsWidgetField = AbstractField.extend({
|
|
||||||
supportedFieldTypes: ['float','char','datetime'],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
// init: function () {
|
|
||||||
// this._super.apply(this, arguments);
|
|
||||||
// this.units = this.nodeOptions && this.nodeOptions.units || '';
|
|
||||||
// },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
_renderReadonly() {
|
|
||||||
this.units = this.nodeOptions && this.nodeOptions.units || '';
|
|
||||||
this.$el.empty().html(this._formatValue(this.value) + " <b>"+this.units+"</b>");
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
fieldRegistry.add('show_units', ShowUnitsWidgetField);
|
|
||||||
|
|
||||||
export const ShowUnitsWidgetField = AbstractField.extend({
|
|
||||||
supportedFieldTypes: ['float','char','datetime'],
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
// init: function () {
|
|
||||||
// this._super.apply(this, arguments);
|
|
||||||
// this.units = this.nodeOptions && this.nodeOptions.units || '';
|
|
||||||
// },
|
|
||||||
|
|
||||||
/**
|
|
||||||
* @override
|
|
||||||
*/
|
|
||||||
_renderReadonly() {
|
|
||||||
this.units = this.nodeOptions && this.nodeOptions.units || '';
|
|
||||||
this.$el.empty().html(this._formatValue(this.value) + " <b>"+this.units+"</b>");
|
|
||||||
},
|
|
||||||
|
|
||||||
});
|
|
||||||
|
|
||||||
fieldRegistry.add('show_units', ShowUnitsWidgetField);
|
|
||||||
@@ -1,10 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<templates xml:space="preserve">
|
|
||||||
|
|
||||||
<t t-name="owl_demo.my_component">
|
|
||||||
<div t-on-click="increment">
|
|
||||||
<t t-esc="state.value"/>
|
|
||||||
</div>
|
|
||||||
</t>
|
|
||||||
|
|
||||||
</templates>
|
|
||||||
@@ -1,4 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8" ?>
|
|
||||||
<templates>
|
|
||||||
|
|
||||||
</templates>
|
|
||||||
@@ -1,36 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<templates xml:space="preserve">
|
|
||||||
<t t-name="owl_demo.PartnerOrderSummary" owl="1">
|
|
||||||
<div class="center"
|
|
||||||
style="width: 100%; text-align: center; border: 1px solid #cecece; padding: 2rem 20%; margin: 12px 0;">
|
|
||||||
<img
|
|
||||||
t-attf-src="data:image/jpg;base64,{{partner.image_256}}"
|
|
||||||
width="75px"
|
|
||||||
height="75px"
|
|
||||||
style="background-color: #ccc; border-radius: 50%; margin-bottom: 10px;"/>
|
|
||||||
<!-- Customer name -->
|
|
||||||
<p style="font-size: 16px; color: #4d4b4b;"><strong t-esc="partner.name"/></p>
|
|
||||||
<!-- Address -->
|
|
||||||
<p style="font-size: 12px; color: #8c8787;">
|
|
||||||
<i class="fa fa-map-marker" style="padding-right: 4px;"/>
|
|
||||||
<span t-esc="partner.city"/>
|
|
||||||
<span t-esc="partner.zip" style="margin-left: 5px;"/>
|
|
||||||
</p>
|
|
||||||
<!-- Grid of previous order stats -->
|
|
||||||
<div class="row" style="padding-top: 20px;">
|
|
||||||
<div class="col-6" style="border-right: 1px solid #ccc;">
|
|
||||||
<p style="font-size: 20px;">
|
|
||||||
<strong t-esc="partner.sale_order_count"/>
|
|
||||||
</p>
|
|
||||||
<p style="font-size: 12px; color: #8c8787;">Orders</p>
|
|
||||||
</div>
|
|
||||||
<div class="col-6">
|
|
||||||
<p style="font-size: 20px;">
|
|
||||||
<strong t-esc="partner.total_invoiced" t-options='{"widget": "monetary"}'/>
|
|
||||||
</p>
|
|
||||||
<p style="font-size: 12px; color: #8c8787;">Total Sales</p>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</div>
|
|
||||||
</t>
|
|
||||||
</templates>
|
|
||||||
43
requirements.txt
Normal file
43
requirements.txt
Normal file
@@ -0,0 +1,43 @@
|
|||||||
|
Babel==2.9.1 # min version = 2.6.0 (Focal with security backports)
|
||||||
|
chardet==3.0.4
|
||||||
|
cryptography==3.4.8
|
||||||
|
decorator==4.4.2
|
||||||
|
docutils==0.16
|
||||||
|
ebaysdk==2.1.5
|
||||||
|
freezegun==0.3.15; python_version >= '3.8'
|
||||||
|
gevent==1.5.0 ; python_version == '3.7'
|
||||||
|
gevent==21.8.0 ; python_version > '3.9' # (Jammy)
|
||||||
|
greenlet==1.1.2 ; python_version > '3.9' # (Jammy)
|
||||||
|
idna==2.8
|
||||||
|
Jinja2==2.11.3 # min version = 2.10.1 (Focal - with security backports)
|
||||||
|
libsass==0.18.0
|
||||||
|
lxml==4.6.5 # min version = 4.5.0 (Focal - with security backports)
|
||||||
|
MarkupSafe==1.1.0
|
||||||
|
num2words==0.5.6
|
||||||
|
ofxparse==0.21; python_version > '3.9' # (Jammy)
|
||||||
|
passlib==1.7.3 # min version = 1.7.2 (Focal with security backports)
|
||||||
|
Pillow==9.0.1 # min version = 7.0.0 (Focal with security backports)
|
||||||
|
polib==1.1.0
|
||||||
|
psutil==5.6.7 # min version = 5.5.1 (Focal with security backports)
|
||||||
|
psycopg2==2.8.6; sys_platform == 'win32' or python_version >= '3.8'
|
||||||
|
pydot==1.4.1
|
||||||
|
pyopenssl==19.0.0
|
||||||
|
PyPDF2==1.26.0
|
||||||
|
pypiwin32 ; sys_platform == 'win32'
|
||||||
|
pyserial==3.4
|
||||||
|
python-dateutil==2.7.3
|
||||||
|
python-ldap==3.4.0 ; sys_platform != 'win32' # min version = 3.2.0 (Focal with security backports)
|
||||||
|
python-stdnum==1.13
|
||||||
|
pytz==2019.3
|
||||||
|
pyusb==1.0.2
|
||||||
|
qrcode==6.1
|
||||||
|
reportlab==3.5.59 # version < 3.5.54 are not compatible with Pillow 8.1.2 and 3.5.59 is bullseye
|
||||||
|
requests==2.25.1 # versions < 2.25 aren't compatible w/ urllib3 1.26. Bullseye = 2.25.1. min version = 2.22.0 (Focal)
|
||||||
|
urllib3==1.26.5 # indirect / min version = 1.25.8 (Focal with security backports)
|
||||||
|
vobject==0.9.6.1
|
||||||
|
Werkzeug==0.16.1 ; python_version <= '3.9'
|
||||||
|
Werkzeug==2.0.2 ; python_version > '3.9' # (Jammy)
|
||||||
|
xlrd==1.2.0; python_version >= '3.8'
|
||||||
|
XlsxWriter==1.1.2
|
||||||
|
xlwt==1.3.*
|
||||||
|
zeep==3.4.0
|
||||||
@@ -49,6 +49,7 @@ class MrsProductionProcess(models.Model):
|
|||||||
processing_order_ids = fields.One2many('sf.processing.order', 'production_process_id', string='工序')
|
processing_order_ids = fields.One2many('sf.processing.order', 'production_process_id', string='工序')
|
||||||
partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂')
|
partner_process_ids = fields.Many2many('res.partner', 'process_ids', '加工工厂')
|
||||||
active = fields.Boolean('有效', default=True)
|
active = fields.Boolean('有效', default=True)
|
||||||
|
parameter_ids = fields.One2many('sf.production.process.parameter', 'process_id', string='可选参数')
|
||||||
|
|
||||||
|
|
||||||
class MrsProcessingTechnology(models.Model):
|
class MrsProcessingTechnology(models.Model):
|
||||||
@@ -96,3 +97,12 @@ class SupplierSort(models.Model):
|
|||||||
('supplier_sort_uniq', 'unique (partner_id,materials_model_id)', '排序不能重复!')
|
('supplier_sort_uniq', 'unique (partner_id,materials_model_id)', '排序不能重复!')
|
||||||
]
|
]
|
||||||
|
|
||||||
|
class MrsProductionProcessParameter(models.Model):
|
||||||
|
_name = 'sf.production.process.parameter'
|
||||||
|
_description = '可选参数'
|
||||||
|
name = fields.Char('参数名')
|
||||||
|
active = fields.Boolean('有效', default=True)
|
||||||
|
price = fields.Float('单价')
|
||||||
|
process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
||||||
|
materials_model_ids = fields.Many2many('sf.materials.model', 'applicable_material', string='适用材料')
|
||||||
|
code = fields.Char("编码")
|
||||||
@@ -14,7 +14,7 @@ access_sf_processing_technology,sf_processing_technology,model_sf_processing_tec
|
|||||||
access_sf_tray,sf_tray,model_sf_tray,base.group_user,1,1,1,1
|
access_sf_tray,sf_tray,model_sf_tray,base.group_user,1,1,1,1
|
||||||
access_sf_supplier_sort,sf_supplier_sort,model_sf_supplier_sort,base.group_user,1,1,1,1
|
access_sf_supplier_sort,sf_supplier_sort,model_sf_supplier_sort,base.group_user,1,1,1,1
|
||||||
|
|
||||||
|
access_sf_production_process_parameter,sf_production_process_parameter,model_sf_production_process_parameter,base.group_user,1,1,1,1
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
|
@@ -74,6 +74,32 @@
|
|||||||
</form>
|
</form>
|
||||||
</field>
|
</field>
|
||||||
</page>
|
</page>
|
||||||
|
<page string="可选参数">
|
||||||
|
<field name="parameter_ids">
|
||||||
|
<tree force_save="1">
|
||||||
|
<field name="code" readonly="1" force_save="1"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="price"/>
|
||||||
|
<field name='process_id' default="default" invisible="1"/>
|
||||||
|
</tree>
|
||||||
|
<form>
|
||||||
|
<sheet>
|
||||||
|
<group>
|
||||||
|
<field name="code" readonly="1" force_save="1"/>
|
||||||
|
<field name="name"/>
|
||||||
|
<field name="price"/>
|
||||||
|
</group>
|
||||||
|
<notebook>
|
||||||
|
<page string="适用材料">
|
||||||
|
<field name="materials_model_ids"/>
|
||||||
|
</page>
|
||||||
|
</notebook>
|
||||||
|
</sheet>
|
||||||
|
|
||||||
|
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</page>
|
||||||
</notebook>
|
</notebook>
|
||||||
<group>
|
<group>
|
||||||
<field name="remark"/>
|
<field name="remark"/>
|
||||||
|
|||||||
@@ -131,4 +131,15 @@
|
|||||||
<field name="numbercall">-1</field>
|
<field name="numbercall">-1</field>
|
||||||
<field name="doall" eval="False"/>
|
<field name="doall" eval="False"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<record model="ir.cron" id="sf_cron13">
|
||||||
|
<field name="name">同步表面工艺可选参数</field>
|
||||||
|
<field name="model_id" ref="model_sf_production_process_parameter"/>
|
||||||
|
<field name="state">code</field>
|
||||||
|
<field name="code">model.sync_production_process_parameter()</field>
|
||||||
|
<field name="interval_number">1</field>
|
||||||
|
<field name="interval_type">days</field>
|
||||||
|
<field name="numbercall">-1</field>
|
||||||
|
<field name="doall" eval="False"/>
|
||||||
|
</record>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -2,7 +2,7 @@
|
|||||||
# Part of SmartGo. See LICENSE file for full copyright and licensing details.
|
# Part of SmartGo. See LICENSE file for full copyright and licensing details.
|
||||||
import logging
|
import logging
|
||||||
from odoo import api, fields, models
|
from odoo import api, fields, models
|
||||||
|
from odoo.exceptions import ValidationError
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -19,6 +19,7 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
ftp_password = fields.Char(string='FTP密码')
|
ftp_password = fields.Char(string='FTP密码')
|
||||||
|
|
||||||
def sf_all_sync(self):
|
def sf_all_sync(self):
|
||||||
|
try:
|
||||||
self.env['sf.production.materials'].sync_all_production_materials()
|
self.env['sf.production.materials'].sync_all_production_materials()
|
||||||
_logger.info("同步资源库材料")
|
_logger.info("同步资源库材料")
|
||||||
self.env['sf.materials.model'].sync_all_materials_model()
|
self.env['sf.materials.model'].sync_all_materials_model()
|
||||||
@@ -33,15 +34,18 @@ class ResConfigSettings(models.TransientModel):
|
|||||||
_logger.info("同步资源库品牌")
|
_logger.info("同步资源库品牌")
|
||||||
self.env['sf.machine.control_system'].sync_all_machine_tool_type_control_system()
|
self.env['sf.machine.control_system'].sync_all_machine_tool_type_control_system()
|
||||||
_logger.info("同步资源库控制系统")
|
_logger.info("同步资源库控制系统")
|
||||||
# self.env['sf.machine_tool'].sync_all_machine_tool()
|
|
||||||
# _logger.info("同步机床行业编码")
|
|
||||||
self.env['sf.machine_tool.type'].sync_all_machine_tool_type()
|
self.env['sf.machine_tool.type'].sync_all_machine_tool_type()
|
||||||
_logger.info("同步资源库机床型号")
|
_logger.info("同步资源库机床型号")
|
||||||
self.env['sf.cutting_tool.category'].sync_all_cutting_tool_category()
|
self.env['sf.cutting_tool.category'].sync_all_cutting_tool_category()
|
||||||
_logger.info("同步资源库刀具类别")
|
_logger.info("同步资源库刀具类别")
|
||||||
self.env['sf.cutting_tool.type'].sync_all_cutting_tool_type()
|
self.env['sf.cutting_tool.type'].sync_all_cutting_tool_type()
|
||||||
_logger.info("同步资源库刀具")
|
_logger.info("同步资源库刀具")
|
||||||
# self.env['sf.processing.order'].sync_all_processing_order()
|
self.env['sf.production.process.parameter'].sync_all_production_process_parameter()
|
||||||
|
_logger.info("同步表面工艺参数")
|
||||||
|
except Exception as e:
|
||||||
|
_logger.info("捕获错误信息:%s" % e)
|
||||||
|
raise ValidationError("数据错误导致同步失败,请联系管理员")
|
||||||
|
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def get_values(self):
|
def get_values(self):
|
||||||
|
|||||||
@@ -948,3 +948,75 @@ class sfProcessingOrder(models.Model):
|
|||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
raise ValidationError("认证未通过")
|
raise ValidationError("认证未通过")
|
||||||
|
|
||||||
|
class sfProductionProcessParameter(models.Model):
|
||||||
|
_inherit = 'sf.production.process.parameter'
|
||||||
|
_description = '表面工艺可选参数'
|
||||||
|
url = '/api/production_process_parameter/list'
|
||||||
|
|
||||||
|
# 定时同步每日表面工艺
|
||||||
|
def sync_production_process_parameter(self):
|
||||||
|
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||||
|
token = sf_sync_config['token']
|
||||||
|
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||||
|
headers = Common.get_headers(self, token, sf_secret_key)
|
||||||
|
|
||||||
|
strUrl = sf_sync_config['sf_url'] + self.url
|
||||||
|
r = requests.post(strUrl, json={}, data=None, headers=headers)
|
||||||
|
r = r.json()
|
||||||
|
result = json.loads(r['result'])
|
||||||
|
if result['status'] == 1:
|
||||||
|
for item in result['mrs_production_process_parameter_yesterday_list']:
|
||||||
|
if item:
|
||||||
|
brand = self.env['sf.production.process.parameter'].search(
|
||||||
|
[("code", '=', item['code'])])
|
||||||
|
if brand:
|
||||||
|
brand.name = item['name'],
|
||||||
|
brand.code = item['code'],
|
||||||
|
brand.active = item['active'],
|
||||||
|
brand.price = item['price'],
|
||||||
|
else:
|
||||||
|
self.env['sf.production.process.parameter'].create({
|
||||||
|
"name": item['name'],
|
||||||
|
"code": item['code'],
|
||||||
|
"active": item['active'],
|
||||||
|
"price" : item['price'],
|
||||||
|
"process_id": self.env['sf.production.process'].search(
|
||||||
|
[('process_encode', '=', item['process_id_code'])]).id,
|
||||||
|
'materials_model_ids': self.env['sf.materials.model'].search(
|
||||||
|
[('materials_no', 'in', item['materials_model_ids_codes'])])
|
||||||
|
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
raise ValidationError("认证未通过") # 定时同步表面工艺
|
||||||
|
|
||||||
|
# 同步所有表面工艺
|
||||||
|
def sync_all_production_process_parameter(self):
|
||||||
|
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||||
|
token = sf_sync_config['token']
|
||||||
|
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||||
|
headers = Common.get_headers(self, token, sf_secret_key)
|
||||||
|
|
||||||
|
strUrl = sf_sync_config['sf_url'] + self.url
|
||||||
|
r = requests.post(strUrl, json={}, data=None, headers=headers)
|
||||||
|
r = r.json()
|
||||||
|
result = json.loads(r['result'])
|
||||||
|
if result['status'] == 1:
|
||||||
|
for item in result['mrs_production_process_parameter_all_list']:
|
||||||
|
if item:
|
||||||
|
brand = self.env['sf.production.process.parameter'].search(
|
||||||
|
[("code", '=', item['code'])])
|
||||||
|
if not brand:
|
||||||
|
self.env['sf.production.process.parameter'].create({
|
||||||
|
"name": item['name'],
|
||||||
|
"code": item['code'],
|
||||||
|
"price": item['price'],
|
||||||
|
"active": item['active'],
|
||||||
|
"process_id": self.env['sf.production.process'].search(
|
||||||
|
[('process_encode', '=', item['process_id_code'])]).id,
|
||||||
|
'materials_model_ids': self.env['sf.materials.model'].search(
|
||||||
|
[('materials_no', 'in', item['materials_model_ids_codes'])])
|
||||||
|
|
||||||
|
})
|
||||||
|
else:
|
||||||
|
raise ValidationError("认证未通过")
|
||||||
Reference in New Issue
Block a user