Accept Merge Request #141: (feature/页面优化 -> develop)

Merge Request: 页面优化及排产(根据胚料的长宽高比对一下机床的最大加工尺寸)

Created By: @杨金灵
Accepted By: @杨金灵
URL: https://jikimo-hn.coding.net/p/jikimo_sfs/d/jikimo_sf/git/merge/141?initial=true
This commit is contained in:
杨金灵
2023-02-17 15:03:05 +08:00
46 changed files with 1328 additions and 89 deletions

8
.idea/.gitignore generated vendored
View File

@@ -1,8 +0,0 @@
# 默认忽略的文件
/shelf/
/workspace.xml
# 基于编辑器的 HTTP 客户端请求
/httpRequests/
# Datasource local storage ignored files
/dataSources/
/dataSources.local.xml

View File

@@ -1,6 +0,0 @@
<component name="InspectionProjectProfileManager">
<settings>
<option name="USE_PROJECT_PROFILE" value="false" />
<version value="1.0" />
</settings>
</component>

20
.idea/jikimo-sf.iml generated
View File

@@ -1,20 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<module type="PYTHON_MODULE" version="4">
<component name="NewModuleRootManager">
<content url="file://$MODULE_DIR$" />
<orderEntry type="inheritedJdk" />
<orderEntry type="sourceFolder" forTests="false" />
<orderEntry type="module" module-name="odoo-16.0" />
</component>
<component name="PyDocumentationSettings">
<option name="format" value="PLAIN" />
<option name="myDocStringFormat" value="Plain" />
</component>
<component name="TemplatesService">
<option name="TEMPLATE_FOLDERS">
<list>
<option value="$MODULE_DIR$/yizuo_login_background_and_styles/templates" />
</list>
</option>
</component>
</module>

4
.idea/misc.xml generated
View File

@@ -1,4 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectRootManager" version="2" project-jdk-name="Python 3.9 (odoo-15.0)" project-jdk-type="Python SDK" />
</project>

9
.idea/modules.xml generated
View File

@@ -1,9 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="ProjectModuleManager">
<modules>
<module fileurl="file://$PROJECT_DIR$/.idea/jikimo-sf.iml" filepath="$PROJECT_DIR$/.idea/jikimo-sf.iml" />
<module fileurl="file://$PROJECT_DIR$/../../../odoo-16.0/.idea/odoo-16.0.iml" filepath="$PROJECT_DIR$/../../../odoo-16.0/.idea/odoo-16.0.iml" />
</modules>
</component>
</project>

6
.idea/vcs.xml generated
View File

@@ -1,6 +0,0 @@
<?xml version="1.0" encoding="UTF-8"?>
<project version="4">
<component name="VcsDirectoryMappings">
<mapping directory="$PROJECT_DIR$" vcs="Git" />
</component>
</project>

2
owl_demo/__init__.py Normal file
View File

@@ -0,0 +1,2 @@
from . import models
from . import controllers

32
owl_demo/__manifest__.py Normal file
View File

@@ -0,0 +1,32 @@
{
"name": "OWL开发演示",
"summary": "示例OWL开发模块。",
"description": "用于演示OWL模块的开发。",
"author": "Van",
"website": "https://topodoo.com",
"category": "Tutorials",
"version": "15.0.0.1",
"depends": ["sale", "sale_management"],
"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',
],
}
}

View File

@@ -0,0 +1 @@
from . import main

View File

@@ -0,0 +1,266 @@
# -*- 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)

View File

@@ -0,0 +1 @@
from . import sale_order

View File

@@ -0,0 +1,15 @@
# -*- coding: utf-8 -*-
# Part of Odoo. See LICENSE file for full copyright and licensing details.
import logging
from odoo import models,fields
from odoo.tools import populate, groupby
_logger = logging.getLogger(__name__)
class SaleOrder(models.Model):
_inherit = "sale.order"
step_file = fields.Binary("Step File")

View File

View File

@@ -0,0 +1,8 @@
<?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>

View File

@@ -0,0 +1,30 @@
.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;
}
}
}
}
}

View File

@@ -0,0 +1,127 @@
/** @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);

View File

@@ -0,0 +1,88 @@
<?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>

View File

@@ -0,0 +1,277 @@
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.

View File

@@ -0,0 +1,25 @@
/** @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');
});

View File

@@ -0,0 +1,84 @@
/** @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);
// });
// }
// }
//});

View File

@@ -0,0 +1,64 @@
<?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">-->
<!--&lt;!&ndash; <h3><t t-out="record.data.name"/></h3>&ndash;&gt;-->
<!-- <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>

View File

@@ -0,0 +1,97 @@
/** @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);

View File

@@ -0,0 +1,3 @@
.o_field_widget.o_field_template {
display: block;
}

View File

@@ -0,0 +1,8 @@
<?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>

View File

@@ -0,0 +1,25 @@
/** @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);

View File

@@ -0,0 +1,50 @@
/** @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);

View File

@@ -0,0 +1,10 @@
<?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>

View File

@@ -0,0 +1,4 @@
<?xml version="1.0" encoding="UTF-8" ?>
<templates>
</templates>

View File

@@ -0,0 +1,36 @@
<?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>

33
owl_demo/views/views.xml Normal file
View File

@@ -0,0 +1,33 @@
<?xml version="1.0" encoding="utf-8"?>
<odoo>
<record id="sale_order_form_inherit" model="ir.ui.view">
<field name="name">sale.order.form.inherit</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_form"/>
<field name="arch" type="xml">
<field name="payment_term_id" position="after">
<!-- <field name="create_date" widget="show_units" options="{'units':'UTC'}" string="Create Date"/>-->
<!-- <group class="o_partner_order_summary" col="2"/>-->
<field name="step_file" widget="Viewer3D" readonly="True"/>
</field>
</field>
</record>
<record id="sale_order_tree_inherit" model="ir.ui.view">
<field name="name">sale.order.tree.inherit</field>
<field name="model">sale.order</field>
<field name="inherit_id" ref="sale.view_order_tree"/>
<field name="arch" type="xml">
<field name="partner_id" position="attributes">
<attribute name="widget">CTemplate</attribute>
<attribute name="options">{'template':'owl_demo.field_partner_id'}</attribute>
</field>
<field name="team_id" position="before">
<field name="order_line" widget="CTemplate" options="{'template':'owl_demo.field_order_line'}"/>
</field>
</field>
</record>
</odoo>

View File

@@ -1,18 +1,13 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from odoo import fields, models, api from odoo import models
import time import time
import hashlib import hashlib
class Common(models.Model): class Common(models.Model):
_name = 'sf.sync.common' _name = 'sf.sync.common'
_description = u'公用类' _description = u'公用类'
def get_headers(self,token, secret_key): def get_headers(self,token, secret_key):
''' '''
获取requests中的heardes参数 获取requests中的heardes参数

View File

@@ -1,12 +1,9 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
from datetime import datetime
import requests import requests
import json import json
from odoo import fields, models, api from odoo import fields, models, api
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
from odoo.http import request
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)

View File

@@ -1,6 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging import logging
from odoo import fields, models, api from odoo import fields, models
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)

View File

@@ -11,7 +11,7 @@ class Sf_Bf_Connect(http.Controller):
cors="*") cors="*")
def get_bfm_process_order_list(self, **kw): def get_bfm_process_order_list(self, **kw):
""" """
获取业务平台传送来的订单 接收业务平台加工订单分配工厂时传送来的订单数据并生成销售订单和产品及胚料
:param kw: :param kw:
:return: :return:
""" """
@@ -105,6 +105,7 @@ class Sf_Bf_Connect(http.Controller):
product_bom_purchase.with_user(request.env.ref("base.user_admin")).bom_create_line_has( product_bom_purchase.with_user(request.env.ref("base.user_admin")).bom_create_line_has(
purchase_embryo) purchase_embryo)
order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item) order_id.with_user(request.env.ref("base.user_admin")).sale_order_create_line(product, item)
order_id.step_file = product.model_file
i += 1 i += 1
res['factory_order_no'] = order_id.name res['factory_order_no'] = order_id.name
return json.JSONEncoder().encode(res) return json.JSONEncoder().encode(res)

View File

@@ -237,7 +237,7 @@ class ResMrpBom(models.Model):
'bom_id': self.id, 'bom_id': self.id,
'product_id': raw_bom_line.id, 'product_id': raw_bom_line.id,
'product_tmpl_id': raw_bom_line.product_tmpl_id.id, 'product_tmpl_id': raw_bom_line.product_tmpl_id.id,
'product_qty': round(embryo.volume / 1000000000 * raw_bom_line.materials_type_id.density, 2), 'product_qty': round(embryo.volume * raw_bom_line.materials_type_id.density / 1000000),
'product_uom_id': raw_bom_line.uom_id.id, 'product_uom_id': raw_bom_line.uom_id.id,
}) })
return bom_line return bom_line

View File

@@ -1,5 +1,4 @@
from odoo import api, fields, models from odoo import fields, models
class ResMrpWorkOrder(models.Model): class ResMrpWorkOrder(models.Model):

View File

@@ -10,12 +10,12 @@
<!-- <field name="upload_model_file" required="True"--> <!-- <field name="upload_model_file" required="True"-->
<!-- widget='many2many_binary'/>--> <!-- widget='many2many_binary'/>-->
<!-- </field>--> <!-- </field>-->
<field name="invoice_policy" position="after"> <field name="invoice_policy" position="after">
<!-- <field name="model_file" widget="model_viewer"--> <field name='categ_type' invisible="1"/>
<!-- attrs="{'invisible': [('categ_type', '!=', '成品')]}"/>--> <field name="model_file" widget="model_viewer"
<!-- <field name="embryo_model_type_id" string="模型类型"--> attrs="{'invisible': ['|', ('categ_type', '!=', '成品'),('categ_type', '=', False)]}"/>
<!-- attrs="{'invisible': [('categ_type', '=', '胚料')]}"/>--> <field name="embryo_model_type_id" string="模型类型"
attrs="{'invisible': ['|',('categ_type', '!=', '胚料'),('categ_type', '=', False)]}"/>
<field name="materials_id" string="材料"/> <field name="materials_id" string="材料"/>
<field name="materials_type_id" string="型号" <field name="materials_type_id" string="型号"
domain="[('materials_id', '=', materials_id)]"/> domain="[('materials_id', '=', materials_id)]"/>

View File

@@ -24,18 +24,33 @@ class ResMrpRoutingWorkcenter(models.Model):
company_id = fields.Many2one('res.company', compute="get_company_id", related=False) company_id = fields.Many2one('res.company', compute="get_company_id", related=False)
# 排产的时候, 根据胚料的长宽高比对一下机床的最大加工尺寸.不符合就不要分配给这个加工中心(机床).
# 工单对应的工作中心,根据工序中的工作中心去匹配, # 工单对应的工作中心,根据工序中的工作中心去匹配,
# 如果只配置了一个工作中心,则默认采用该工作中心; # 如果只配置了一个工作中心,则默认采用该工作中心;
# 如果有多个工作中心, # 如果有多个工作中心,
# 则根据该工作中心的工单个数进行分配(优先分配给工单个数最少的); # 则根据该工作中心的工单个数进行分配(优先分配给工单个数最少的);
def get_workcenter(self, workcenter_ids): def get_workcenter(self, workcenter_ids, routing_type, product):
if workcenter_ids: if workcenter_ids:
if len(workcenter_ids) == 1: if len(workcenter_ids) == 1:
return workcenter_ids[0] return workcenter_ids[0]
elif len(workcenter_ids) >= 2: elif len(workcenter_ids) >= 2:
# workcenter_ids_str = ','.join([str(s) for s in workcenter_ids]) # workcenter_ids_str = ','.join([str(s) for s in workcenter_ids])
if routing_type == 'CNC加工':
workcenter = self.env['mrp.workcenter'].search([('id', 'in', workcenter_ids)])
workcenter_ids = []
for item in workcenter:
print(item.name)
if item.machine_tool_id:
machine_tool = self.env['sf.machine_tool'].search(
[('x_axis', '>', product.bom_ids.bom_line_ids.product_id.length), ('y_axis', '>', product.bom_ids.bom_line_ids.product_id.width),
('z_axis', '>', product.bom_ids.bom_line_ids.product_id.height), ('id', '=', item.machine_tool_id.id)])
if machine_tool:
workcenter_ids.append(item.id)
if len(workcenter_ids) == 1:
return workcenter_ids[0]
self.env.cr.execute(""" self.env.cr.execute("""
SELECT workcenter_id FROM mrp_workorder where workcenter_id SELECT workcenter_id FROM mrp_workorder where workcenter_id
in %s group by workcenter_id in %s group by workcenter_id
order by count(*),workcenter_id asc limit 1 """, [tuple(workcenter_ids)]) order by count(*),workcenter_id asc limit 1 """, [tuple(workcenter_ids)])
return self.env.cr.dictfetchall()[0].get('workcenter_id') workcenter_id = self.env.cr.dictfetchall()[0].get('workcenter_id')
return workcenter_id

View File

@@ -146,7 +146,9 @@ class ResMrpWorkOrder(models.Model):
'processing_panel': k, 'processing_panel': k,
'routing_type': route.routing_type, 'routing_type': route.routing_type,
'work_state': '' if not route.routing_type == '获取CNC加工程序' else '待发起', 'work_state': '' if not route.routing_type == '获取CNC加工程序' else '待发起',
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids), 'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids,
route.routing_type,
production.product_id),
'date_planned_start': False, 'date_planned_start': False,
'date_planned_finished': False, 'date_planned_finished': False,
'duration_expected': 60, 'duration_expected': 60,
@@ -357,7 +359,9 @@ class ResMrpWorkOrder(models.Model):
'processing_panel': k, 'processing_panel': k,
'routing_type': route.routing_type, 'routing_type': route.routing_type,
'work_state': '' if not route.routing_type == '获取CNC加工程序' else '待发起', 'work_state': '' if not route.routing_type == '获取CNC加工程序' else '待发起',
'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids), 'workcenter_id': self.env['mrp.routing.workcenter'].get_workcenter(route.workcenter_ids.ids,
route.routing_type,
production.product_id),
'date_planned_start': False, 'date_planned_start': False,
'date_planned_finished': False, 'date_planned_finished': False,
'duration_expected': 60, 'duration_expected': 60,
@@ -463,6 +467,7 @@ class CNCprocessing(models.Model):
cnc_workorder.time_ids.date_end = datetime.now() cnc_workorder.time_ids.date_end = datetime.now()
cnc_workorder.button_finish() cnc_workorder.button_finish()
# 根据程序名和加工面匹配到ftp里对应的Nc程序名
def get_cnc_processing_file(self, folder_name, cnc_processing, processing_panel): def get_cnc_processing_file(self, folder_name, cnc_processing, processing_panel):
logging.info('folder_name:%s' % folder_name) logging.info('folder_name:%s' % folder_name)
serverdir = os.path.join('/tmp', folder_name, 'return', processing_panel) serverdir = os.path.join('/tmp', folder_name, 'return', processing_panel)

View File

@@ -1,5 +1,6 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
from odoo import SUPERUSER_ID, _, api, fields, models, registry from odoo import fields, models
class Users(models.Model): class Users(models.Model):
_inherit = 'res.users' _inherit = 'res.users'

View File

@@ -1,11 +1,10 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import logging
from collections import defaultdict, namedtuple from collections import defaultdict, namedtuple
from odoo.addons.stock.models.stock_rule import ProcurementException from odoo.addons.stock.models.stock_rule import ProcurementException
from re import findall as regex_findall from re import findall as regex_findall
from re import split as regex_split from re import split as regex_split
from odoo import SUPERUSER_ID, _, api, fields, models, registry from odoo import SUPERUSER_ID, _, api, models
from odoo.tools import float_compare, float_is_zero, html_escape from odoo.tools import float_compare
class StockRule(models.Model): class StockRule(models.Model):

View File

@@ -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 base64 import base64
from io import BytesIO from io import BytesIO
from odoo import api, fields, models, SUPERUSER_ID, _ from odoo import api, fields, models
from pystrich.code128 import Code128Encoder from pystrich.code128 import Code128Encoder

View File

@@ -1,7 +1,5 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import os import os
import posixpath
from odoo.modules import get_resource_path
from ftplib import FTP from ftplib import FTP
import logging import logging

View File

@@ -1,9 +1,8 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
# 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 UserError
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)

View File

@@ -1,14 +1,11 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import requests import requests
import json import json
import base64
from odoo import models from odoo import models
from odoo.exceptions import ValidationError from odoo.exceptions import ValidationError
import logging import logging
from odoo.addons.sf_base.commons.common import Common from odoo.addons.sf_base.commons.common import Common
from odoo.http import request
from .res_config_setting import ResConfigSettings
_logger = logging.getLogger(__name__) _logger = logging.getLogger(__name__)