Compare commits
1 Commits
feature/优化
...
feature/cu
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
186ac391ea |
@@ -20,7 +20,7 @@
|
|||||||
'version': '0.1',
|
'version': '0.1',
|
||||||
|
|
||||||
# any module necessary for this one to work correctly
|
# any module necessary for this one to work correctly
|
||||||
'depends': ['base', 'account', 'l10n_cn'],
|
'depends': ['base', 'account'],
|
||||||
|
|
||||||
# always loaded
|
# always loaded
|
||||||
'data': [
|
'data': [
|
||||||
|
|||||||
@@ -1,4 +1,4 @@
|
|||||||
from odoo import models, fields, api, _
|
from odoo import models, fields, api
|
||||||
|
|
||||||
from odoo.exceptions import ValidationError
|
from odoo.exceptions import ValidationError
|
||||||
|
|
||||||
@@ -7,14 +7,6 @@ class CustomAccountMoveLine(models.Model):
|
|||||||
_inherit = 'account.move'
|
_inherit = 'account.move'
|
||||||
_description = "account move line"
|
_description = "account move line"
|
||||||
|
|
||||||
fapiao = fields.Char(string='发票号', size=20, copy=False, tracking=True, required=True)
|
|
||||||
|
|
||||||
@api.constrains('fapiao')
|
|
||||||
def _check_fapiao(self):
|
|
||||||
for record in self:
|
|
||||||
if record.fapiao and (len(record.fapiao) != 20 or not record.fapiao.isdecimal()):
|
|
||||||
raise ValidationError(_("Fapiao number is an 20-digit number. Please enter a correct one."))
|
|
||||||
|
|
||||||
@api.model_create_multi
|
@api.model_create_multi
|
||||||
def create(self, vals):
|
def create(self, vals):
|
||||||
for val in vals:
|
for val in vals:
|
||||||
|
|||||||
@@ -21,8 +21,8 @@
|
|||||||
'web.assets_qweb': [
|
'web.assets_qweb': [
|
||||||
],
|
],
|
||||||
'web.assets_backend': [
|
'web.assets_backend': [
|
||||||
# 'jikimo_frontend/static/src/fields/custom_many2many_checkboxes/*',
|
'jikimo_frontend/static/src/fields/custom_many2many_checkboxes/*',
|
||||||
# 'jikimo_frontend/static/src/fields/Many2OneRadioField/*',
|
'jikimo_frontend/static/src/fields/Many2OneRadioField/*',
|
||||||
# 移除odoo相关标识
|
# 移除odoo相关标识
|
||||||
'jikimo_frontend/static/src/bye_odoo/*',
|
'jikimo_frontend/static/src/bye_odoo/*',
|
||||||
'jikimo_frontend/static/src/scss/custom_style.scss',
|
'jikimo_frontend/static/src/scss/custom_style.scss',
|
||||||
|
|||||||
@@ -1,8 +1,3 @@
|
|||||||
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector):not(.o_handle_cell):not(.o_list_button):not(.o_list_record_remove){
|
.o_list_renderer .o_list_table tbody > tr > td:not(.o_list_record_selector):not(.o_handle_cell):not(.o_list_button):not(.o_list_record_remove){
|
||||||
border:1px solid #dee2e6 !important;
|
border:1px solid #dee2e6 !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.custom_required_add::before{
|
|
||||||
content: '*';
|
|
||||||
color: red;
|
|
||||||
}
|
|
||||||
@@ -0,0 +1,3 @@
|
|||||||
|
.many2one_radio_field {
|
||||||
|
display: inline-block;
|
||||||
|
}
|
||||||
@@ -0,0 +1,53 @@
|
|||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import { RadioField } from "@web/views/fields/radio/radio_field"; // 导入单选按钮组件
|
||||||
|
import { registry } from "@web/core/registry";
|
||||||
|
|
||||||
|
export class Many2OneRadioField extends RadioField {
|
||||||
|
// 你可以重写或者添加一些方法和属性
|
||||||
|
// 例如,你可以重写setup方法来添加一些事件监听器或者初始化一些变量
|
||||||
|
setup() {
|
||||||
|
super.setup(); // 调用父类的setup方法
|
||||||
|
// 你自己的代码
|
||||||
|
}
|
||||||
|
|
||||||
|
onImageClick(event) {
|
||||||
|
// 放大图片逻辑
|
||||||
|
// 获取图片元素
|
||||||
|
const img = event.target;
|
||||||
|
const close = img.nextSibling;
|
||||||
|
// 实现放大图片逻辑
|
||||||
|
// 比如使用 CSS 放大
|
||||||
|
img.parentElement.classList.add('zoomed');
|
||||||
|
close.classList.add('img_close');
|
||||||
|
}
|
||||||
|
|
||||||
|
onCloseClick(event) {
|
||||||
|
const close = event.target;
|
||||||
|
const img = close.previousSibling;
|
||||||
|
img.parentElement.classList.remove('zoomed');
|
||||||
|
close.classList.remove('img_close');
|
||||||
|
}
|
||||||
|
|
||||||
|
get items() {
|
||||||
|
return Many2OneRadioField.getItems(this.props.name, this.props.record);
|
||||||
|
}
|
||||||
|
|
||||||
|
static getItems(fieldName, record) {
|
||||||
|
switch (record.fields[fieldName].type) {
|
||||||
|
case "selection":
|
||||||
|
return record.fields[fieldName].selection;
|
||||||
|
case "many2one": {
|
||||||
|
const value = record.preloadedData[fieldName] || [];
|
||||||
|
return value.map((item) => [item.id, item.display_name, item.image]);
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
return [];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
Many2OneRadioField.template = "jikimo_frontend.Many2OneRadioField";
|
||||||
|
// MyCustomWidget.supportedTypes = ['many2many'];
|
||||||
|
|
||||||
|
registry.category("fields").add("many2one_radio", Many2OneRadioField);
|
||||||
@@ -0,0 +1,35 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
|
||||||
|
<t t-name="jikimo_frontend.Many2OneRadioField" owl="1">
|
||||||
|
<div
|
||||||
|
role="radiogroup"
|
||||||
|
t-attf-class="o_{{ props.orientation }}"
|
||||||
|
t-att-aria-label="string"
|
||||||
|
>
|
||||||
|
<t t-foreach="items" t-as="item" t-key="item[0]">
|
||||||
|
<div class="form-check o_radio_item many2one_radio_field" aria-atomic="true">
|
||||||
|
<input
|
||||||
|
type="radio"
|
||||||
|
class="form-check-input o_radio_input"
|
||||||
|
t-att-checked="item[0] === value"
|
||||||
|
t-att-disabled="props.readonly"
|
||||||
|
t-att-name="id"
|
||||||
|
t-att-data-value="item[0]"
|
||||||
|
t-att-data-index="item_index"
|
||||||
|
t-att-id="`${id}_${item[0]}`"
|
||||||
|
t-on-change="() => this.onChange(item)"
|
||||||
|
/>
|
||||||
|
<label class="form-check-label o_form_label" t-att-for="`${id}_${item[0]}`" t-esc="item[1]" />
|
||||||
|
<div t-on-dblclick="onImageClick">
|
||||||
|
<t>
|
||||||
|
<img t-att-src="item[2]" width="50" height="50"/>
|
||||||
|
<div class="close" t-on-click="onCloseClick">×</div>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
</templates>
|
||||||
@@ -0,0 +1,100 @@
|
|||||||
|
|
||||||
|
.processing-capabilities-grid {
|
||||||
|
display: grid;
|
||||||
|
grid-template-columns: repeat(6, 1fr);
|
||||||
|
gap: 10px;
|
||||||
|
width: 100%;
|
||||||
|
}
|
||||||
|
|
||||||
|
.grid-item {
|
||||||
|
display: flex;
|
||||||
|
align-items: center;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-content {
|
||||||
|
display: flex;
|
||||||
|
flex-direction: column;
|
||||||
|
align-items: center;
|
||||||
|
text-align: center;
|
||||||
|
}
|
||||||
|
/*控制图片大小*/
|
||||||
|
.item-icon {
|
||||||
|
width: 50px;
|
||||||
|
height: 50px;
|
||||||
|
margin-bottom: 5px;
|
||||||
|
margin-top: 15px;
|
||||||
|
}
|
||||||
|
|
||||||
|
.item-label {
|
||||||
|
font-size: 12px;
|
||||||
|
word-break: break-word;
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 1200px) {
|
||||||
|
.processing-capabilities-grid {
|
||||||
|
grid-template-columns: repeat(4, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 768px) {
|
||||||
|
.processing-capabilities-grid {
|
||||||
|
grid-template-columns: repeat(3, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
@media (max-width: 480px) {
|
||||||
|
.processing-capabilities-grid {
|
||||||
|
grid-template-columns: repeat(2, 1fr);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
.image-preview-container {
|
||||||
|
position: fixed;
|
||||||
|
top: 0;
|
||||||
|
left: 0;
|
||||||
|
width: 100%;
|
||||||
|
height: 100%;
|
||||||
|
background-color: rgba(0, 0, 0, 0.9);
|
||||||
|
display: flex;
|
||||||
|
justify-content: center;
|
||||||
|
align-items: center;
|
||||||
|
z-index: 1000;
|
||||||
|
opacity: 0;
|
||||||
|
transition: opacity 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-preview-container.show {
|
||||||
|
opacity: 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-preview {
|
||||||
|
max-width: 90%;
|
||||||
|
max-height: 90%;
|
||||||
|
object-fit: contain;
|
||||||
|
box-shadow: 0 0 20px rgba(255, 255, 255, 0.2);
|
||||||
|
border-radius: 5px;
|
||||||
|
transform: scale(0.9);
|
||||||
|
transition: transform 0.3s ease;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-preview-container.show .image-preview {
|
||||||
|
transform: scale(1);
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-preview-close {
|
||||||
|
position: absolute;
|
||||||
|
top: 20px;
|
||||||
|
right: 30px;
|
||||||
|
color: #fff;
|
||||||
|
font-size: 40px;
|
||||||
|
font-weight: bold;
|
||||||
|
transition: 0.3s;
|
||||||
|
cursor: pointer;
|
||||||
|
opacity: 0.7;
|
||||||
|
}
|
||||||
|
|
||||||
|
.image-preview-close:hover,
|
||||||
|
.image-preview-close:focus {
|
||||||
|
opacity: 1;
|
||||||
|
text-decoration: none;
|
||||||
|
cursor: pointer;
|
||||||
|
}
|
||||||
@@ -0,0 +1,60 @@
|
|||||||
|
/** @odoo-module **/
|
||||||
|
|
||||||
|
import {Many2ManyCheckboxesField} from "@web/views/fields/many2many_checkboxes/many2many_checkboxes_field";
|
||||||
|
import {registry} from "@web/core/registry";
|
||||||
|
|
||||||
|
export class MyCustomWidget extends Many2ManyCheckboxesField {
|
||||||
|
setup() {
|
||||||
|
super.setup();
|
||||||
|
}
|
||||||
|
|
||||||
|
onImageClick(event, src) {
|
||||||
|
event.preventDefault();
|
||||||
|
event.stopPropagation();
|
||||||
|
|
||||||
|
// 创建预览框
|
||||||
|
const previewContainer = document.createElement('div');
|
||||||
|
previewContainer.className = 'image-preview-container';
|
||||||
|
|
||||||
|
const previewImg = document.createElement('img');
|
||||||
|
previewImg.src = src;
|
||||||
|
previewImg.className = 'image-preview';
|
||||||
|
// 设置放大的预览图片大小
|
||||||
|
previewImg.style.width = '600px';
|
||||||
|
previewImg.style.height = 'auto'; // 保持宽高比
|
||||||
|
|
||||||
|
const closeButton = document.createElement('span');
|
||||||
|
closeButton.innerHTML = '×';
|
||||||
|
closeButton.className = 'image-preview-close';
|
||||||
|
|
||||||
|
previewContainer.appendChild(previewImg);
|
||||||
|
previewContainer.appendChild(closeButton);
|
||||||
|
document.body.appendChild(previewContainer);
|
||||||
|
|
||||||
|
// 添加关闭预览的事件监听器
|
||||||
|
const closePreview = () => {
|
||||||
|
previewContainer.classList.remove('show');
|
||||||
|
setTimeout(() => {
|
||||||
|
document.body.removeChild(previewContainer);
|
||||||
|
}, 300);
|
||||||
|
};
|
||||||
|
|
||||||
|
closeButton.addEventListener('click', closePreview);
|
||||||
|
|
||||||
|
// 点击预览框外部也可以关闭
|
||||||
|
previewContainer.addEventListener('click', (e) => {
|
||||||
|
if (e.target === previewContainer) {
|
||||||
|
closePreview();
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
// 使用 setTimeout 来触发过渡效果
|
||||||
|
setTimeout(() => {
|
||||||
|
previewContainer.classList.add('show');
|
||||||
|
}, 10);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
MyCustomWidget.template = "jikimo_frontend.MyCustomWidget";
|
||||||
|
|
||||||
|
registry.category("fields").add("custom_many2many_checkboxes", MyCustomWidget);
|
||||||
@@ -0,0 +1,23 @@
|
|||||||
|
<?xml version="1.0" encoding="UTF-8"?>
|
||||||
|
<templates xml:space="preserve">
|
||||||
|
|
||||||
|
<t t-name="jikimo_frontend.MyCustomWidget" owl="1">
|
||||||
|
<div aria-atomic="true" class="many2many_flex processing-capabilities-grid">
|
||||||
|
<t t-foreach="items" t-as="item" t-key="item[0]">
|
||||||
|
<div class="grid-item">
|
||||||
|
<CheckBox
|
||||||
|
value="isSelected(item)"
|
||||||
|
disabled="props.readonly"
|
||||||
|
onChange="(ev) => this.onChange(item[0], ev)"
|
||||||
|
>
|
||||||
|
<div class="item-content">
|
||||||
|
<img t-att-src="item[2]" class="item-icon" t-on-click="(ev) => this.onImageClick(ev, item[2])"/>
|
||||||
|
<span class="item-label"><t t-esc="item[1]"/></span>
|
||||||
|
</div>
|
||||||
|
</CheckBox>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
</div>
|
||||||
|
</t>
|
||||||
|
|
||||||
|
</templates>
|
||||||
@@ -6,9 +6,8 @@ import {_t} from "@web/core/l10n/translation";
|
|||||||
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
|
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
|
||||||
import {ListRenderer} from "@web/views/list/list_renderer";
|
import {ListRenderer} from "@web/views/list/list_renderer";
|
||||||
// import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field";
|
// import {StatusBarField} from "@web/views/fields/statusbar/statusbar_field";
|
||||||
import {FormLabel} from "@web/views/form/form_label";
|
|
||||||
import { fieldVisualFeedback } from "@web/views/fields/field";
|
|
||||||
|
|
||||||
|
import {Field} from "@web/views/fields/field";
|
||||||
|
|
||||||
var Dialog = require('web.Dialog');
|
var Dialog = require('web.Dialog');
|
||||||
// var {patch} = require("web.utils") 这句话也行
|
// var {patch} = require("web.utils") 这句话也行
|
||||||
@@ -52,6 +51,7 @@ const tableRequiredList = [
|
|||||||
'product_template_id', 'product_uom_qty', 'price_unit','product_id','product_qty',
|
'product_template_id', 'product_uom_qty', 'price_unit','product_id','product_qty',
|
||||||
'name', 'fault_type', 'maintenance_standards', 'Period'
|
'name', 'fault_type', 'maintenance_standards', 'Period'
|
||||||
]
|
]
|
||||||
|
|
||||||
patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
|
patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
|
||||||
setup() {
|
setup() {
|
||||||
owl.onMounted(() => {
|
owl.onMounted(() => {
|
||||||
@@ -107,7 +107,33 @@ patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
|
|||||||
|
|
||||||
}
|
}
|
||||||
);
|
);
|
||||||
|
patch(Field.prototype, 'jikimo_frontend.Field', {
|
||||||
|
setup() {
|
||||||
|
owl.onMounted(this.setRequired);
|
||||||
|
return this._super(...arguments);
|
||||||
|
},
|
||||||
|
setRequired() {
|
||||||
|
const id = this.props.id
|
||||||
|
const isRequired = filedRequiredList[id]
|
||||||
|
if(id == 'number_of_axles') {
|
||||||
|
console.log(isRequired)
|
||||||
|
}
|
||||||
|
if(isRequired) {
|
||||||
|
let dom;
|
||||||
|
dom = $(`label[for=${id}]`)
|
||||||
|
if(isRequired.multiple && dom.length > 1) {
|
||||||
|
dom = dom.eq(-1)
|
||||||
|
dom = dom.parent().parent().next().find('label')
|
||||||
|
}
|
||||||
|
if(isRequired.noLabel) {
|
||||||
|
dom = dom.parent().parent()
|
||||||
|
}
|
||||||
|
let t = dom.html()
|
||||||
|
t = '<i class="c* r" style="color: red;margin-left: -4px">*</i>' + t
|
||||||
|
dom.html(t)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
})
|
||||||
patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
|
patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
|
||||||
setup(){
|
setup(){
|
||||||
owl.onMounted(() => {
|
owl.onMounted(() => {
|
||||||
@@ -165,33 +191,7 @@ patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
patch(FormLabel.prototype, 'jikimo_frontend.FormLabel', {
|
|
||||||
get className() {
|
|
||||||
|
|
||||||
const { invalid, empty, readonly } = fieldVisualFeedback(
|
|
||||||
this.props.fieldInfo.FieldComponent,
|
|
||||||
this.props.record,
|
|
||||||
this.props.fieldName,
|
|
||||||
this.props.fieldInfo
|
|
||||||
);
|
|
||||||
const classes = this.props.className ? [this.props.className] : [];
|
|
||||||
const otherRequired = filedRequiredList[this.props.fieldName]
|
|
||||||
|
|
||||||
if(this.props.fieldInfo?.rawAttrs?.class?.indexOf('custom_required') >= 0 || otherRequired) {
|
|
||||||
classes.push('custom_required_add')
|
|
||||||
}
|
|
||||||
if (invalid) {
|
|
||||||
classes.push("o_field_invalid");
|
|
||||||
}
|
|
||||||
if (empty) {
|
|
||||||
classes.push("o_form_label_empty");
|
|
||||||
}
|
|
||||||
if (readonly) {
|
|
||||||
classes.push("o_form_label_readonly");
|
|
||||||
}
|
|
||||||
return classes.join(" ");
|
|
||||||
}
|
|
||||||
})
|
|
||||||
|
|
||||||
// 根据进度条设置水印
|
// 根据进度条设置水印
|
||||||
// const statusbar_params = {
|
// const statusbar_params = {
|
||||||
@@ -231,6 +231,7 @@ $(function () {
|
|||||||
clearInterval(timer)
|
clearInterval(timer)
|
||||||
timer = setInterval(() => {
|
timer = setInterval(() => {
|
||||||
timer_count++
|
timer_count++
|
||||||
|
const dom = $('.custom_required')
|
||||||
let tableDom = $('.table_custom_required')
|
let tableDom = $('.table_custom_required')
|
||||||
if (tableDom.length) {
|
if (tableDom.length) {
|
||||||
tableDom = tableDom.eq(0).parents('tr').children('.table_custom_required')
|
tableDom = tableDom.eq(0).parents('tr').children('.table_custom_required')
|
||||||
@@ -242,6 +243,17 @@ $(function () {
|
|||||||
})
|
})
|
||||||
clearInterval(timer)
|
clearInterval(timer)
|
||||||
}
|
}
|
||||||
|
if (dom.length) {
|
||||||
|
dom.each(function () {
|
||||||
|
const requiredDom = $(this).parent().prev().find('label')
|
||||||
|
let t = requiredDom.html()
|
||||||
|
if (t && t.indexOf('c*') < 0) {
|
||||||
|
t = '<i class="c*" style="color: red;margin-left: -4px">*</i>' + t
|
||||||
|
}
|
||||||
|
requiredDom.html(t)
|
||||||
|
})
|
||||||
|
clearInterval(timer)
|
||||||
|
}
|
||||||
if (timer_count == 20) {
|
if (timer_count == 20) {
|
||||||
clearInterval(timer)
|
clearInterval(timer)
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -10,6 +10,7 @@
|
|||||||
</t>
|
</t>
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
<!-- 暂存,同一份文件中有问题,拆分后正常工作 -->
|
<!-- 暂存,同一份文件中有问题,拆分后正常工作 -->
|
||||||
|
|
||||||
<!-- <t t-name="og.web.ListRenderer.Rows" t-inherit="web.ListRenderer.Rows" t-inherit-mode="extension"> -->
|
<!-- <t t-name="og.web.ListRenderer.Rows" t-inherit="web.ListRenderer.Rows" t-inherit-mode="extension"> -->
|
||||||
|
|||||||
@@ -1,4 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
||||||
from . import models
|
from . import models
|
||||||
from . import wizards
|
from . import wizards
|
||||||
|
|||||||
@@ -24,6 +24,9 @@
|
|||||||
|
|
||||||
# always loaded
|
# always loaded
|
||||||
'data': [
|
'data': [
|
||||||
|
'security/ir.model.access.csv',
|
||||||
|
'data/documents_data.xml',
|
||||||
|
'wizards/upload_file_wizard_view.xml',
|
||||||
'views/views.xml',
|
'views/views.xml',
|
||||||
],
|
],
|
||||||
# only loaded in demonstration mode
|
# only loaded in demonstration mode
|
||||||
|
|||||||
3
jikimo_purchase_tier_validation/controllers/__init__.py
Normal file
3
jikimo_purchase_tier_validation/controllers/__init__.py
Normal file
@@ -0,0 +1,3 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
|
||||||
|
from . import controllers
|
||||||
21
jikimo_purchase_tier_validation/controllers/controllers.py
Normal file
21
jikimo_purchase_tier_validation/controllers/controllers.py
Normal file
@@ -0,0 +1,21 @@
|
|||||||
|
# -*- coding: utf-8 -*-
|
||||||
|
# from odoo import http
|
||||||
|
|
||||||
|
|
||||||
|
# class JikimoPurchaseTierValidation(http.Controller):
|
||||||
|
# @http.route('/jikimo_purchase_tier_validation/jikimo_purchase_tier_validation', auth='public')
|
||||||
|
# def index(self, **kw):
|
||||||
|
# return "Hello, world"
|
||||||
|
|
||||||
|
# @http.route('/jikimo_purchase_tier_validation/jikimo_purchase_tier_validation/objects', auth='public')
|
||||||
|
# def list(self, **kw):
|
||||||
|
# return http.request.render('jikimo_purchase_tier_validation.listing', {
|
||||||
|
# 'root': '/jikimo_purchase_tier_validation/jikimo_purchase_tier_validation',
|
||||||
|
# 'objects': http.request.env['jikimo_purchase_tier_validation.jikimo_purchase_tier_validation'].search([]),
|
||||||
|
# })
|
||||||
|
|
||||||
|
# @http.route('/jikimo_purchase_tier_validation/jikimo_purchase_tier_validation/objects/<model("jikimo_purchase_tier_validation.jikimo_purchase_tier_validation"):obj>', auth='public')
|
||||||
|
# def object(self, obj, **kw):
|
||||||
|
# return http.request.render('jikimo_purchase_tier_validation.object', {
|
||||||
|
# 'object': obj
|
||||||
|
# })
|
||||||
11
jikimo_purchase_tier_validation/data/documents_data.xml
Normal file
11
jikimo_purchase_tier_validation/data/documents_data.xml
Normal file
@@ -0,0 +1,11 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<data noupdate="1">
|
||||||
|
<!-- 创建采购合同文件夹 -->
|
||||||
|
<record id="documents_purchase_contracts_folder" model="documents.folder">
|
||||||
|
<field name="name">采购合同</field>
|
||||||
|
<field name="description">存放采购合同相关文件</field>
|
||||||
|
<field name="sequence">10</field>
|
||||||
|
</record>
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
30
jikimo_purchase_tier_validation/demo/demo.xml
Normal file
30
jikimo_purchase_tier_validation/demo/demo.xml
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<!--
|
||||||
|
<record id="object0" model="jikimo_purchase_tier_validation.jikimo_purchase_tier_validation">
|
||||||
|
<field name="name">Object 0</field>
|
||||||
|
<field name="value">0</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object1" model="jikimo_purchase_tier_validation.jikimo_purchase_tier_validation">
|
||||||
|
<field name="name">Object 1</field>
|
||||||
|
<field name="value">10</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object2" model="jikimo_purchase_tier_validation.jikimo_purchase_tier_validation">
|
||||||
|
<field name="name">Object 2</field>
|
||||||
|
<field name="value">20</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object3" model="jikimo_purchase_tier_validation.jikimo_purchase_tier_validation">
|
||||||
|
<field name="name">Object 3</field>
|
||||||
|
<field name="value">30</field>
|
||||||
|
</record>
|
||||||
|
|
||||||
|
<record id="object4" model="jikimo_purchase_tier_validation.jikimo_purchase_tier_validation">
|
||||||
|
<field name="name">Object 4</field>
|
||||||
|
<field name="value">40</field>
|
||||||
|
</record>
|
||||||
|
-->
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
@@ -9,8 +9,6 @@ class jikimo_purchase_tier_validation(models.Model):
|
|||||||
_name = 'purchase.order'
|
_name = 'purchase.order'
|
||||||
_inherit = ['purchase.order', 'tier.validation']
|
_inherit = ['purchase.order', 'tier.validation']
|
||||||
_description = "采购订单"
|
_description = "采购订单"
|
||||||
_state_from = ["draft", "to approve", "rejected"]
|
|
||||||
_state_to = ["approved"]
|
|
||||||
|
|
||||||
_tier_validation_buttons_xpath = "/form/header/button[@id='draft_confirm'][1]"
|
_tier_validation_buttons_xpath = "/form/header/button[@id='draft_confirm'][1]"
|
||||||
|
|
||||||
@@ -23,8 +21,12 @@ class jikimo_purchase_tier_validation(models.Model):
|
|||||||
|
|
||||||
def button_confirm(self):
|
def button_confirm(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.need_validation and not record.validation_status == 'validated':
|
# if record.need_validation and record.validation_status != 'validated':
|
||||||
|
# raise ValidationError(_('此操作需要至少对一条记录进行审批。\n请发起审批申请。'))
|
||||||
|
if record.state in ['to approve']:
|
||||||
raise ValidationError(_('请先完成审批。'))
|
raise ValidationError(_('请先完成审批。'))
|
||||||
|
# if record.state == 'approved':
|
||||||
|
# record.state = 'purchase'
|
||||||
res = super(jikimo_purchase_tier_validation, self).button_confirm()
|
res = super(jikimo_purchase_tier_validation, self).button_confirm()
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.state == 'approved':
|
if record.state == 'approved':
|
||||||
@@ -37,8 +39,45 @@ class jikimo_purchase_tier_validation(models.Model):
|
|||||||
record.message_subscribe([record.partner_id.id])
|
record.message_subscribe([record.partner_id.id])
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
# def button_confirm(self):
|
||||||
|
# self = self.with_context(skip_validation=True)
|
||||||
|
# return super().button_confirm()
|
||||||
|
#
|
||||||
|
# def _check_state_conditions(self, vals):
|
||||||
|
# self.ensure_one()
|
||||||
|
# if self._context.get('skip_validation'):
|
||||||
|
# return False
|
||||||
|
# return (
|
||||||
|
# self._check_state_from_condition()
|
||||||
|
# and vals.get(self._state_field) in self._state_to
|
||||||
|
# )
|
||||||
|
|
||||||
def request_validation(self):
|
def request_validation(self):
|
||||||
for record in self:
|
for record in self:
|
||||||
|
error_messages = []
|
||||||
|
|
||||||
|
# 检查必填字段
|
||||||
|
required_fields = {
|
||||||
|
'partner_ref': '合同名称',
|
||||||
|
'contract_number': '合同编号'
|
||||||
|
}
|
||||||
|
|
||||||
|
missing_fields = [
|
||||||
|
name for field, name in required_fields.items()
|
||||||
|
if not record[field]
|
||||||
|
]
|
||||||
|
|
||||||
|
if missing_fields:
|
||||||
|
error_messages.append('* 如下字段要求必须填写:%s' % '、'.join(missing_fields))
|
||||||
|
|
||||||
|
# 检查合同文件
|
||||||
|
if not record.contract_document_id:
|
||||||
|
error_messages.append('* 必须点击上传合同文件')
|
||||||
|
|
||||||
|
# 如果有任何错误,一次性显示所有错误信息
|
||||||
|
if error_messages:
|
||||||
|
raise ValidationError('\n'.join(error_messages))
|
||||||
|
|
||||||
# 添加通知消息
|
# 添加通知消息
|
||||||
if hasattr(record, 'message_post'):
|
if hasattr(record, 'message_post'):
|
||||||
current_user = self.env.user.name
|
current_user = self.env.user.name
|
||||||
@@ -70,6 +109,11 @@ class jikimo_purchase_tier_validation(models.Model):
|
|||||||
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
|
def _rejected_tier(self, tiers=False):
|
||||||
|
res = super(jikimo_purchase_tier_validation, self)._rejected_tier(tiers)
|
||||||
|
self.state = 'draft'
|
||||||
|
return res
|
||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _get_under_validation_exceptions(self):
|
def _get_under_validation_exceptions(self):
|
||||||
res = super(jikimo_purchase_tier_validation, self)._get_under_validation_exceptions()
|
res = super(jikimo_purchase_tier_validation, self)._get_under_validation_exceptions()
|
||||||
|
|||||||
@@ -0,0 +1,2 @@
|
|||||||
|
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||||
|
access_ir_attachment_wizard,ir.attachment.wizard,model_ir_attachment_wizard,base.group_user,1,1,1,1
|
||||||
|
24
jikimo_purchase_tier_validation/views/templates.xml
Normal file
24
jikimo_purchase_tier_validation/views/templates.xml
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
<odoo>
|
||||||
|
<data>
|
||||||
|
<!--
|
||||||
|
<template id="listing">
|
||||||
|
<ul>
|
||||||
|
<li t-foreach="objects" t-as="object">
|
||||||
|
<a t-attf-href="#{ root }/objects/#{ object.id }">
|
||||||
|
<t t-esc="object.display_name"/>
|
||||||
|
</a>
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
</template>
|
||||||
|
<template id="object">
|
||||||
|
<h1><t t-esc="object.display_name"/></h1>
|
||||||
|
<dl>
|
||||||
|
<t t-foreach="object._fields" t-as="field">
|
||||||
|
<dt><t t-esc="field"/></dt>
|
||||||
|
<dd><t t-esc="object[field]"/></dd>
|
||||||
|
</t>
|
||||||
|
</dl>
|
||||||
|
</template>
|
||||||
|
-->
|
||||||
|
</data>
|
||||||
|
</odoo>
|
||||||
@@ -23,10 +23,76 @@
|
|||||||
<xpath expr="//header/field[@name='state']" position="replace">
|
<xpath expr="//header/field[@name='state']" position="replace">
|
||||||
<field name="state" widget="statusbar" statusbar_visible="draft,sent,to approve, approved, purchase" readonly="1"/>
|
<field name="state" widget="statusbar" statusbar_visible="draft,sent,to approve, approved, purchase" readonly="1"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
|
|
||||||
<xpath expr="//header/button[last()]" position="after">
|
<xpath expr="//header/button[last()]" position="after">
|
||||||
<button name="button_cancel" states="draft,to approve,sent,purchase" string="取消" type="object" data-hotkey="x" />
|
<button name="button_cancel" states="draft,to approve,sent,purchase" string="取消" type="object" data-hotkey="x" />
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
|
<xpath expr="//header/button[@name='action_rfq_send'][1]" position="before">
|
||||||
|
<field name="validation_status" invisible="1"/>
|
||||||
|
<field name="is_upload_contract_file" invisible="1"/>
|
||||||
|
<button name="upload_contract_file" string="上传合同" type="object" class="oe_highlight" attrs="{'invisible': ['|', '|', ('validation_status', '!=', 'no'), ('is_upload_contract_file', '=', True), ('state', 'not in', ['draft', 'sent'])]}"/>]}"/>
|
||||||
|
<button name="delete_contract_file" string="删除合同" type="object" class="oe_highlight" attrs="{'invisible': ['|', ('validation_status', '!=', 'no'), ('is_upload_contract_file', '=', False)]}"/>
|
||||||
|
</xpath>
|
||||||
|
<xpath expr="//notebook/page[1]" position="before">
|
||||||
|
<page string="合同" name="contract_documents"
|
||||||
|
attrs="{'invisible': [('contract_document_id', '=', False)]}"
|
||||||
|
autofocus="autofocus">
|
||||||
|
<group>
|
||||||
|
<group>
|
||||||
|
<field name="contract_document_id" invisible="1"/>
|
||||||
|
<field name="contract_file_name" invisible="1"/>
|
||||||
|
<field name="contract_file"
|
||||||
|
widget="adaptive_viewer"
|
||||||
|
filename="contract_file_name"/>
|
||||||
|
</group>
|
||||||
|
</group>
|
||||||
|
</page>
|
||||||
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
<!-- actions opening views on models -->
|
||||||
|
<!--
|
||||||
|
<record model="ir.actions.act_window" id="jikimo_purchase_tier_validation.action_window">
|
||||||
|
<field name="name">jikimo_purchase_tier_validation window</field>
|
||||||
|
<field name="res_model">jikimo_purchase_tier_validation.jikimo_purchase_tier_validation</field>
|
||||||
|
<field name="view_mode">tree,form</field>
|
||||||
|
</record>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- server action to the one above -->
|
||||||
|
<!--
|
||||||
|
<record model="ir.actions.server" id="jikimo_purchase_tier_validation.action_server">
|
||||||
|
<field name="name">jikimo_purchase_tier_validation server</field>
|
||||||
|
<field name="model_id" ref="model_jikimo_purchase_tier_validation_jikimo_purchase_tier_validation"/>
|
||||||
|
<field name="state">code</field>
|
||||||
|
<field name="code">
|
||||||
|
action = {
|
||||||
|
"type": "ir.actions.act_window",
|
||||||
|
"view_mode": "tree,form",
|
||||||
|
"res_model": model._name,
|
||||||
|
}
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
-->
|
||||||
|
|
||||||
|
<!-- Top menu item -->
|
||||||
|
<!--
|
||||||
|
<menuitem name="jikimo_purchase_tier_validation" id="jikimo_purchase_tier_validation.menu_root"/>
|
||||||
|
-->
|
||||||
|
<!-- menu categories -->
|
||||||
|
<!--
|
||||||
|
<menuitem name="Menu 1" id="jikimo_purchase_tier_validation.menu_1" parent="jikimo_purchase_tier_validation.menu_root"/>
|
||||||
|
<menuitem name="Menu 2" id="jikimo_purchase_tier_validation.menu_2" parent="jikimo_purchase_tier_validation.menu_root"/>
|
||||||
|
-->
|
||||||
|
<!-- actions -->
|
||||||
|
<!--
|
||||||
|
<menuitem name="List" id="jikimo_purchase_tier_validation.menu_1_list" parent="jikimo_purchase_tier_validation.menu_1"
|
||||||
|
action="jikimo_purchase_tier_validation.action_window"/>
|
||||||
|
<menuitem name="Server to list" id="jikimo_purchase_tier_validation" parent="jikimo_purchase_tier_validation.menu_2"
|
||||||
|
action="jikimo_purchase_tier_validation.action_server"/>
|
||||||
|
-->
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -1 +1,2 @@
|
|||||||
|
from . import upload_file_wizard
|
||||||
from . import comment_wizard
|
from . import comment_wizard
|
||||||
114
jikimo_purchase_tier_validation/wizards/upload_file_wizard.py
Normal file
114
jikimo_purchase_tier_validation/wizards/upload_file_wizard.py
Normal file
@@ -0,0 +1,114 @@
|
|||||||
|
from odoo import models, fields, api, _
|
||||||
|
|
||||||
|
|
||||||
|
class IrAttachmentWizard(models.TransientModel):
|
||||||
|
_name = 'ir.attachment.wizard'
|
||||||
|
_description = '文件上传向导'
|
||||||
|
|
||||||
|
attachment = fields.Binary(string='选择文件', required=True)
|
||||||
|
filename = fields.Char(string='文件名')
|
||||||
|
res_model = fields.Char()
|
||||||
|
res_id = fields.Integer()
|
||||||
|
|
||||||
|
# def action_upload_file(self):
|
||||||
|
# self.ensure_one()
|
||||||
|
# # 首先创建 ir.attachment
|
||||||
|
# attachment = self.env['ir.attachment'].create({
|
||||||
|
# 'name': self.filename,
|
||||||
|
# 'type': 'binary',
|
||||||
|
# 'datas': self.attachment,
|
||||||
|
# 'res_model': self.res_model,
|
||||||
|
# 'res_id': self.res_id,
|
||||||
|
# })
|
||||||
|
#
|
||||||
|
# # 获取默认的文档文件夹
|
||||||
|
# workspace = self.env['documents.folder'].search([('name', '=', '采购合同')], limit=1)
|
||||||
|
#
|
||||||
|
# # 创建 documents.document 记录
|
||||||
|
# document = self.env['documents.document'].create({
|
||||||
|
# 'name': self.filename,
|
||||||
|
# 'attachment_id': attachment.id,
|
||||||
|
# 'folder_id': workspace.id,
|
||||||
|
# 'res_model': self.res_model,
|
||||||
|
# 'res_id': self.res_id,
|
||||||
|
# })
|
||||||
|
#
|
||||||
|
# return {
|
||||||
|
# 'type': 'ir.actions.client',
|
||||||
|
# 'tag': 'display_notification',
|
||||||
|
# 'params': {
|
||||||
|
# 'title': _('成功'),
|
||||||
|
# 'message': _('文件上传成功'),
|
||||||
|
# 'type': 'success',
|
||||||
|
# }
|
||||||
|
# }
|
||||||
|
|
||||||
|
def action_upload_file(self):
|
||||||
|
self.ensure_one()
|
||||||
|
# 获取当前用户的 partner_id
|
||||||
|
current_partner = self.env.user.partner_id
|
||||||
|
# 首先创建 ir.attachment
|
||||||
|
attachment = self.env['ir.attachment'].create({
|
||||||
|
'name': self.filename,
|
||||||
|
'type': 'binary',
|
||||||
|
'datas': self.attachment,
|
||||||
|
'res_model': self.res_model,
|
||||||
|
'res_id': self.res_id,
|
||||||
|
})
|
||||||
|
|
||||||
|
# 获取默认的文档文件夹
|
||||||
|
workspace = self.env['documents.folder'].search([('name', '=', '采购合同')], limit=1)
|
||||||
|
|
||||||
|
# 创建 documents.document 记录
|
||||||
|
document = self.env['documents.document'].create({
|
||||||
|
'name': self.filename,
|
||||||
|
'attachment_id': attachment.id,
|
||||||
|
'folder_id': workspace.id,
|
||||||
|
'res_model': self.res_model,
|
||||||
|
'res_id': self.res_id,
|
||||||
|
'partner_id': current_partner.id,
|
||||||
|
})
|
||||||
|
|
||||||
|
# 更新采购订单的合同文档字段
|
||||||
|
purchase_order = self.env['purchase.order'].browse(self.res_id)
|
||||||
|
purchase_order.write({
|
||||||
|
'contract_document_id': document.id,
|
||||||
|
'is_upload_contract_file': True
|
||||||
|
})
|
||||||
|
|
||||||
|
# 显示成功消息并关闭向导
|
||||||
|
message = {
|
||||||
|
'type': 'ir.actions.client',
|
||||||
|
'tag': 'display_notification',
|
||||||
|
'params': {
|
||||||
|
'title': _('成功'),
|
||||||
|
'message': _('文件上传成功'),
|
||||||
|
'type': 'success',
|
||||||
|
'sticky': False, # 自动消失
|
||||||
|
'next': {
|
||||||
|
'type': 'ir.actions.act_window_close'
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return message
|
||||||
|
|
||||||
|
|
||||||
|
# def action_upload_file(self):
|
||||||
|
# self.ensure_one()
|
||||||
|
# attachment = self.env['ir.attachment'].create({
|
||||||
|
# 'name': self.filename,
|
||||||
|
# 'type': 'binary',
|
||||||
|
# 'datas': self.attachment,
|
||||||
|
# 'res_model': self.res_model,
|
||||||
|
# 'res_id': self.res_id,
|
||||||
|
# })
|
||||||
|
# return {
|
||||||
|
# 'type': 'ir.actions.client',
|
||||||
|
# 'tag': 'display_notification',
|
||||||
|
# 'params': {
|
||||||
|
# 'title': _('成功'),
|
||||||
|
# 'message': _('文件上传成功'),
|
||||||
|
# 'type': 'success',
|
||||||
|
# }
|
||||||
|
# }
|
||||||
@@ -0,0 +1,21 @@
|
|||||||
|
<?xml version="1.0" encoding="utf-8"?>
|
||||||
|
<odoo>
|
||||||
|
<record id="view_upload_file_wizard_form" model="ir.ui.view">
|
||||||
|
<field name="name">ir.attachment.wizard.form</field>
|
||||||
|
<field name="model">ir.attachment.wizard</field>
|
||||||
|
<field name="arch" type="xml">
|
||||||
|
<form string="上传文件">
|
||||||
|
<group>
|
||||||
|
<field name="attachment" widget="binary" filename="filename" options="{'accepted_file_extensions': '.pdf,.doc,.docx,.jpg,.jpeg,.png'}"/>
|
||||||
|
<field name="filename" invisible="1"/>
|
||||||
|
<field name="res_model" invisible="1"/>
|
||||||
|
<field name="res_id" invisible="1"/>
|
||||||
|
</group>
|
||||||
|
<footer>
|
||||||
|
<button name="action_upload_file" string="确认上传" type="object" class="btn-primary"/>
|
||||||
|
<button string="取消" class="btn-secondary" special="cancel"/>
|
||||||
|
</footer>
|
||||||
|
</form>
|
||||||
|
</field>
|
||||||
|
</record>
|
||||||
|
</odoo>
|
||||||
@@ -1,3 +0,0 @@
|
|||||||
from . import models
|
|
||||||
from . import controllers
|
|
||||||
from . import wizards
|
|
||||||
@@ -1,32 +0,0 @@
|
|||||||
{
|
|
||||||
'name': '机企猫 测试助手',
|
|
||||||
'version': '16.0.1.0.0',
|
|
||||||
'category': 'Technical',
|
|
||||||
'summary': '测试数据初始化工具',
|
|
||||||
'description': """
|
|
||||||
用于初始化测试环境数据的工具模块
|
|
||||||
""",
|
|
||||||
'author': 'Jikimo',
|
|
||||||
'website': 'www.jikimo.com',
|
|
||||||
'depends': [
|
|
||||||
'base',
|
|
||||||
'sale_management',
|
|
||||||
'purchase',
|
|
||||||
'mrp',
|
|
||||||
'stock',
|
|
||||||
'account'
|
|
||||||
],
|
|
||||||
'data': [
|
|
||||||
'security/ir.model.access.csv',
|
|
||||||
'wizards/jikimo_data_clean_wizard.xml',
|
|
||||||
],
|
|
||||||
'assets': {
|
|
||||||
'web.assets_backend': [
|
|
||||||
'jikimo_test_assistant/static/src/js/data_clean_confirm.js',
|
|
||||||
],
|
|
||||||
},
|
|
||||||
'installable': True,
|
|
||||||
'application': False,
|
|
||||||
'auto_install': False,
|
|
||||||
'license': 'LGPL-3',
|
|
||||||
}
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from . import main
|
|
||||||
@@ -1,86 +0,0 @@
|
|||||||
from odoo import http
|
|
||||||
import logging
|
|
||||||
import os
|
|
||||||
import json
|
|
||||||
import sys
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class Main(http.Controller):
|
|
||||||
@http.route('/api/pdf2image', type='http', auth='public', methods=['POST'], csrf=False)
|
|
||||||
def convert_pdf_to_image(self, **kwargs):
|
|
||||||
"""将PDF文件转换为图片文件
|
|
||||||
|
|
||||||
Returns:
|
|
||||||
dict: 包含转换后图片url的字典
|
|
||||||
"""
|
|
||||||
res = {}
|
|
||||||
try:
|
|
||||||
# 检查poppler是否可用
|
|
||||||
# if sys.platform.startswith('win'):
|
|
||||||
# if not os.environ.get('POPPLER_PATH'):
|
|
||||||
# return {
|
|
||||||
# 'code': 400,
|
|
||||||
# 'msg': '请先配置POPPLER_PATH环境变量'
|
|
||||||
# }
|
|
||||||
# else:
|
|
||||||
# import shutil
|
|
||||||
# if not shutil.which('pdftoppm'):
|
|
||||||
# return {
|
|
||||||
# 'code': 400,
|
|
||||||
# 'msg': '请先安装poppler-utils'
|
|
||||||
# }
|
|
||||||
|
|
||||||
# 获取上传的PDF文件
|
|
||||||
pdf_file = kwargs.get('file')
|
|
||||||
if not pdf_file:
|
|
||||||
res = {'code': 400, 'msg': '未找到上传的PDF文件'}
|
|
||||||
|
|
||||||
# 检查文件类型
|
|
||||||
if not pdf_file.filename.lower().endswith('.pdf'):
|
|
||||||
res = {'code': 400, 'msg': '请上传PDF格式的文件'}
|
|
||||||
|
|
||||||
# 读取PDF文件内容
|
|
||||||
pdf_content = pdf_file.read()
|
|
||||||
|
|
||||||
# 使用pdf2image转换
|
|
||||||
from pdf2image import convert_from_bytes
|
|
||||||
import tempfile
|
|
||||||
|
|
||||||
# 转换PDF
|
|
||||||
with tempfile.TemporaryDirectory() as path:
|
|
||||||
images = convert_from_bytes(pdf_content)
|
|
||||||
image_urls = []
|
|
||||||
|
|
||||||
# 保存每一页为图片
|
|
||||||
for i, image in enumerate(images):
|
|
||||||
image_path = os.path.join(path, f'page_{i+1}.jpg')
|
|
||||||
image.save(image_path, 'JPEG')
|
|
||||||
|
|
||||||
# 将图片保存到ir.attachment
|
|
||||||
with open(image_path, 'rb') as img_file:
|
|
||||||
attachment = http.request.env['ir.attachment'].sudo().create({
|
|
||||||
'name': f'page_{i+1}.jpg',
|
|
||||||
'datas': img_file.read(),
|
|
||||||
'type': 'binary',
|
|
||||||
'access_token': kwargs.get('access_token') or '123'
|
|
||||||
})
|
|
||||||
image_urls.append({
|
|
||||||
'page': i+1,
|
|
||||||
'url': f'/web/content/{attachment.id}'
|
|
||||||
})
|
|
||||||
|
|
||||||
res = {
|
|
||||||
'code': 200,
|
|
||||||
'msg': '转换成功',
|
|
||||||
'data': image_urls
|
|
||||||
}
|
|
||||||
|
|
||||||
except Exception as e:
|
|
||||||
_logger.error('PDF转换失败: %s', str(e))
|
|
||||||
res = {
|
|
||||||
'code': 500,
|
|
||||||
'msg': f'转换失败: {str(e)}'
|
|
||||||
}
|
|
||||||
return json.JSONEncoder().encode(res)
|
|
||||||
|
|
||||||
@@ -1 +0,0 @@
|
|||||||
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
|
||||||
access_jikimo_data_clean_wizard,jikimo_test_assistant.jikimo_data_clean_wizard,model_jikimo_data_clean_wizard,base.group_system,1,1,1,1
|
|
||||||
|
@@ -1,50 +0,0 @@
|
|||||||
odoo.define('jikimo_test_assistant.action_clean_data_confirm', function (require) {
|
|
||||||
const core = require('web.core');
|
|
||||||
const ajax = require('web.ajax');
|
|
||||||
const Dialog = require('web.Dialog');
|
|
||||||
var rpc = require('web.rpc');
|
|
||||||
var _t = core._t;
|
|
||||||
|
|
||||||
async function action_clean_data_confirm(parent, {params}) {
|
|
||||||
let message = "确认清理数据?<br/>"
|
|
||||||
message += "日期:"+ params.date + "以前<br/>"
|
|
||||||
message += "模型:" + params.model_names.join(',')
|
|
||||||
const dialog = new Dialog(parent, {
|
|
||||||
title: "确认",
|
|
||||||
$content: $('<div>').append(message),
|
|
||||||
buttons: [
|
|
||||||
{ text: "确认", classes: 'btn-primary jikimo_button_confirm', close: true, click: () => actionCleanDataConfirm(parent, params) },
|
|
||||||
{ text: "取消", close: true },
|
|
||||||
],
|
|
||||||
});
|
|
||||||
dialog.open();
|
|
||||||
|
|
||||||
|
|
||||||
async function actionCleanDataConfirm(parent, params) {
|
|
||||||
rpc.query({
|
|
||||||
model: 'jikimo.data.clean.wizard',
|
|
||||||
method: 'action_clean_data',
|
|
||||||
args: [params.active_id],
|
|
||||||
kwargs: {
|
|
||||||
context: params.context,
|
|
||||||
}
|
|
||||||
}).then(res => {
|
|
||||||
parent.services.action.doAction({
|
|
||||||
'type': 'ir.actions.client',
|
|
||||||
'tag': 'display_notification',
|
|
||||||
'target': 'new',
|
|
||||||
'params': {
|
|
||||||
'message': '数据清理成功!',
|
|
||||||
'type': 'success',
|
|
||||||
'sticky': false,
|
|
||||||
'next': {'type': 'ir.actions.act_window_close'},
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
core.action_registry.add('action_clean_data_confirm', action_clean_data_confirm);
|
|
||||||
return action_clean_data_confirm;
|
|
||||||
});
|
|
||||||
@@ -1,2 +0,0 @@
|
|||||||
# -*- coding: utf-8 -*-
|
|
||||||
from . import jikimo_data_clean_wizard
|
|
||||||
@@ -1,99 +0,0 @@
|
|||||||
from odoo import models, fields, api
|
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
import logging
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
|
||||||
|
|
||||||
class JikimoDataCleanWizard(models.TransientModel):
|
|
||||||
_name = 'jikimo.data.clean.wizard'
|
|
||||||
_description = '业务数据清理'
|
|
||||||
|
|
||||||
date = fields.Date(string='截止日期', required=True, default=fields.Date.context_today)
|
|
||||||
model_ids = fields.Many2many('ir.model', string='业务模型', domain=[
|
|
||||||
('model', 'in', [
|
|
||||||
'sale.order', # 销售订单
|
|
||||||
'purchase.order', # 采购订单
|
|
||||||
'mrp.production', # 生产订单
|
|
||||||
'stock.picking', # 库存调拨
|
|
||||||
'account.move', # 会计凭证
|
|
||||||
])
|
|
||||||
])
|
|
||||||
|
|
||||||
def action_clean_data(self):
|
|
||||||
self.ensure_one()
|
|
||||||
model_list = self.model_ids.mapped('model')
|
|
||||||
|
|
||||||
# 销售订单清理(排除已交付,已锁定,已取消)
|
|
||||||
if 'sale.order' in model_list:
|
|
||||||
self.model_cancel('sale.order', except_states=['delivered', 'done', 'cancel'])
|
|
||||||
|
|
||||||
# 采购订单清理(排除采购订单,已锁定,已取消)
|
|
||||||
if 'purchase.order' in model_list:
|
|
||||||
self.model_cancel('purchase.order', except_states=['purchase', 'done', 'cancel'])
|
|
||||||
|
|
||||||
# 生产订单清理(排除返工,报废,完成,已取消)
|
|
||||||
if 'mrp.production' in model_list:
|
|
||||||
self.model_cancel('mrp.production', except_states=['rework', 'scrap', 'done', 'cancel'])
|
|
||||||
|
|
||||||
# 工单清理 (排除返工,完成,已取消)
|
|
||||||
if 'mrp.workorder' in model_list:
|
|
||||||
self.model_cancel('mrp.production', except_states=['rework', 'done', 'cancel'])
|
|
||||||
|
|
||||||
# 排程单清理 (排除已完成,已取消)
|
|
||||||
if 'mrp.workorder' in model_list:
|
|
||||||
self.model_cancel('mrp.production', except_states=['finished', 'cancel'])
|
|
||||||
|
|
||||||
# 工单库存移动 (排除完成,已取消)
|
|
||||||
if 'stock.move' in model_list:
|
|
||||||
self.model_cancel('stock.move')
|
|
||||||
|
|
||||||
# 库存调拨清理 (排除完成,已取消)
|
|
||||||
if 'stock.picking' in model_list:
|
|
||||||
self.model_cancel('stock.picking')
|
|
||||||
|
|
||||||
# 会计凭证清理 (排除已过账,已取消)
|
|
||||||
if 'account.move' in model_list:
|
|
||||||
self.model_cancel('account.move', except_states=['posted', 'cancel'])
|
|
||||||
|
|
||||||
return True
|
|
||||||
|
|
||||||
def model_cancel(self, model_name, state_field='state', to_state='cancel',except_states=('done', 'cancel')):
|
|
||||||
table = self.env[model_name]._table
|
|
||||||
if isinstance(except_states, list):
|
|
||||||
except_states = tuple(except_states)
|
|
||||||
sql = """
|
|
||||||
UPDATE
|
|
||||||
%s SET %s = '%s'
|
|
||||||
WHERE
|
|
||||||
create_date < '%s'
|
|
||||||
AND state NOT IN %s
|
|
||||||
""" % (table, state_field, to_state, self.date.strftime('%Y-%m-%d'), except_states)
|
|
||||||
self.env.cr.execute(sql)
|
|
||||||
self.env.cr.commit()
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def get_confirm_message(self):
|
|
||||||
date_str = self.date.strftime('%Y-%m-%d') if self.date else ''
|
|
||||||
model_names = ', '.join([model.name for model in self.model_ids])
|
|
||||||
return {
|
|
||||||
'date': date_str,
|
|
||||||
'model_names': model_names
|
|
||||||
}
|
|
||||||
|
|
||||||
def action_clean_data_confirm(self):
|
|
||||||
model_names = self.model_ids.mapped('display_name')
|
|
||||||
return {
|
|
||||||
'type': 'ir.actions.client',
|
|
||||||
'tag': 'action_clean_data_confirm',
|
|
||||||
'params': {
|
|
||||||
'model_names': model_names,
|
|
||||||
'date': self.date,
|
|
||||||
'active_id': self.id,
|
|
||||||
'context': self.env.context
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
@@ -1,47 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<odoo>
|
|
||||||
<!-- Form View -->
|
|
||||||
<record id="view_jikimo_data_clean_form" model="ir.ui.view">
|
|
||||||
<field name="name">jikimo.data.clean.wizard.form</field>
|
|
||||||
<field name="model">jikimo.data.clean.wizard</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="业务数据清理">
|
|
||||||
<sheet>
|
|
||||||
<group>
|
|
||||||
<field name="date"/>
|
|
||||||
<field name="model_ids" widget="many2many_tags"/>
|
|
||||||
</group>
|
|
||||||
</sheet>
|
|
||||||
<footer>
|
|
||||||
<button name="action_clean_data_confirm"
|
|
||||||
string="确认清理"
|
|
||||||
type="object"
|
|
||||||
class="btn-primary"/>
|
|
||||||
<button special="cancel"
|
|
||||||
string="取消"
|
|
||||||
class="btn-secondary"/>
|
|
||||||
</footer>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Action -->
|
|
||||||
<record id="action_jikimo_data_clean" model="ir.actions.act_window">
|
|
||||||
<field name="name">业务数据清理</field>
|
|
||||||
<field name="res_model">jikimo.data.clean.wizard</field>
|
|
||||||
<field name="view_mode">form</field>
|
|
||||||
<field name="target">new</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- Menu -->
|
|
||||||
<menuitem id="menu_test_root"
|
|
||||||
name="测试"
|
|
||||||
parent="base.menu_custom"
|
|
||||||
sequence="100"/>
|
|
||||||
|
|
||||||
<menuitem id="menu_jikimo_data_clean"
|
|
||||||
name="业务数据清理"
|
|
||||||
parent="menu_test_root"
|
|
||||||
action="action_jikimo_data_clean"
|
|
||||||
sequence="10"/>
|
|
||||||
</odoo>
|
|
||||||
@@ -4,7 +4,6 @@ import json
|
|||||||
import logging
|
import logging
|
||||||
from odoo.addons.sf_mrs_connect.controllers.controllers import Sf_Mrs_Connect
|
from odoo.addons.sf_mrs_connect.controllers.controllers import Sf_Mrs_Connect
|
||||||
from odoo.addons.sf_manufacturing.controllers.controllers import Manufacturing_Connect
|
from odoo.addons.sf_manufacturing.controllers.controllers import Manufacturing_Connect
|
||||||
from datetime import datetime
|
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
|
|
||||||
@@ -31,7 +30,6 @@ class WorkorderExceptionConroller(http.Controller):
|
|||||||
workorder = request.env['mrp.workorder'].sudo().search([
|
workorder = request.env['mrp.workorder'].sudo().search([
|
||||||
('rfid_code', '=', ret['RfidCode']),
|
('rfid_code', '=', ret['RfidCode']),
|
||||||
('routing_type', '=', 'CNC加工'),
|
('routing_type', '=', 'CNC加工'),
|
||||||
('state', '!=', 'rework')
|
|
||||||
])
|
])
|
||||||
if not workorder:
|
if not workorder:
|
||||||
res = {'Succeed': False, 'ErrorCode': 401, 'Error': '无效的工单'}
|
res = {'Succeed': False, 'ErrorCode': 401, 'Error': '无效的工单'}
|
||||||
@@ -43,10 +41,7 @@ class WorkorderExceptionConroller(http.Controller):
|
|||||||
'exception_code': ret.get('coding'),
|
'exception_code': ret.get('coding'),
|
||||||
'exception_content': ret.get('Error', '')
|
'exception_content': ret.get('Error', '')
|
||||||
})
|
})
|
||||||
# 申请重新编程
|
|
||||||
workorder.production_id.update_programming_state(trigger_time=datetime.now().strftime('%Y-%m-%d %H:%M:%S'),
|
|
||||||
reprogramming_reason=ret.get('Error', ''))
|
|
||||||
workorder.production_id.write({'programming_state': '编程中', 'work_state': '编程中', 'is_rework': False})
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
||||||
_logger.info('workder_exception error:%s' % e)
|
_logger.info('workder_exception error:%s' % e)
|
||||||
|
|||||||
@@ -8,7 +8,7 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//notebook/page[last()]" position="after">
|
<xpath expr="//notebook/page[last()]" position="after">
|
||||||
<field name="routing_type" invisible="1"/>
|
<field name="routing_type" invisible="1"/>
|
||||||
<page string="异常记录" name="workorder_exception" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "ER")]}'>
|
<page string="异常记录" name="workorder_exception" attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}">
|
||||||
<field name="exception_ids" nolabel="1" readonly="1">
|
<field name="exception_ids" nolabel="1" readonly="1">
|
||||||
<tree create="false" delete="false" edit="false">
|
<tree create="false" delete="false" edit="false">
|
||||||
<field name="exception_content" string="反馈的异常/问题信息"/>
|
<field name="exception_content" string="反馈的异常/问题信息"/>
|
||||||
|
|||||||
@@ -187,7 +187,7 @@ class CuttingToolModel(models.Model):
|
|||||||
def _get_ids(self, cutting_tool_type_code, factory_short_name):
|
def _get_ids(self, cutting_tool_type_code, factory_short_name):
|
||||||
cutting_tool_type_ids = []
|
cutting_tool_type_ids = []
|
||||||
for item in cutting_tool_type_code:
|
for item in cutting_tool_type_code:
|
||||||
cutting_tool_type = self.search([('code', '=', item)])
|
cutting_tool_type = self.search([('code', '=', item.replace("JKM", factory_short_name))])
|
||||||
if cutting_tool_type:
|
if cutting_tool_type:
|
||||||
cutting_tool_type_ids.append(cutting_tool_type.id)
|
cutting_tool_type_ids.append(cutting_tool_type.id)
|
||||||
return [(6, 0, cutting_tool_type_ids)]
|
return [(6, 0, cutting_tool_type_ids)]
|
||||||
|
|||||||
@@ -9,7 +9,6 @@ function getDomData() {
|
|||||||
table.hide()
|
table.hide()
|
||||||
const thead = customTable.children('thead')
|
const thead = customTable.children('thead')
|
||||||
const tbody = customTable.children('tbody')
|
const tbody = customTable.children('tbody')
|
||||||
const tfooter = customTable.children('tfoot')
|
|
||||||
const tableData = []
|
const tableData = []
|
||||||
const tbody_child = tbody.children()
|
const tbody_child = tbody.children()
|
||||||
|
|
||||||
@@ -17,29 +16,30 @@ function getDomData() {
|
|||||||
|
|
||||||
for (let v = 0; v < tbody_child_len; v++) { // 将数据取出来到tableData里面
|
for (let v = 0; v < tbody_child_len; v++) { // 将数据取出来到tableData里面
|
||||||
const data = tbody_child[v].innerText.split('\t')
|
const data = tbody_child[v].innerText.split('\t')
|
||||||
|
// console.log('dom data',data)
|
||||||
const [index, deep, name, Φ, value] = data
|
const [index, deep, name, Φ, value] = data
|
||||||
tableData.push({index, deep, name, Φ, value})
|
tableData.push({index, deep, name, Φ, value})
|
||||||
}
|
}
|
||||||
const ΦList = [...new Set(tableData.map(_ => _.Φ))] // ΦList去重
|
const ΦList = [...new Set(tableData.map(_ => _.name))] // ΦList去重
|
||||||
const newTableData = {}
|
const newTableData = {}
|
||||||
tableData.forEach(_ => {
|
tableData.forEach(_ => {
|
||||||
const key = _.deep + '|' + _.name
|
const key = _.deep + '|' + _.Φ
|
||||||
!newTableData[key] ? newTableData[key] = {i: _.index} : '';
|
!newTableData[key] ? newTableData[key] = {i: _.index} : '';
|
||||||
if (_.Φ) { // 去除没有Φ的脏数据
|
if (_.Φ) { // 去除没有Φ的脏数据
|
||||||
newTableData[key]['Φ' + _.Φ] = _.value
|
newTableData[key]['Φ' + _.Φ] = _.value
|
||||||
newTableData[key]['Φ' + _.Φ + 'i'] = _.index
|
newTableData[key]['Φ' + _.Φ + 'i'] = _.index
|
||||||
}
|
}
|
||||||
})
|
})
|
||||||
// console.log(tableData, ΦList, newTableData);
|
// console.log('qwdh',tableData, ΦList, newTableData);
|
||||||
|
|
||||||
if (ΦList.filter(_ => _).length == 0) return;
|
if (ΦList.filter(_ => _).length == 0) return;
|
||||||
handleThead(thead, ΦList, tfooter)
|
handleThead(thead, ΦList)
|
||||||
|
|
||||||
handleTbody(tbody, newTableData, ΦList, table)
|
handleTbody(tbody, newTableData, ΦList, table)
|
||||||
}
|
}
|
||||||
|
|
||||||
// 重新设置表头、
|
// 重新设置表头、
|
||||||
function handleThead(thead, ΦList, tfooter) {
|
function handleThead(thead, ΦList) {
|
||||||
const dom = thead.children().eq(0).children()
|
const dom = thead.children().eq(0).children()
|
||||||
const len = dom.length
|
const len = dom.length
|
||||||
dom.eq(0).attr('rowspan', 2)
|
dom.eq(0).attr('rowspan', 2)
|
||||||
@@ -47,11 +47,7 @@ function handleThead(thead, ΦList, tfooter) {
|
|||||||
len == 5 ? dom.eq(2).attr('rowspan', 2) : ''
|
len == 5 ? dom.eq(2).attr('rowspan', 2) : ''
|
||||||
dom.eq(-2).attr('colspan', ΦList.length)
|
dom.eq(-2).attr('colspan', ΦList.length)
|
||||||
dom.eq(-1).remove()
|
dom.eq(-1).remove()
|
||||||
if(tfooter && tfooter.length) {
|
|
||||||
tfooter.children().each(function () {
|
|
||||||
$(this).children().eq(-1).remove()
|
|
||||||
})
|
|
||||||
}
|
|
||||||
const tr = document.createElement('tr')
|
const tr = document.createElement('tr')
|
||||||
for (let v = 0; v < ΦList.length; v++) {
|
for (let v = 0; v < ΦList.length; v++) {
|
||||||
const th = document.createElement('th')
|
const th = document.createElement('th')
|
||||||
@@ -72,6 +68,7 @@ function handleTbody(tbody, newTableData, ΦList, table) {
|
|||||||
// b = b.split('=')[1].split('%')[0]
|
// b = b.split('=')[1].split('%')[0]
|
||||||
// return a - b
|
// return a - b
|
||||||
// })
|
// })
|
||||||
|
// console.log('wqoqw ',ΦList)
|
||||||
data.forEach(_ => {
|
data.forEach(_ => {
|
||||||
i++
|
i++
|
||||||
const tr = $('<tr class="o_data_row"></tr>')
|
const tr = $('<tr class="o_data_row"></tr>')
|
||||||
@@ -101,6 +98,61 @@ function handleTbody(tbody, newTableData, ΦList, table) {
|
|||||||
// // }
|
// // }
|
||||||
tbody.append(tr)
|
tbody.append(tr)
|
||||||
})
|
})
|
||||||
|
// $(document).click(function (e) {
|
||||||
|
// if ($(e.target).attr('coustomTd')) {
|
||||||
|
// const orginV = $('[coustomInput=1]').children('input').val()
|
||||||
|
// $('[coustomInput=1]').parent().html(orginV)
|
||||||
|
// const v = $(e.target).attr('val')
|
||||||
|
// console.log($(e.target));
|
||||||
|
// $(e.target).html('')
|
||||||
|
// const input = $('<div coustomInput="1" name="feed_per_tooth" class="o_field_widget o_field_char"><input class="o_input" type="text" autocomplete="off" maxlength="20"></div>')
|
||||||
|
// input.children('input').val(v)
|
||||||
|
// $(e.target).append(input)
|
||||||
|
// input.children('input').focus()
|
||||||
|
// input.children('input').select()
|
||||||
|
// } else if ($(e.target).attr('coustomInput')) {
|
||||||
|
//
|
||||||
|
// } else {
|
||||||
|
// const orginV = $('[coustomInput=1]').children('input').val()
|
||||||
|
// $('[coustomInput=1]').parent().html(orginV)
|
||||||
|
// const v = $(e.target).attr('val')
|
||||||
|
// }
|
||||||
|
// })
|
||||||
|
// $(document).off('change') // 防止重复绑定
|
||||||
|
// $(document).on('change', '[coustomInput] input', function () {
|
||||||
|
// $(this).parents('td').attr('val', $(this).val());
|
||||||
|
// var eve1 = new Event('change');
|
||||||
|
// var eve2 = new Event('input');
|
||||||
|
// var eve3 = new Event('click');
|
||||||
|
// const i = $(this).parents('td').attr('col');
|
||||||
|
// let patchDom = table.find('tbody').children('tr').eq(i - 1);
|
||||||
|
//
|
||||||
|
// if (patchDom.length === 0) {
|
||||||
|
// console.error('No such row found');
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
//
|
||||||
|
// patchDom = patchDom.children().eq(-1);
|
||||||
|
//
|
||||||
|
// setTimeout(() => {
|
||||||
|
// if (patchDom.length === 0) {
|
||||||
|
// console.error('No such cell found');
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// patchDom[0].dispatchEvent(eve3); // Simulate click event
|
||||||
|
//
|
||||||
|
// setTimeout(() => {
|
||||||
|
// patchDom = patchDom.find('input');
|
||||||
|
// if (patchDom.length === 0) {
|
||||||
|
// console.error('No input found in the target cell');
|
||||||
|
// return;
|
||||||
|
// }
|
||||||
|
// patchDom.val($(this).val());
|
||||||
|
// patchDom[0].dispatchEvent(eve2);
|
||||||
|
// patchDom[0].dispatchEvent(eve1);
|
||||||
|
// }, 200);
|
||||||
|
// }, 500);
|
||||||
|
// });
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -25,17 +25,3 @@
|
|||||||
.o_search_panel.account_root {
|
.o_search_panel.account_root {
|
||||||
flex: unset !important;
|
flex: unset !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.multi-line {
|
|
||||||
display: flex;
|
|
||||||
flex-wrap: nowrap;
|
|
||||||
> label.o_form_label {
|
|
||||||
width: 52px;
|
|
||||||
}
|
|
||||||
> span {
|
|
||||||
flex: 1;
|
|
||||||
}
|
|
||||||
> div {
|
|
||||||
flex: 2
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -112,8 +112,6 @@
|
|||||||
<field name="cutting_tool_material_id"/>
|
<field name="cutting_tool_material_id"/>
|
||||||
<field name="cutting_tool_type_id"/>
|
<field name="cutting_tool_type_id"/>
|
||||||
<field name="brand_id"/>
|
<field name="brand_id"/>
|
||||||
<field name="create_date" optional="hide"/>
|
|
||||||
<field name="write_date" string="修改时间" optional="hide"/>
|
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -140,7 +138,7 @@
|
|||||||
<field name="brand_id" required="1"/>
|
<field name="brand_id" required="1"/>
|
||||||
<label for="integral_run_out_accuracy_min" string="端跳精度"
|
<label for="integral_run_out_accuracy_min" string="端跳精度"
|
||||||
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')]}"/>
|
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')]}"/>
|
||||||
<div class="o_address_format multi-line"
|
<div class="o_address_format"
|
||||||
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')]}">
|
attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')]}">
|
||||||
<label for="integral_run_out_accuracy_min" string="最小"/>
|
<label for="integral_run_out_accuracy_min" string="最小"/>
|
||||||
<field name="integral_run_out_accuracy_min" class="o_address_zip"
|
<field name="integral_run_out_accuracy_min" class="o_address_zip"
|
||||||
@@ -179,33 +177,33 @@
|
|||||||
</group>
|
</group>
|
||||||
<group string="适配刀片形状"
|
<group string="适配刀片形状"
|
||||||
attrs="{'invisible': [('cutting_tool_type', 'in', ('刀柄','夹头','整体式刀具',False))]}">
|
attrs="{'invisible': [('cutting_tool_type', 'in', ('刀柄','夹头','整体式刀具',False))]}">
|
||||||
<field name="fit_blade_shape_id" string="" widget="many2one_radio" attrs="{'showExpand': True}"/>
|
<field name="fit_blade_shape_id" string="" widget="many2one_radio"/>
|
||||||
</group>
|
</group>
|
||||||
<group string="适合加工方式"
|
<group string="适合加工方式"
|
||||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀杆','刀盘','刀片'))]}">
|
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀杆','刀盘','刀片'))]}">
|
||||||
<field name="suitable_machining_method_ids" string=""
|
<field name="suitable_machining_method_ids" string=""
|
||||||
widget="custom_many2many_checkboxes" attrs="{'showExpand': True}"/>
|
widget="custom_many2many_checkboxes"/>
|
||||||
</group>
|
</group>
|
||||||
<group string="刀尖特征"
|
<group string="刀尖特征"
|
||||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀杆','刀盘','刀片'))]}">
|
attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀杆','刀盘','刀片'))]}">
|
||||||
<field name="blade_tip_characteristics_id" string=""
|
<field name="blade_tip_characteristics_id" string=""
|
||||||
widget="many2one_radio" attrs="{'showExpand': True}"/>
|
widget="many2one_radio"/>
|
||||||
</group>
|
</group>
|
||||||
<group attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀杆','刀盘','刀片'))]}">
|
<group attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀杆','刀盘','刀片'))]}">
|
||||||
<group string="柄部类型" attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')]}">
|
<group string="柄部类型" attrs="{'invisible': [('cutting_tool_type', '!=', '整体式刀具')]}">
|
||||||
<field name="handle_type_id" string="" widget="many2one_radio" attrs="{'showExpand': True}"/>
|
<field name="handle_type_id" string="" widget="many2one_radio"/>
|
||||||
</group>
|
</group>
|
||||||
<group string="压紧方式"
|
<group string="压紧方式"
|
||||||
attrs="{'invisible': [('cutting_tool_type', 'not in', ('刀杆','刀盘'))]}">
|
attrs="{'invisible': [('cutting_tool_type', 'not in', ('刀杆','刀盘'))]}">
|
||||||
<field name="compaction_way_id" string="" widget="many2one_radio" attrs="{'showExpand': True}"/>
|
<field name="compaction_way_id" string="" widget="many2one_radio"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<group attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀杆','刀盘','刀片'))]}">
|
<group attrs="{'invisible': [('cutting_tool_type', 'not in', ('整体式刀具','刀杆','刀盘','刀片'))]}">
|
||||||
<group string="走刀方向">
|
<group string="走刀方向">
|
||||||
<field name="cutting_direction_ids" string="" widget="custom_many2many_checkboxes" attrs="{'showExpand': True}"/>
|
<field name="cutting_direction_ids" string="" widget="custom_many2many_checkboxes"/>
|
||||||
</group>
|
</group>
|
||||||
<group string="适合冷却方式">
|
<group string="适合冷却方式">
|
||||||
<field name="suitable_coolant_ids" string="" widget="custom_many2many_checkboxes" attrs="{'showExpand': True}" />
|
<field name="suitable_coolant_ids" string="" widget="custom_many2many_checkboxes"/>
|
||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
<notebook>
|
<notebook>
|
||||||
@@ -319,28 +317,28 @@
|
|||||||
|
|
||||||
<field name="knife_handle_basic_parameters_ids"
|
<field name="knife_handle_basic_parameters_ids"
|
||||||
attrs="{'invisible': [('cutting_tool_type', '!=', '刀柄')]}">
|
attrs="{'invisible': [('cutting_tool_type', '!=', '刀柄')]}">
|
||||||
<tree editable="bottom" delete="1">
|
<tree editable="bottom" class="center" delete="1">
|
||||||
<field name="cutting_tool_type" invisible="1"/>
|
<field name="cutting_tool_type" invisible="1"/>
|
||||||
<field name="name"/>
|
<field name="name"/>
|
||||||
<field name="taper_shank_model"/>
|
<field name="taper_shank_model"/>
|
||||||
<field name="total_length"/>
|
<field name="total_length"/>
|
||||||
<field name="shank_length"/>
|
<field name="shank_length"/>
|
||||||
<field name="shank_diameter" class="diameter"/>
|
<field name="shank_diameter" class="diameter"/>
|
||||||
<field name="flange_shank_length" optional="hide"/>
|
<field name="flange_shank_length"/>
|
||||||
<field name="flange_diameter" optional="hide"/>
|
<field name="flange_diameter"/>
|
||||||
<field name="diameter_slip_accuracy" optional="hide"/>
|
<field name="diameter_slip_accuracy"/>
|
||||||
<field name="dynamic_balance_class" optional="hide"/>
|
<field name="dynamic_balance_class"/>
|
||||||
<field name="min_clamping_diameter" class="diameter"/>
|
<field name="min_clamping_diameter" class="diameter"/>
|
||||||
<field name="max_clamping_diameter" class="diameter"/>
|
<field name="max_clamping_diameter" class="diameter"/>
|
||||||
<field name="max_rotate_speed" optional="hide"/>
|
<field name="max_rotate_speed"/>
|
||||||
<field name="fit_chuck_size"/>
|
<field name="fit_chuck_size"/>
|
||||||
<field name="nut" optional="hide"/>
|
<field name="nut"/>
|
||||||
<field name="spanner" string="适配锁紧扳手型号" optional="hide"/>
|
<field name="spanner" string="适配锁紧扳手型号"/>
|
||||||
<field name="clamping_mode" optional="hide"/>
|
<field name="clamping_mode"/>
|
||||||
<field name="tool_changing_time" optional="hide"/>
|
<field name="tool_changing_time"/>
|
||||||
<field name="cooling_model" optional="hide"/>
|
<field name="cooling_model"/>
|
||||||
<field name="is_quick_cutting" optional="hide"/>
|
<field name="is_quick_cutting"/>
|
||||||
<field name="is_safe_lock" optional="hide"/>
|
<field name="is_safe_lock"/>
|
||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
<field name="chuck_basic_parameters_ids"
|
<field name="chuck_basic_parameters_ids"
|
||||||
|
|||||||
@@ -132,26 +132,6 @@ class Sf_Bf_Connect(http.Controller):
|
|||||||
request.cr.rollback()
|
request.cr.rollback()
|
||||||
return json.JSONEncoder().encode(res)
|
return json.JSONEncoder().encode(res)
|
||||||
|
|
||||||
@http.route('/api/bfm_cancel_order', type='http', auth='sf_token', methods=['GET', 'POST'], csrf=False,
|
|
||||||
cors="*")
|
|
||||||
def get_bfm_cancel_order(self, **kw):
|
|
||||||
"""
|
|
||||||
业务平台取消销售订单
|
|
||||||
:param kw:
|
|
||||||
:return:
|
|
||||||
"""
|
|
||||||
res = {'status': 1, 'message': '工厂取消销售订单成功'}
|
|
||||||
logging.info('get_bfm_cancel_order:%s' % kw['order_number'])
|
|
||||||
try:
|
|
||||||
sale_order_info = request.env['sale.order'].sudo().search([('name', '=', kw['order_number'])])
|
|
||||||
sale_order_info._action_cancel()
|
|
||||||
return json.JSONEncoder().encode(res)
|
|
||||||
except Exception as e:
|
|
||||||
logging.error('get_bfm_cancel_order error: %s' % e)
|
|
||||||
res['status'] = -1
|
|
||||||
res['message'] = '工厂取消销售订单失败,请联系管理员'
|
|
||||||
return json.JSONEncoder().encode(res)
|
|
||||||
|
|
||||||
|
|
||||||
class jdElcp(http.Controller):
|
class jdElcp(http.Controller):
|
||||||
|
|
||||||
|
|||||||
@@ -72,7 +72,7 @@ class StatusChange(models.Model):
|
|||||||
logging.info('函数已经执行=============')
|
logging.info('函数已经执行=============')
|
||||||
|
|
||||||
# 使用super()来调用原始方法(在本例中为'sale.order'模型的'action_cancel'方法)
|
# 使用super()来调用原始方法(在本例中为'sale.order'模型的'action_cancel'方法)
|
||||||
res = super(StatusChange, self.with_context(disable_cancel_warning=True)).action_cancel()
|
res = super(StatusChange, self).action_cancel()
|
||||||
|
|
||||||
# 原有方法执行后,进行额外的操作(如调用外部API)
|
# 原有方法执行后,进行额外的操作(如调用外部API)
|
||||||
logging.info('函数已经执行=============2')
|
logging.info('函数已经执行=============2')
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<field name="inherit_id" ref="sf_manufacturing.view_mrp_production_workorder_tray_form_inherit_sf"/>
|
<field name="inherit_id" ref="sf_manufacturing.view_mrp_production_workorder_tray_form_inherit_sf"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//page[1]" position="before">
|
<xpath expr="//page[1]" position="before">
|
||||||
<page string="开料要求" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "CMR")]}'>
|
<page string="开料要求" attrs='{"invisible": [("routing_type","!=","切割")]}'>
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="product_tmpl_id_materials_id" widget="many2one"/>
|
<field name="product_tmpl_id_materials_id" widget="many2one"/>
|
||||||
|
|||||||
@@ -7,7 +7,7 @@
|
|||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//page[last()-3]" position="before">
|
<xpath expr="//page[last()-3]" position="before">
|
||||||
<!-- <page string="下发记录" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>-->
|
<!-- <page string="下发记录" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>-->
|
||||||
<page string="下发记录" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "HDR")]}'>
|
<page string="下发记录" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||||
<field name="delivery_records">
|
<field name="delivery_records">
|
||||||
<tree create="false">
|
<tree create="false">
|
||||||
<field name="delivery_type"/>
|
<field name="delivery_type"/>
|
||||||
|
|||||||
@@ -6,7 +6,7 @@
|
|||||||
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
|
<field name="inherit_id" ref="mrp.mrp_production_workorder_form_view_inherit"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//page[last()-3]" position="before">
|
<xpath expr="//page[last()-3]" position="before">
|
||||||
<page string="机床信息" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "MTI")]}'>
|
<page string="机床信息" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||||
<group string="机床信息">
|
<group string="机床信息">
|
||||||
<group>
|
<group>
|
||||||
<field name="machine_tool_name"/>
|
<field name="machine_tool_name"/>
|
||||||
|
|||||||
@@ -27,7 +27,6 @@
|
|||||||
'wizard/production_technology_re_adjust_wizard_views.xml',
|
'wizard/production_technology_re_adjust_wizard_views.xml',
|
||||||
'wizard/mrp_workorder_batch_replan_wizard_views.xml',
|
'wizard/mrp_workorder_batch_replan_wizard_views.xml',
|
||||||
'wizard/sf_programming_reason_views.xml',
|
'wizard/sf_programming_reason_views.xml',
|
||||||
'wizard/sale_order_cancel_views.xml',
|
|
||||||
'views/mrp_views_menus.xml',
|
'views/mrp_views_menus.xml',
|
||||||
'views/agv_scheduling_views.xml',
|
'views/agv_scheduling_views.xml',
|
||||||
'views/stock_lot_views.xml',
|
'views/stock_lot_views.xml',
|
||||||
|
|||||||
@@ -596,9 +596,6 @@ class Manufacturing_Connect(http.Controller):
|
|||||||
if panel_workorder:
|
if panel_workorder:
|
||||||
panel_workorder.write({'production_line_state': '已下产线'})
|
panel_workorder.write({'production_line_state': '已下产线'})
|
||||||
workorder.write({'state': 'to be detected'})
|
workorder.write({'state': 'to be detected'})
|
||||||
workorder.check_ids.filtered(
|
|
||||||
lambda ch: ch.quality_state == 'waiting').write(
|
|
||||||
{'quality_state': 'none'})
|
|
||||||
else:
|
else:
|
||||||
res = {'Succeed': False, 'ErrorCode': 204,
|
res = {'Succeed': False, 'ErrorCode': 204,
|
||||||
'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}
|
'Error': 'DeviceId为%s没有对应的已配送工件数据' % ret['DeviceId']}
|
||||||
|
|||||||
@@ -4,63 +4,5 @@
|
|||||||
<field name="code">PTD</field>
|
<field name="code">PTD</field>
|
||||||
<field name="name">后置三元检测</field>
|
<field name="name">后置三元检测</field>
|
||||||
</record>
|
</record>
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_2">
|
|
||||||
<field name="code">WCP</field>
|
|
||||||
<field name="name">工件装夹</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_3">
|
|
||||||
<field name="code">ITD_PP</field>
|
|
||||||
<field name="name">前置三元检测定位参数</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_4">
|
|
||||||
<field name="code">2D_MD</field>
|
|
||||||
<field name="name">2D加工图纸</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_5">
|
|
||||||
<field name="code">QIS</field>
|
|
||||||
<field name="name">质检标准</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_6">
|
|
||||||
<field name="code">WD</field>
|
|
||||||
<field name="name">工件配送</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_9">
|
|
||||||
<field name="code">CNC_P</field>
|
|
||||||
<field name="name">CNC程序</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_10">
|
|
||||||
<field name="code">CMM_P</field>
|
|
||||||
<field name="name">CMM程序</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_11">
|
|
||||||
<field name="code">MTI</field>
|
|
||||||
<field name="name">机床信息</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_12">
|
|
||||||
<field name="code">HDR</field>
|
|
||||||
<field name="name">下发记录</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_13">
|
|
||||||
<field name="code">ER</field>
|
|
||||||
<field name="name">异常记录</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_14">
|
|
||||||
<field name="code">DCP</field>
|
|
||||||
<field name="name">解除装夹</field>
|
|
||||||
</record>
|
|
||||||
<record model="sf.work.individuation.page" id="sf_work_individuation_page_15">
|
|
||||||
<field name="code">CMR</field>
|
|
||||||
<field name="name">开料要求</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<!-- 原生页签先不进行配置 -->
|
|
||||||
<!-- <record model="sf.work.individuation.page" id="sf_work_individuation_page_7">-->
|
|
||||||
<!-- <field name="code">ML</field>-->
|
|
||||||
<!-- <field name="name">物料</field>-->
|
|
||||||
<!-- </record>-->
|
|
||||||
<!-- <record model="sf.work.individuation.page" id="sf_work_individuation_page_8">-->
|
|
||||||
<!-- <field name="code">TT</field>-->
|
|
||||||
<!-- <field name="name">时间跟踪</field>-->
|
|
||||||
<!-- </record>-->
|
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -19,10 +19,12 @@ class AgvScheduling(models.Model):
|
|||||||
_order = 'id desc'
|
_order = 'id desc'
|
||||||
|
|
||||||
name = fields.Char('任务单号', index=True, copy=False)
|
name = fields.Char('任务单号', index=True, copy=False)
|
||||||
agv_route_id = fields.Many2one('sf.agv.task.route', '任务路线')
|
|
||||||
def _get_agv_route_type_selection(self):
|
def _get_agv_route_type_selection(self):
|
||||||
return self.env['sf.agv.task.route'].fields_get(['route_type'])['route_type']['selection']
|
return self.env['sf.agv.task.route'].fields_get(['route_type'])['route_type']['selection']
|
||||||
|
|
||||||
agv_route_type = fields.Selection(selection=_get_agv_route_type_selection, string='任务类型', required=True)
|
agv_route_type = fields.Selection(selection=_get_agv_route_type_selection, string='任务类型', required=True)
|
||||||
|
agv_route_id = fields.Many2one('sf.agv.task.route', '任务路线')
|
||||||
start_site_id = fields.Many2one('sf.agv.site', '起点接驳站', required=True)
|
start_site_id = fields.Many2one('sf.agv.site', '起点接驳站', required=True)
|
||||||
end_site_id = fields.Many2one('sf.agv.site', '终点接驳站', tracking=True)
|
end_site_id = fields.Many2one('sf.agv.site', '终点接驳站', tracking=True)
|
||||||
site_state = fields.Selection([
|
site_state = fields.Selection([
|
||||||
|
|||||||
@@ -1,20 +1,27 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
|
import asyncio
|
||||||
import base64
|
import base64
|
||||||
|
import cProfile
|
||||||
|
import concurrent
|
||||||
import datetime
|
import datetime
|
||||||
|
import io
|
||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
import os
|
import os
|
||||||
|
import pstats
|
||||||
import re
|
import re
|
||||||
|
import threading
|
||||||
|
import time
|
||||||
|
from concurrent.futures import ThreadPoolExecutor, ProcessPoolExecutor
|
||||||
import requests
|
import requests
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from collections import defaultdict, namedtuple
|
from collections import defaultdict, namedtuple
|
||||||
|
|
||||||
from odoo import api, fields, models, SUPERUSER_ID, _
|
from odoo import api, fields, models, SUPERUSER_ID, _, tools
|
||||||
from odoo.exceptions import UserError, ValidationError
|
from odoo.exceptions import UserError, ValidationError
|
||||||
from odoo.addons.sf_base.commons.common import Common
|
from odoo.addons.sf_base.commons.common import Common
|
||||||
from odoo.tools import float_compare, float_round, float_is_zero, format_datetime
|
from odoo.tools import float_compare, float_round, float_is_zero, format_datetime
|
||||||
|
|
||||||
|
|
||||||
class MrpProduction(models.Model):
|
class MrpProduction(models.Model):
|
||||||
_inherit = 'mrp.production'
|
_inherit = 'mrp.production'
|
||||||
_description = "制造订单"
|
_description = "制造订单"
|
||||||
@@ -235,7 +242,7 @@ class MrpProduction(models.Model):
|
|||||||
programming_no = fields.Char('编程单号')
|
programming_no = fields.Char('编程单号')
|
||||||
work_state = fields.Char('业务状态')
|
work_state = fields.Char('业务状态')
|
||||||
programming_state = fields.Selection(
|
programming_state = fields.Selection(
|
||||||
[('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'), ('已下发', '已下发'), ('已取消', '已取消')],
|
[('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'), ('已下发', '已下发')],
|
||||||
string='编程状态',
|
string='编程状态',
|
||||||
tracking=True)
|
tracking=True)
|
||||||
glb_file = fields.Binary("glb模型文件")
|
glb_file = fields.Binary("glb模型文件")
|
||||||
@@ -265,23 +272,6 @@ class MrpProduction(models.Model):
|
|||||||
|
|
||||||
part_name = fields.Char(string='零件名称', related='product_id.part_name', readonly=True)
|
part_name = fields.Char(string='零件名称', related='product_id.part_name', readonly=True)
|
||||||
|
|
||||||
# 判断制造的产品类型
|
|
||||||
production_product_type = fields.Selection([
|
|
||||||
('成品', '成品'),
|
|
||||||
('坯料', '坯料'),
|
|
||||||
('其他', '其他')
|
|
||||||
], string='产品类型', compute='_compute_production_product_type')
|
|
||||||
|
|
||||||
@api.depends('product_id')
|
|
||||||
def _compute_production_product_type(self):
|
|
||||||
for record in self:
|
|
||||||
if record.product_id.categ_id.name == '成品':
|
|
||||||
record.production_product_type = '成品'
|
|
||||||
elif record.product_id.categ_id.name == '坯料':
|
|
||||||
record.production_product_type = '坯料'
|
|
||||||
else:
|
|
||||||
record.production_product_type = '其他'
|
|
||||||
|
|
||||||
@api.depends('product_id.manual_quotation')
|
@api.depends('product_id.manual_quotation')
|
||||||
def _compute_manual_quotation(self):
|
def _compute_manual_quotation(self):
|
||||||
for item in self:
|
for item in self:
|
||||||
@@ -365,7 +355,7 @@ class MrpProduction(models.Model):
|
|||||||
and production.schedule_state == '已排' and production.is_rework is False):
|
and production.schedule_state == '已排' and production.is_rework is False):
|
||||||
production.state = 'pending_cam'
|
production.state = 'pending_cam'
|
||||||
if any((wo.test_results == '返工' and wo.state == 'done' and
|
if any((wo.test_results == '返工' and wo.state == 'done' and
|
||||||
(production.programming_state in ['已编程'] or 'PTD' in wo.individuation_page_list))
|
(production.programming_state in ['已编程'] or wo.individuation_page_PTD is True))
|
||||||
or (wo.is_rework is True and wo.state == 'done' and production.programming_state in ['编程中', '已编程'])
|
or (wo.is_rework is True and wo.state == 'done' and production.programming_state in ['编程中', '已编程'])
|
||||||
for wo in production.workorder_ids) or production.is_rework is True:
|
for wo in production.workorder_ids) or production.is_rework is True:
|
||||||
production.state = 'rework'
|
production.state = 'rework'
|
||||||
@@ -594,19 +584,16 @@ class MrpProduction(models.Model):
|
|||||||
|
|
||||||
# 编程单更新
|
# 编程单更新
|
||||||
# 增加触发时间参数
|
# 增加触发时间参数
|
||||||
def update_programming_state(self, trigger_time=None, reprogramming_reason=None):
|
def update_programming_state(self, trigger_time=None):
|
||||||
try:
|
try:
|
||||||
manufacturing_type = None
|
manufacturing_type = 'rework'
|
||||||
if self.is_scrap:
|
if self.is_scrap:
|
||||||
manufacturing_type = 'scrap'
|
manufacturing_type = 'scrap'
|
||||||
elif self.tool_state == '2':
|
elif self.tool_state == '2':
|
||||||
manufacturing_type = 'invalid_tool_rework'
|
manufacturing_type = 'invalid_tool_rework'
|
||||||
elif self.is_rework:
|
|
||||||
manufacturing_type = 'rework'
|
|
||||||
res = {'programming_no': self.programming_no,
|
res = {'programming_no': self.programming_no,
|
||||||
'manufacturing_type': manufacturing_type,
|
'manufacturing_type': manufacturing_type,
|
||||||
'trigger_time': trigger_time,
|
'trigger_time': trigger_time}
|
||||||
'reprogramming_reason': reprogramming_reason}
|
|
||||||
logging.info('res=%s:' % res)
|
logging.info('res=%s:' % res)
|
||||||
configsettings = self.env['res.config.settings'].get_values()
|
configsettings = self.env['res.config.settings'].get_values()
|
||||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
||||||
@@ -663,27 +650,6 @@ class MrpProduction(models.Model):
|
|||||||
logging.info('update_programming_state error:%s' % e)
|
logging.info('update_programming_state error:%s' % e)
|
||||||
raise UserError("更新编程单状态失败,请联系管理员")
|
raise UserError("更新编程单状态失败,请联系管理员")
|
||||||
|
|
||||||
# 修改编程单状态
|
|
||||||
def _change_programming_state(self):
|
|
||||||
try:
|
|
||||||
res = {"programming_no": self.programming_no, "state": "已取消"}
|
|
||||||
logging.info('res=%s:' % res)
|
|
||||||
configsettings = self.env['res.config.settings'].get_values()
|
|
||||||
config_header = Common.get_headers(self, configsettings['token'], configsettings['sf_secret_key'])
|
|
||||||
url = '/api/intelligent_programming/set_state'
|
|
||||||
config_url = configsettings['sf_url'] + url
|
|
||||||
ret = requests.post(config_url, json=res, data=None, headers=config_header)
|
|
||||||
ret = ret.json()
|
|
||||||
result = json.loads(ret['result'])
|
|
||||||
logging.info('change_programming_state-ret:%s' % result)
|
|
||||||
if result['status'] == 1:
|
|
||||||
self.write({'programming_state': '已取消'})
|
|
||||||
else:
|
|
||||||
raise UserError(ret['message'])
|
|
||||||
except Exception as e:
|
|
||||||
logging.info('change_programming_state error:%s' % e)
|
|
||||||
raise UserError("修改编程单状态失败,请联系管理员")
|
|
||||||
|
|
||||||
# cnc程序获取
|
# cnc程序获取
|
||||||
def fetchCNC(self, production_names):
|
def fetchCNC(self, production_names):
|
||||||
cnc = self.env['mrp.production'].search([('id', '=', self.id)])
|
cnc = self.env['mrp.production'].search([('id', '=', self.id)])
|
||||||
@@ -696,8 +662,6 @@ class MrpProduction(models.Model):
|
|||||||
programme_way = 'manual operation'
|
programme_way = 'manual operation'
|
||||||
else:
|
else:
|
||||||
programme_way = 'auto'
|
programme_way = 'auto'
|
||||||
if cnc.production_type == '人工线下加工':
|
|
||||||
programme_way = 'manual operation'
|
|
||||||
if quick_order:
|
if quick_order:
|
||||||
programme_way = 'manual operation'
|
programme_way = 'manual operation'
|
||||||
try:
|
try:
|
||||||
@@ -713,9 +677,9 @@ class MrpProduction(models.Model):
|
|||||||
[('id', '=', cnc.product_id.materials_type_id.id)]).materials_no,
|
[('id', '=', cnc.product_id.materials_type_id.id)]).materials_no,
|
||||||
'machining_processing_panel': cnc.product_id.model_processing_panel,
|
'machining_processing_panel': cnc.product_id.model_processing_panel,
|
||||||
'machining_precision': '',
|
'machining_precision': '',
|
||||||
'embryo_long': cnc.product_id.bom_ids[0].bom_line_ids.product_id.length,
|
'embryo_long': cnc.product_id.bom_ids.bom_line_ids.product_id.length,
|
||||||
'embryo_height': cnc.product_id.bom_ids[0].bom_line_ids.product_id.height,
|
'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height,
|
||||||
'embryo_width': cnc.product_id.bom_ids[0].bom_line_ids.product_id.width,
|
'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
|
||||||
'order_no': cnc.origin,
|
'order_no': cnc.origin,
|
||||||
'model_order_no': cnc.product_id.default_code,
|
'model_order_no': cnc.product_id.default_code,
|
||||||
'user': cnc.env.user.name,
|
'user': cnc.env.user.name,
|
||||||
@@ -790,11 +754,11 @@ class MrpProduction(models.Model):
|
|||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
iot_code = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env[
|
iot_code = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id) or self.env[
|
||||||
'ir.sequence'].next_by_code('stock.lot.serial')
|
'ir.sequence'].next_by_code('stock.lot.serial')
|
||||||
# iot_code_name = re.sub('[\u4e00-\u9fa5]', "", iot_code)
|
iot_code_name = re.sub('[\u4e00-\u9fa5]', "", iot_code)
|
||||||
self.lot_producing_id = self.env['stock.lot'].create({
|
self.lot_producing_id = self.env['stock.lot'].create({
|
||||||
'product_id': self.product_id.id,
|
'product_id': self.product_id.id,
|
||||||
'company_id': self.company_id.id,
|
'company_id': self.company_id.id,
|
||||||
'name': iot_code,
|
'name': iot_code_name,
|
||||||
})
|
})
|
||||||
if self.move_finished_ids.filtered(lambda m: m.product_id == self.product_id).move_line_ids:
|
if self.move_finished_ids.filtered(lambda m: m.product_id == self.product_id).move_line_ids:
|
||||||
self.move_finished_ids.filtered(
|
self.move_finished_ids.filtered(
|
||||||
@@ -802,24 +766,21 @@ class MrpProduction(models.Model):
|
|||||||
# if self.product_id.tracking == 'serial':
|
# if self.product_id.tracking == 'serial':
|
||||||
# self._set_qty_producing()
|
# self._set_qty_producing()
|
||||||
|
|
||||||
|
|
||||||
# 重载根据工序生成工单的程序:如果产品BOM中没有工序时,
|
# 重载根据工序生成工单的程序:如果产品BOM中没有工序时,
|
||||||
# 根据产品对应的模板类型中工序,去生成工单;
|
# 根据产品对应的模板类型中工序,去生成工单;
|
||||||
# CNC加工工序的选取规则:
|
# CNC加工工序的选取规则:
|
||||||
# 如果自动报价有带过来预分配的机床,
|
# 如果自动报价有带过来预分配的机床,
|
||||||
# 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制;
|
# 则根据设备找到工作中心;否则采用前面描述的工作中心分配机制;
|
||||||
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
|
# 其他规则限制: 默认只分配给工作中心状态为非故障的工作中心;
|
||||||
|
def process_production(self):
|
||||||
def _create_workorder3(self, item):
|
|
||||||
for production in self:
|
|
||||||
if not production.bom_id or not production.product_id:
|
|
||||||
continue
|
|
||||||
workorders_values = []
|
workorders_values = []
|
||||||
product_qty = production.product_uom_id._compute_quantity(production.product_qty,
|
# production = self.env['mrp.production'].browse(production_id)
|
||||||
production.bom_id.product_uom_id)
|
product_qty = self.product_uom_id._compute_quantity(self.product_qty,
|
||||||
exploded_boms, dummy = production.bom_id.explode(production.product_id,
|
self.bom_id.product_uom_id)
|
||||||
product_qty / production.bom_id.product_qty,
|
exploded_boms, dummy = self.bom_id.explode(self.product_id,
|
||||||
picking_type=production.bom_id.picking_type_id)
|
product_qty / self.bom_id.product_qty,
|
||||||
|
picking_type=self.bom_id.picking_type_id)
|
||||||
for bom, bom_data in exploded_boms:
|
for bom, bom_data in exploded_boms:
|
||||||
# If the operations of the parent BoM and phantom BoM are the same, don't recreate work orders.
|
# If the operations of the parent BoM and phantom BoM are the same, don't recreate work orders.
|
||||||
if not (bom.operation_ids and (not bom_data['parent_line'] or bom_data[
|
if not (bom.operation_ids and (not bom_data['parent_line'] or bom_data[
|
||||||
@@ -830,36 +791,80 @@ class MrpProduction(models.Model):
|
|||||||
continue
|
continue
|
||||||
workorders_values += [{
|
workorders_values += [{
|
||||||
'name': operation.name,
|
'name': operation.name,
|
||||||
'production_id': production.id,
|
'production_id': self.id,
|
||||||
'workcenter_id': operation.workcenter_id.id,
|
'workcenter_id': operation.workcenter_id.id,
|
||||||
'product_uom_id': production.product_uom_id.id,
|
'product_uom_id': self.product_uom_id.id,
|
||||||
'operation_id': operation.id,
|
'operation_id': operation.id,
|
||||||
'state': 'pending',
|
'state': 'pending',
|
||||||
}]
|
}]
|
||||||
if production.product_id.categ_id.type in ['成品', '坯料']:
|
if self.product_id.categ_id.type in ['成品', '坯料']:
|
||||||
# # 根据工序设计生成工单
|
# # 根据工序设计生成工单
|
||||||
technology_design_ids = sorted(production.technology_design_ids, key=lambda x: x.sequence)
|
technology_design_ids = sorted(self.technology_design_ids, key=lambda x: x.sequence)
|
||||||
for route in technology_design_ids:
|
for route in technology_design_ids:
|
||||||
workorder_has = self.env['mrp.workorder'].search(
|
workorder_has = self.env['mrp.workorder'].search(
|
||||||
[('technology_design_id', '=', route.id), ('production_id', '=', production.id)])
|
[('technology_design_id', '=', route.id), ('production_id', '=', self.id)])
|
||||||
if not workorder_has:
|
if not workorder_has:
|
||||||
if route.route_id.routing_type not in ['表面工艺']:
|
if route.route_id.routing_type not in ['表面工艺']:
|
||||||
workorders_values.append(
|
workorders_values.append(
|
||||||
self.env['mrp.workorder'].json_workorder_str(production, route))
|
self.env['mrp.workorder'].json_workorder_str(self, route))
|
||||||
else:
|
else:
|
||||||
product_production_process = self.env['product.template'].search(
|
product_production_process = self.env['product.template'].search(
|
||||||
[('server_product_process_parameters_id', '=', route.process_parameters_id.id)])
|
[('server_product_process_parameters_id', '=', route.process_parameters_id.id)])
|
||||||
workorders_values.append(
|
workorders_values.append(
|
||||||
self.env[
|
self.env[
|
||||||
'mrp.workorder']._json_workorder_surface_process_str(
|
'mrp.workorder']._json_workorder_surface_process_str(
|
||||||
production, route, product_production_process.seller_ids[0].partner_id.id))
|
self, route, product_production_process.seller_ids[0].partner_id.id))
|
||||||
production.workorder_ids = workorders_values
|
return workorders_values
|
||||||
|
|
||||||
|
def _set_workorder_duration_expected(self):
|
||||||
|
try:
|
||||||
|
# 在每个线程中创建独立的 ORM 环境
|
||||||
|
with api.Environment.manage():
|
||||||
|
new_cr = self.pool.cursor()
|
||||||
|
self = self.with_env(self.env(cr=new_cr))
|
||||||
|
# program_ids = self.sudo().env['loyalty.program'].browse(program_ids.ids)
|
||||||
|
# 使用独立的环境来处理数据库事务
|
||||||
|
# 在独立的环境中对 workorder 进行操作
|
||||||
|
production = self.sudo().env['mrp.production'].browse(self.id)
|
||||||
|
workorders_values = production.process_production()
|
||||||
|
production.write({'workorder_ids': workorders_values})
|
||||||
for workorder in production.workorder_ids:
|
for workorder in production.workorder_ids:
|
||||||
workorder.duration_expected = workorder._get_duration_expected()
|
workorder.duration_expected = workorder._get_duration_expected()
|
||||||
|
# 可以进行其他与工作单相关的操作
|
||||||
|
# workorder_env.write({'...'})
|
||||||
|
return production
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error processing workorder {workorder.id}: {e}")
|
||||||
|
# workorders_values = self.process_production(self)
|
||||||
|
# print('_set_workorder_duration_expected wqio ', self)
|
||||||
|
# self.write({'workorder_ids': workorders_values})
|
||||||
|
# for workorder in self.workorder_ids:
|
||||||
|
# workorder.duration_expected = workorder._get_duration_expected()
|
||||||
|
|
||||||
|
def _create_workorder3(self, item):
|
||||||
|
with ThreadPoolExecutor(max_workers=os.cpu_count()) as executor:
|
||||||
|
futures = []
|
||||||
|
for production in self:
|
||||||
|
if not production.bom_id or not production.product_id:
|
||||||
|
continue
|
||||||
|
# 提交每个生产任务到线程池
|
||||||
|
futures.append(executor.submit(production._set_workorder_duration_expected))
|
||||||
|
|
||||||
|
# 等待所有线程完成任务
|
||||||
|
results = []
|
||||||
|
for future in futures:
|
||||||
|
try:
|
||||||
|
result = future.result()
|
||||||
|
if result:
|
||||||
|
results.append(result)
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
logging.error(f"Error processing production: {e}")
|
||||||
|
return results
|
||||||
|
|
||||||
# 外协出入库单处理
|
# 外协出入库单处理
|
||||||
def get_subcontract_pick_purchase(self):
|
def get_subcontract_pick_purchase(self,productions):
|
||||||
production_all = self.sorted(lambda x: x.id)
|
production_all = productions.sorted(lambda x: x.id)
|
||||||
product_id_to_production_names = {}
|
product_id_to_production_names = {}
|
||||||
grouped_product_ids = {k: list(g) for k, g in
|
grouped_product_ids = {k: list(g) for k, g in
|
||||||
groupby(production_all, key=lambda x: x.product_id.id)}
|
groupby(production_all, key=lambda x: x.product_id.id)}
|
||||||
@@ -868,9 +873,10 @@ class MrpProduction(models.Model):
|
|||||||
sorted_workorders = None
|
sorted_workorders = None
|
||||||
for production in production_all:
|
for production in production_all:
|
||||||
proc_workorders = []
|
proc_workorders = []
|
||||||
process_parameter_workorder = self.env['mrp.workorder'].search(
|
process_parameter_workorder=production.workorder_ids.filtered(lambda w: w.surface_technics_parameters_id and w.is_subcontract and w.state!='cancel')
|
||||||
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id),
|
# process_parameter_workorder = self.env['mrp.workorder'].search(
|
||||||
('is_subcontract', '=', True), ('state', '!=', 'cancel')], order='sequence asc')
|
# [('surface_technics_parameters_id', '!=', False), ('production_id', '=', production.id),
|
||||||
|
# ('is_subcontract', '=', True), ('state', '!=', 'cancel')], order='sequence asc')
|
||||||
if process_parameter_workorder:
|
if process_parameter_workorder:
|
||||||
# 将这些特殊表面工艺工单的采购单与调拨单置为失效
|
# 将这些特殊表面工艺工单的采购单与调拨单置为失效
|
||||||
for workorder in process_parameter_workorder:
|
for workorder in process_parameter_workorder:
|
||||||
@@ -985,11 +991,7 @@ class MrpProduction(models.Model):
|
|||||||
if purchase_order_line:
|
if purchase_order_line:
|
||||||
line.unlink()
|
line.unlink()
|
||||||
|
|
||||||
def _reset_work_order_sequence(self):
|
def _process_reset_work_order_sequence(self,rec):
|
||||||
"""
|
|
||||||
工单工序排序方法(新)
|
|
||||||
"""
|
|
||||||
for rec in self:
|
|
||||||
workorder_ids = rec.workorder_ids
|
workorder_ids = rec.workorder_ids
|
||||||
technology_design_ids = rec.technology_design_ids
|
technology_design_ids = rec.technology_design_ids
|
||||||
if workorder_ids.filtered(lambda item: item.state in ('返工', 'rework')):
|
if workorder_ids.filtered(lambda item: item.state in ('返工', 'rework')):
|
||||||
@@ -1026,7 +1028,12 @@ class MrpProduction(models.Model):
|
|||||||
key=lambda w: w.sequence).sequence
|
key=lambda w: w.sequence).sequence
|
||||||
for cw in cancel_work_ids:
|
for cw in cancel_work_ids:
|
||||||
cw.sequence = sequence + 1
|
cw.sequence = sequence + 1
|
||||||
|
def _reset_work_order_sequence(self,productions):
|
||||||
|
"""
|
||||||
|
工单工序排序方法(新)
|
||||||
|
"""
|
||||||
|
for rec in productions:
|
||||||
|
self._process_reset_work_order_sequence(rec)
|
||||||
def _reset_work_order_sequence_1(self):
|
def _reset_work_order_sequence_1(self):
|
||||||
"""
|
"""
|
||||||
工单工序排序方法(旧)
|
工单工序排序方法(旧)
|
||||||
@@ -1122,9 +1129,9 @@ class MrpProduction(models.Model):
|
|||||||
|
|
||||||
# 创建工单并进行排序
|
# 创建工单并进行排序
|
||||||
def _create_workorder(self, item):
|
def _create_workorder(self, item):
|
||||||
self._create_workorder3(item)
|
productions = self._create_workorder3(item)
|
||||||
self._reset_work_order_sequence()
|
self._reset_work_order_sequence(productions)
|
||||||
return True
|
return productions
|
||||||
|
|
||||||
def production_process(self, pro_plan):
|
def production_process(self, pro_plan):
|
||||||
type_map = {'装夹预调': False, 'CNC加工': False, '解除装夹': False}
|
type_map = {'装夹预调': False, 'CNC加工': False, '解除装夹': False}
|
||||||
@@ -1297,14 +1304,11 @@ class MrpProduction(models.Model):
|
|||||||
'target': 'new',
|
'target': 'new',
|
||||||
'context': {
|
'context': {
|
||||||
'default_production_id': self.id,
|
'default_production_id': self.id,
|
||||||
'default_is_clamping': True if self.workorder_ids.filtered(
|
|
||||||
lambda wk: wk.routing_type == '装夹预调') else False,
|
|
||||||
'default_workorder_ids': workorder_ids.ids if workorder_ids.ids != [] else self.workorder_ids.ids,
|
'default_workorder_ids': workorder_ids.ids if workorder_ids.ids != [] else self.workorder_ids.ids,
|
||||||
'default_hidden_workorder_ids': ','.join(map(str, work_id_list)) if work_id_list != [] else '',
|
'default_hidden_workorder_ids': ','.join(map(str, work_id_list)) if work_id_list != [] else '',
|
||||||
'default_reprogramming_num': cloud_programming.get('reprogramming_num') if cloud_programming else '',
|
'default_reprogramming_num': cloud_programming.get('reprogramming_num') if cloud_programming else '',
|
||||||
'default_programming_state': cloud_programming.get('programming_state') if cloud_programming else '',
|
'default_programming_state': cloud_programming.get('programming_state') if cloud_programming else '',
|
||||||
'default_is_reprogramming': True if cloud_programming and (
|
'default_is_reprogramming': True if cloud_programming and (cloud_programming.get('programming_state') in ['已下发']) else False
|
||||||
cloud_programming.get('programming_state') in ['已下发']) else False
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1338,8 +1342,7 @@ class MrpProduction(models.Model):
|
|||||||
for rework_item in rework_workorder:
|
for rework_item in rework_workorder:
|
||||||
pending_workorder = production.workorder_ids.filtered(
|
pending_workorder = production.workorder_ids.filtered(
|
||||||
lambda m1: m1.state in [
|
lambda m1: m1.state in [
|
||||||
'pending'] and m1.processing_panel == rework_item.processing_panel and m1.routing_type in [
|
'pending'] and m1.processing_panel == rework_item.processing_panel and m1.routing_type == 'CNC加工')
|
||||||
'CNC加工', '人工线下加工'])
|
|
||||||
if not pending_workorder.cnc_ids:
|
if not pending_workorder.cnc_ids:
|
||||||
production.get_new_program(rework_item.processing_panel)
|
production.get_new_program(rework_item.processing_panel)
|
||||||
# production.write({'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
|
# production.write({'state': 'progress', 'programming_state': '已编程', 'is_rework': False})
|
||||||
@@ -1349,7 +1352,6 @@ class MrpProduction(models.Model):
|
|||||||
# 对制造订单所以面的cnc工单的程序用刀进行校验
|
# 对制造订单所以面的cnc工单的程序用刀进行校验
|
||||||
try:
|
try:
|
||||||
logging.info(f'已更新制造订单:{productions_not_delivered}')
|
logging.info(f'已更新制造订单:{productions_not_delivered}')
|
||||||
productions = productions.filtered(lambda p: p.production_type == '自动化产线加工')
|
|
||||||
productions.production_cnc_tool_checkout()
|
productions.production_cnc_tool_checkout()
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.info(f'对cnc工单的程序用刀进行校验报错:{e}')
|
logging.info(f'对cnc工单的程序用刀进行校验报错:{e}')
|
||||||
@@ -1382,8 +1384,7 @@ class MrpProduction(models.Model):
|
|||||||
if productions:
|
if productions:
|
||||||
for production in productions:
|
for production in productions:
|
||||||
panel_workorder = production.workorder_ids.filtered(lambda
|
panel_workorder = production.workorder_ids.filtered(lambda
|
||||||
pw: pw.processing_panel == processing_panel and pw.routing_type in [
|
pw: pw.processing_panel == processing_panel and pw.routing_type == 'CNC加工' and pw.state not in (
|
||||||
'CNC加工', '人工线下加工'] and pw.state not in (
|
|
||||||
'rework', 'done'))
|
'rework', 'done'))
|
||||||
if panel_workorder:
|
if panel_workorder:
|
||||||
if panel_workorder.cmm_ids:
|
if panel_workorder.cmm_ids:
|
||||||
@@ -1409,8 +1410,7 @@ class MrpProduction(models.Model):
|
|||||||
'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
|
'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||||
logging.info('len(cnc_worksheet):%s' % len(panel_workorder.cnc_worksheet))
|
logging.info('len(cnc_worksheet):%s' % len(panel_workorder.cnc_worksheet))
|
||||||
pre_workorder = production.workorder_ids.filtered(lambda
|
pre_workorder = production.workorder_ids.filtered(lambda
|
||||||
ap: ap.routing_type in ['装夹预调',
|
ap: ap.routing_type == '装夹预调' and ap.processing_panel == processing_panel and ap.state not in (
|
||||||
'人工线下加工'] and ap.processing_panel == processing_panel and ap.state not in (
|
|
||||||
'rework', 'done'))
|
'rework', 'done'))
|
||||||
if pre_workorder:
|
if pre_workorder:
|
||||||
pre_workorder.write(
|
pre_workorder.write(
|
||||||
@@ -1724,13 +1724,13 @@ class MrpProduction(models.Model):
|
|||||||
url = '/api/intelligent_programming/reset_state_again'
|
url = '/api/intelligent_programming/reset_state_again'
|
||||||
config_url = configsettings['sf_url'] + url
|
config_url = configsettings['sf_url'] + url
|
||||||
ret = requests.post(config_url, json=res, data=None, headers=config_header)
|
ret = requests.post(config_url, json=res, data=None, headers=config_header)
|
||||||
# ret = ret.json()
|
ret = ret.json()
|
||||||
# result = json.loads(ret['result'])
|
result = json.loads(ret['result'])
|
||||||
# logging.info('update_programming_state-ret:%s' % result)
|
logging.info('update_programming_state-ret:%s' % result)
|
||||||
# if result['status'] == 1:
|
if result['status'] == 1:
|
||||||
# self.write({'is_rework': True})
|
self.write({'is_rework': True})
|
||||||
# else:
|
else:
|
||||||
# raise UserError(ret['message'])
|
raise UserError(ret['message'])
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.info('update_programming_state error:%s' % e)
|
logging.info('update_programming_state error:%s' % e)
|
||||||
raise UserError("更新编程单状态失败,请联系管理员")
|
raise UserError("更新编程单状态失败,请联系管理员")
|
||||||
@@ -1748,7 +1748,7 @@ class sf_programming_record(models.Model):
|
|||||||
programming_method = fields.Selection([
|
programming_method = fields.Selection([
|
||||||
('auto', '自动'),
|
('auto', '自动'),
|
||||||
('manual operation', '人工')], string="编程方式")
|
('manual operation', '人工')], string="编程方式")
|
||||||
current_programming_count = fields.Integer('重新编程次数')
|
current_programming_count = fields.Integer('当前编程次数')
|
||||||
target_production_id = fields.Char('目标制造单号')
|
target_production_id = fields.Char('目标制造单号')
|
||||||
apply_time = fields.Datetime('申请时间')
|
apply_time = fields.Datetime('申请时间')
|
||||||
send_time = fields.Datetime('下发时间')
|
send_time = fields.Datetime('下发时间')
|
||||||
@@ -1806,3 +1806,5 @@ class sf_processing_panel(models.Model):
|
|||||||
|
|
||||||
name = fields.Char('加工面')
|
name = fields.Char('加工面')
|
||||||
active = fields.Boolean('有效', default=True)
|
active = fields.Boolean('有效', default=True)
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ from odoo.exceptions import UserError, ValidationError
|
|||||||
from odoo.addons.sf_mrs_connect.models.ftp_operate import FtpController
|
from odoo.addons.sf_mrs_connect.models.ftp_operate import FtpController
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
class ResMrpWorkOrder(models.Model):
|
class ResMrpWorkOrder(models.Model):
|
||||||
_inherit = 'mrp.workorder'
|
_inherit = 'mrp.workorder'
|
||||||
_order = 'sequence asc'
|
_order = 'sequence asc'
|
||||||
_description = '工单'
|
|
||||||
|
|
||||||
product_tmpl_name = fields.Char('坯料产品名称', related='production_bom_id.bom_line_ids.product_id.name')
|
product_tmpl_name = fields.Char('坯料产品名称', related='production_bom_id.bom_line_ids.product_id.name')
|
||||||
|
|
||||||
@@ -69,68 +69,6 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
|
|
||||||
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
|
delivery_warning = fields.Selection([('normal', '正常'), ('warning', '告警'), ('overdue', '逾期')], string='时效',
|
||||||
tracking=True)
|
tracking=True)
|
||||||
back_button_display = fields.Boolean(default=False, compute='_compute_back_button_display', store=True)
|
|
||||||
|
|
||||||
@api.depends('state')
|
|
||||||
def _compute_back_button_display(self):
|
|
||||||
for record in self:
|
|
||||||
sorted_workorders = record.production_id.workorder_ids.filtered(lambda w: w.state != 'cancel').sorted(
|
|
||||||
key=lambda w: w.sequence)
|
|
||||||
if not sorted_workorders:
|
|
||||||
continue
|
|
||||||
position = next((idx for idx, workorder in enumerate(sorted_workorders) if workorder.id == record.id), -1)
|
|
||||||
cur_workorder = sorted_workorders[position]
|
|
||||||
if position == len(sorted_workorders) - 1:
|
|
||||||
picking_ids = cur_workorder.production_id.sale_order_id.picking_ids
|
|
||||||
finished_product_area = picking_ids.filtered(
|
|
||||||
lambda picking: picking.location_dest_id.name == '成品存货区' and picking.state == 'done'
|
|
||||||
)
|
|
||||||
if finished_product_area:
|
|
||||||
moves = self.env['stock.move'].search([
|
|
||||||
('name', '=', cur_workorder.production_id.name),
|
|
||||||
('state', '!=', 'cancel')
|
|
||||||
])
|
|
||||||
finish_move = next((move for move in moves if move.location_dest_id.name == '制造后'), None)
|
|
||||||
if not finish_move and not cur_workorder.is_subcontract and not cur_workorder.routing_type == '解除装夹':
|
|
||||||
record.back_button_display = True
|
|
||||||
else:
|
|
||||||
record.back_button_display = any(
|
|
||||||
finish_move.move_dest_ids.ids not in move.ids and record.state == 'done'
|
|
||||||
for picking in finished_product_area
|
|
||||||
for move in picking.move_ids
|
|
||||||
)
|
|
||||||
else:
|
|
||||||
if record.state == 'done':
|
|
||||||
record.back_button_display = True
|
|
||||||
else:
|
|
||||||
record.back_button_display = False
|
|
||||||
# tag_type
|
|
||||||
if cur_workorder.is_subcontract or cur_workorder.routing_type == '解除装夹' or cur_workorder.routing_type == '切割' or any(
|
|
||||||
detection_result.processing_panel == cur_workorder.processing_panel and
|
|
||||||
detection_result.routing_type == cur_workorder.routing_type and
|
|
||||||
cur_workorder.tag_type !='重新加工' and
|
|
||||||
detection_result.test_results != '合格'
|
|
||||||
for detection_result in cur_workorder.production_id.detection_result_ids
|
|
||||||
):
|
|
||||||
record.back_button_display = False
|
|
||||||
else:
|
|
||||||
next_workorder = sorted_workorders[position + 1]
|
|
||||||
next_state = next_workorder.state
|
|
||||||
if (next_state == 'ready' or (
|
|
||||||
next_workorder.state == 'waiting' and next_workorder.is_subcontract)) and cur_workorder.state == 'done':
|
|
||||||
record.back_button_display = True
|
|
||||||
else:
|
|
||||||
record.back_button_display = False
|
|
||||||
if cur_workorder.is_subcontract or cur_workorder.routing_type == '解除装夹' or cur_workorder.routing_type == '切割' or any(
|
|
||||||
detection_result.processing_panel == cur_workorder.processing_panel and
|
|
||||||
detection_result.routing_type == cur_workorder.routing_type and
|
|
||||||
cur_workorder.tag_type !='重新加工' and
|
|
||||||
detection_result.test_results != '合格'
|
|
||||||
for detection_result in cur_workorder.production_id.detection_result_ids
|
|
||||||
):
|
|
||||||
record.back_button_display = False
|
|
||||||
|
|
||||||
date_planned_start = fields.Datetime(tracking=True)
|
|
||||||
|
|
||||||
@api.depends('processing_panel')
|
@api.depends('processing_panel')
|
||||||
def _compute_processing_panel_selection(self):
|
def _compute_processing_panel_selection(self):
|
||||||
@@ -147,82 +85,6 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
|
|
||||||
manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation, store=True)
|
manual_quotation = fields.Boolean('人工编程', default=False, compute=_compute_manual_quotation, store=True)
|
||||||
|
|
||||||
def button_back(self):
|
|
||||||
if self.production_id.state == 'rework':
|
|
||||||
raise UserError('制造订单为返工时不能进行工单回退')
|
|
||||||
sorted_workorders = self.production_id.workorder_ids.filtered(lambda w: w.state != 'cancel').sorted(
|
|
||||||
key=lambda w: w.sequence)
|
|
||||||
position = next((idx for idx, workorder in enumerate(sorted_workorders) if workorder.id == self.id), -1)
|
|
||||||
cur_workorder = sorted_workorders[position]
|
|
||||||
if position == len(sorted_workorders) - 1:
|
|
||||||
# 末工序
|
|
||||||
picking_ids = cur_workorder.production_id.sale_order_id.picking_ids
|
|
||||||
finished_product_area = picking_ids.filtered(
|
|
||||||
lambda picking: picking.location_dest_id.name == '成品存货区' and picking.state == 'done'
|
|
||||||
)
|
|
||||||
moves = self.env['stock.move'].search([
|
|
||||||
('name', '=', cur_workorder.production_id.name),
|
|
||||||
('state', '!=', 'cancel')
|
|
||||||
])
|
|
||||||
finish_move = next((move for move in moves if move.location_dest_id.name == '制造后'), None) or []
|
|
||||||
if any(
|
|
||||||
finish_move.move_dest_ids.ids in move.ids
|
|
||||||
for picking in finished_product_area
|
|
||||||
for move in picking.move_ids
|
|
||||||
):
|
|
||||||
raise UserError('已入库,无法回退')
|
|
||||||
else:
|
|
||||||
moves = self.env['stock.move'].search([
|
|
||||||
('name', '=', cur_workorder.production_id.name),
|
|
||||||
('state', '!=', 'cancel')
|
|
||||||
])
|
|
||||||
move_lines = self.env['stock.move.line'].search([
|
|
||||||
('reference', '=', cur_workorder.production_id.name),
|
|
||||||
('state', '!=', 'cancel')
|
|
||||||
])
|
|
||||||
moves.state = 'assigned'
|
|
||||||
external_assistance = move_lines.filtered(
|
|
||||||
lambda picking: picking.location_id.name != '外协线边仓'
|
|
||||||
)
|
|
||||||
external_assistance.state = 'assigned'
|
|
||||||
# move_lines.state = 'assigned'
|
|
||||||
self.time_ids.date_end = None
|
|
||||||
cur_workorder.state = 'progress'
|
|
||||||
cur_workorder.production_id.state = 'progress'
|
|
||||||
quality_check = self.env['quality.check'].search(
|
|
||||||
[('workorder_id', '=', self.id)])
|
|
||||||
for check_order in quality_check:
|
|
||||||
if check_order.point_id.is_inspect:
|
|
||||||
check_order.quality_state = 'waiting'
|
|
||||||
else:
|
|
||||||
check_order.quality_state = 'none'
|
|
||||||
# move_dest_ids
|
|
||||||
finished_quants = moves.mapped('move_line_ids.lot_id.quant_ids')
|
|
||||||
finished_quants.quantity = 0
|
|
||||||
finish_move = next((move for move in moves if move.location_dest_id.name == '制造后'), None)
|
|
||||||
finish_move.move_dest_ids.reserved_availability = 0
|
|
||||||
finish_move.move_dest_ids.move_line_ids.state = 'draft'
|
|
||||||
finish_move.move_dest_ids.move_line_ids.unlink()
|
|
||||||
# finish_move.move_dest_ids.move_line_ids.reserved_uom_qty = 0
|
|
||||||
else:
|
|
||||||
next_workorder = sorted_workorders[position + 1]
|
|
||||||
next_state = next_workorder.state
|
|
||||||
if next_state not in ['pending', 'waiting', 'ready']:
|
|
||||||
raise UserError('下工序已经开始,无法回退')
|
|
||||||
if next_workorder.is_subcontract:
|
|
||||||
next_workorder.picking_ids.write({'state': 'waiting'})
|
|
||||||
next_workorder.state = 'pending'
|
|
||||||
self.time_ids.date_end = None
|
|
||||||
cur_workorder.state = 'progress'
|
|
||||||
cur_workorder.production_id.state = 'progress'
|
|
||||||
quality_check = self.env['quality.check'].search(
|
|
||||||
[('workorder_id', '=', self.id)])
|
|
||||||
for check_order in quality_check:
|
|
||||||
if check_order.point_id.is_inspect:
|
|
||||||
check_order.quality_state = 'waiting'
|
|
||||||
else:
|
|
||||||
check_order.quality_state = 'none'
|
|
||||||
|
|
||||||
def _compute_working_users(self):
|
def _compute_working_users(self):
|
||||||
super()._compute_working_users()
|
super()._compute_working_users()
|
||||||
for item in self:
|
for item in self:
|
||||||
@@ -293,7 +155,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数")
|
surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数")
|
||||||
|
|
||||||
picking_ids = fields.Many2many('stock.picking', string='外协出入库单',
|
picking_ids = fields.Many2many('stock.picking', string='外协出入库单',
|
||||||
compute='_compute_surface_technics_picking_ids', store=True)
|
compute='_compute_surface_technics_picking_ids')
|
||||||
|
|
||||||
purchase_id = fields.Many2many('purchase.order', string='外协采购单')
|
purchase_id = fields.Many2many('purchase.order', string='外协采购单')
|
||||||
surface_technics_picking_count = fields.Integer("外协出入库", compute='_compute_surface_technics_picking_ids')
|
surface_technics_picking_count = fields.Integer("外协出入库", compute='_compute_surface_technics_picking_ids')
|
||||||
@@ -594,33 +456,6 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
detailed_reason = fields.Text('详细原因')
|
detailed_reason = fields.Text('详细原因')
|
||||||
is_rework = fields.Boolean(string='是否返工', default=False)
|
is_rework = fields.Boolean(string='是否返工', default=False)
|
||||||
|
|
||||||
# rework_flag = fields.Boolean(string='返工标志', compute='_compute_rework_flag')
|
|
||||||
#
|
|
||||||
# @api.depends('state', 'production_line_state')
|
|
||||||
# def _compute_rework_flag(self):
|
|
||||||
# for record in self:
|
|
||||||
# if record.state == 'done' and record.routing_type == '装夹预调':
|
|
||||||
# next_workorder = record.production_id.workorder_ids.filtered(
|
|
||||||
# lambda w: w.sequence == record.sequence + 1)
|
|
||||||
# if next_workorder and next_workorder.routing_type == 'CNC加工' and next_workorder.state in ['ready',
|
|
||||||
# 'waiting',
|
|
||||||
# 'pending'] and next_workorder.production_line_state == '待上产线':
|
|
||||||
# record.rework_flag = False
|
|
||||||
# elif next_workorder and next_workorder.routing_type == '表面工艺' and next_workorder.state in ['ready',
|
|
||||||
# 'waiting',
|
|
||||||
# 'pending']:
|
|
||||||
# record.rework_flag = False
|
|
||||||
# else:
|
|
||||||
# record.rework_flag = True
|
|
||||||
# else:
|
|
||||||
# record.rework_flag = True
|
|
||||||
#
|
|
||||||
# def button_rework(self):
|
|
||||||
# for item in self:
|
|
||||||
# item.state = 'progress'
|
|
||||||
# for time_id in item.time_ids:
|
|
||||||
# time_id.write({'date_end': None})
|
|
||||||
|
|
||||||
def button_change_env(self):
|
def button_change_env(self):
|
||||||
self.is_test_env = not self.is_test_env
|
self.is_test_env = not self.is_test_env
|
||||||
|
|
||||||
@@ -1226,11 +1061,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
and workorder.production_id.schedule_state == '已排'
|
and workorder.production_id.schedule_state == '已排'
|
||||||
and len(workorder.production_id.picking_ids.filtered(
|
and len(workorder.production_id.picking_ids.filtered(
|
||||||
lambda w: w.state not in ['done', 'cancel'])) == 0):
|
lambda w: w.state not in ['done', 'cancel'])) == 0):
|
||||||
# and workorder.production_id.programming_state == '已编程'
|
|
||||||
if workorder.is_subcontract is True:
|
if workorder.is_subcontract is True:
|
||||||
if workorder.production_id.state == 'rework':
|
|
||||||
workorder.state = 'waiting'
|
|
||||||
continue
|
|
||||||
purchase_orders_id = self._get_surface_technics_purchase_ids()
|
purchase_orders_id = self._get_surface_technics_purchase_ids()
|
||||||
if purchase_orders_id.state == 'purchase':
|
if purchase_orders_id.state == 'purchase':
|
||||||
workorder.state = 'ready'
|
workorder.state = 'ready'
|
||||||
@@ -1245,9 +1076,6 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
else:
|
else:
|
||||||
workorder.state = 'waiting'
|
workorder.state = 'waiting'
|
||||||
continue
|
continue
|
||||||
elif workorder.routing_type == '人工线下加工':
|
|
||||||
if workorder.production_id.programming_state == '已编程':
|
|
||||||
workorder.state = 'ready'
|
|
||||||
else:
|
else:
|
||||||
workorder.state = 'ready'
|
workorder.state = 'ready'
|
||||||
continue
|
continue
|
||||||
@@ -1289,7 +1117,6 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
mo.get_move_line(workorder.production_id, workorder))
|
mo.get_move_line(workorder.production_id, workorder))
|
||||||
else:
|
else:
|
||||||
workorder.state = 'waiting'
|
workorder.state = 'waiting'
|
||||||
|
|
||||||
# 重写工单开始按钮方法
|
# 重写工单开始按钮方法
|
||||||
def button_start(self):
|
def button_start(self):
|
||||||
# 判断工单状态是否为等待组件
|
# 判断工单状态是否为等待组件
|
||||||
@@ -1442,7 +1269,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
record.production_id.process_state = '待加工'
|
record.production_id.process_state = '待加工'
|
||||||
# 生成工件配送单
|
# 生成工件配送单
|
||||||
record.workpiece_delivery_ids = record._json_workpiece_delivery_list()
|
record.workpiece_delivery_ids = record._json_workpiece_delivery_list()
|
||||||
if record.routing_type == 'CNC加工' or 'PTD' in record.individuation_page_list:
|
if record.routing_type == 'CNC加工' or record.individuation_page_PTD is True:
|
||||||
if record.routing_type == 'CNC加工':
|
if record.routing_type == 'CNC加工':
|
||||||
record.process_state = '待解除装夹'
|
record.process_state = '待解除装夹'
|
||||||
# record.write({'process_state': '待加工'})
|
# record.write({'process_state': '待加工'})
|
||||||
@@ -1456,8 +1283,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
'detailed_reason': record.detailed_reason,
|
'detailed_reason': record.detailed_reason,
|
||||||
'processing_panel': record.processing_panel,
|
'processing_panel': record.processing_panel,
|
||||||
'routing_type': record.routing_type,
|
'routing_type': record.routing_type,
|
||||||
'handle_result': '待处理' if record.test_results in ['返工',
|
'handle_result': '待处理' if record.test_results in ['返工', '报废'] or record.is_rework is True else '',
|
||||||
'报废'] or record.is_rework is True else '',
|
|
||||||
'test_results': record.test_results,
|
'test_results': record.test_results,
|
||||||
'test_report': record.detection_report})],
|
'test_report': record.detection_report})],
|
||||||
'is_scrap': True if record.test_results == '报废' else False
|
'is_scrap': True if record.test_results == '报废' else False
|
||||||
@@ -1474,8 +1300,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
raise UserError('请先完成该工单的工艺外协再进行操作')
|
raise UserError('请先完成该工单的工艺外协再进行操作')
|
||||||
# 表面工艺外协,最后一张工单
|
# 表面工艺外协,最后一张工单
|
||||||
workorders = self.production_id.workorder_ids
|
workorders = self.production_id.workorder_ids
|
||||||
subcontract_workorders = workorders.filtered(
|
subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence')
|
||||||
lambda wo: wo.is_subcontract == True and wo.state != 'cancel').sorted('sequence')
|
|
||||||
if self == subcontract_workorders[-1]:
|
if self == subcontract_workorders[-1]:
|
||||||
# 给下一个库存移动就绪
|
# 给下一个库存移动就绪
|
||||||
self.move_subcontract_workorder_ids[0].move_dest_ids._action_done()
|
self.move_subcontract_workorder_ids[0].move_dest_ids._action_done()
|
||||||
@@ -1532,7 +1357,6 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
# ('state', '!=', 'done')])
|
# ('state', '!=', 'done')])
|
||||||
# if raw_move:
|
# if raw_move:
|
||||||
# raw_move.write({'state': 'done'})
|
# raw_move.write({'state': 'done'})
|
||||||
if record.production_id.state != 'rework':
|
|
||||||
record.production_id.button_mark_done1()
|
record.production_id.button_mark_done1()
|
||||||
# record.production_id.state = 'done'
|
# record.production_id.state = 'done'
|
||||||
|
|
||||||
@@ -1676,10 +1500,10 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
|
|
||||||
# ==============================配置化页签--个性化记录===================================
|
# ==============================配置化页签--个性化记录===================================
|
||||||
routing_workcenter_id = fields.Many2one('mrp.routing.workcenter', compute='_compute_routing_workcenter_id',
|
routing_workcenter_id = fields.Many2one('mrp.routing.workcenter', compute='_compute_routing_workcenter_id',
|
||||||
store=True, string='工序作业')
|
store=True)
|
||||||
individuation_page_ids = fields.Many2many('sf.work.individuation.page', string='个性化记录', store=True,
|
individuation_page_ids = fields.Many2many('sf.work.individuation.page', string='个性化记录', store=True,
|
||||||
compute='_compute_individuation_page_ids')
|
compute='_compute_individuation_page_ids')
|
||||||
individuation_page_list = fields.Char('个性化记录', default=None)
|
individuation_page_PTD = fields.Boolean('个性化记录(是否显示后置三元检测[PTD]页签)', default=False)
|
||||||
|
|
||||||
@api.depends('name')
|
@api.depends('name')
|
||||||
def _compute_routing_workcenter_id(self):
|
def _compute_routing_workcenter_id(self):
|
||||||
@@ -1695,12 +1519,10 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
if mw.routing_workcenter_id:
|
if mw.routing_workcenter_id:
|
||||||
mw.individuation_page_ids = mw.routing_workcenter_id.individuation_page_ids.ids
|
mw.individuation_page_ids = mw.routing_workcenter_id.individuation_page_ids.ids
|
||||||
# 初始化页签配置
|
# 初始化页签配置
|
||||||
mw.individuation_page_list = None
|
mw.individuation_page_PTD = False
|
||||||
# 根据工单对应的【作业_个性化记录】配置页签
|
# 根据工单对应的【作业_个性化记录】配置页签
|
||||||
individuation_page_list = [item.code for item in mw.routing_workcenter_id.individuation_page_ids]
|
if any(item.code == 'PTD' for item in mw.routing_workcenter_id.individuation_page_ids):
|
||||||
if individuation_page_list:
|
mw.individuation_page_PTD = True
|
||||||
mw.individuation_page_list = list(set(individuation_page_list))
|
|
||||||
|
|
||||||
# =============================================================================================
|
# =============================================================================================
|
||||||
|
|
||||||
is_inspect = fields.Boolean('需送检', compute='_compute_is_inspect', store=True, default=False)
|
is_inspect = fields.Boolean('需送检', compute='_compute_is_inspect', store=True, default=False)
|
||||||
@@ -1721,8 +1543,7 @@ class ResMrpWorkOrder(models.Model):
|
|||||||
# 修改工单状态
|
# 修改工单状态
|
||||||
self.write({'state': 'to be detected'})
|
self.write({'state': 'to be detected'})
|
||||||
# 若关联的【质量检查_需送检】=true,则质量检查单的状态从“等待”更新为“待处理”
|
# 若关联的【质量检查_需送检】=true,则质量检查单的状态从“等待”更新为“待处理”
|
||||||
self.check_ids.filtered(lambda ch: ch.is_inspect is True and ch.quality_state == 'waiting').write(
|
self.check_ids.filtered(lambda ch: ch.is_inspect is True).write({'quality_state': 'none'})
|
||||||
{'quality_state': 'none'})
|
|
||||||
|
|
||||||
|
|
||||||
class CNCprocessing(models.Model):
|
class CNCprocessing(models.Model):
|
||||||
@@ -2013,6 +1834,7 @@ class WorkPieceDelivery(models.Model):
|
|||||||
|
|
||||||
def _get_agv_route_type_selection(self):
|
def _get_agv_route_type_selection(self):
|
||||||
return self.env['sf.agv.task.route'].fields_get(['route_type'])['route_type']['selection']
|
return self.env['sf.agv.task.route'].fields_get(['route_type'])['route_type']['selection']
|
||||||
|
|
||||||
type = fields.Selection(selection=_get_agv_route_type_selection, string='类型')
|
type = fields.Selection(selection=_get_agv_route_type_selection, string='类型')
|
||||||
delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
|
delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
|
||||||
status = fields.Selection(
|
status = fields.Selection(
|
||||||
|
|||||||
@@ -4,7 +4,6 @@ import requests
|
|||||||
import base64
|
import base64
|
||||||
import hashlib
|
import hashlib
|
||||||
import os
|
import os
|
||||||
import re
|
|
||||||
from odoo import models, fields, api, _
|
from odoo import models, fields, api, _
|
||||||
from odoo.exceptions import ValidationError, UserError
|
from odoo.exceptions import ValidationError, UserError
|
||||||
from odoo.modules import get_resource_path
|
from odoo.modules import get_resource_path
|
||||||
@@ -777,33 +776,10 @@ class ResProductMo(models.Model):
|
|||||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
||||||
machining_drawings = fields.Binary('2D加工图纸', readonly=True)
|
machining_drawings = fields.Binary('2D加工图纸', readonly=True)
|
||||||
quality_standard = fields.Binary('质检标准', readonly=True)
|
quality_standard = fields.Binary('质检标准', readonly=True)
|
||||||
part_name = fields.Char(string='零件名称', compute='_compute_related_product', readonly=True, store=True)
|
part_name = fields.Char(string='零件名称', readonly=True)
|
||||||
part_number = fields.Char(string='零件图号', compute='_compute_related_product', readonly=True, store=True)
|
part_number = fields.Char(string='零件图号', readonly=True)
|
||||||
machining_drawings_name = fields.Char(string='零件图号名称', readonly=True)
|
machining_drawings_name = fields.Char(string='零件图号名称', readonly=True)
|
||||||
machining_drawings_mimetype = fields.Char(string='零件图号类型', readonly=True)
|
machining_drawings_mimetype = fields.Char(string='零件图号类型', readonly=True)
|
||||||
|
|
||||||
@api.depends('name')
|
|
||||||
def _compute_related_product(self):
|
|
||||||
for record in self:
|
|
||||||
if record.categ_id.name == '坯料':
|
|
||||||
product_name = ''
|
|
||||||
match = re.search(r'(S\d{5}-\d)', record.name)
|
|
||||||
# 如果匹配成功,提取结果
|
|
||||||
if match:
|
|
||||||
product_name = match.group(0)
|
|
||||||
sale_order_name = ''
|
|
||||||
match_sale = re.search(r'S(\d+)', record.name)
|
|
||||||
if match_sale:
|
|
||||||
sale_order_name = match_sale.group(0)
|
|
||||||
sale_order = self.env['sale.order'].sudo().search(
|
|
||||||
[('name', '=', sale_order_name)])
|
|
||||||
if sale_order:
|
|
||||||
filtered_order_line = sale_order.order_line.filtered(
|
|
||||||
lambda order_line: re.search(f'{product_name}$', order_line.product_id.name)
|
|
||||||
)
|
|
||||||
record.part_number = filtered_order_line.product_id.part_number if filtered_order_line else None
|
|
||||||
record.part_name = filtered_order_line.product_id.part_name if filtered_order_line else None
|
|
||||||
|
|
||||||
@api.constrains('tool_length')
|
@api.constrains('tool_length')
|
||||||
def _check_tool_length_size(self):
|
def _check_tool_length_size(self):
|
||||||
if self.tool_length > 1000000:
|
if self.tool_length > 1000000:
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
# Part of Odoo. See LICENSE file for full copyright and licensing details.
|
||||||
import re
|
|
||||||
from collections import defaultdict
|
from collections import defaultdict
|
||||||
|
|
||||||
from odoo import api, fields, models, _
|
from odoo import api, fields, models, _
|
||||||
@@ -109,35 +109,13 @@ class PurchaseOrder(models.Model):
|
|||||||
class PurchaseOrderLine(models.Model):
|
class PurchaseOrderLine(models.Model):
|
||||||
_inherit = 'purchase.order.line'
|
_inherit = 'purchase.order.line'
|
||||||
|
|
||||||
part_number = fields.Char('零件图号', store=True, compute='_compute_related_product')
|
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
||||||
part_name = fields.Char('零件名称', store=True,
|
|
||||||
compute='_compute_related_product')
|
|
||||||
related_product = fields.Many2one('product.product', string='关联产品',
|
related_product = fields.Many2one('product.product', string='关联产品',
|
||||||
help='经此产品工艺加工成的成品')
|
help='经此产品工艺加工成的成品')
|
||||||
@api.depends('product_id')
|
|
||||||
def _compute_related_product(self):
|
# @api.depends('order_id.origin')
|
||||||
for record in self:
|
# def _compute_related_product(self):
|
||||||
if record.product_id.categ_id.name == '坯料':
|
# for record in self:
|
||||||
product_name = ''
|
|
||||||
match = re.search(r'(S\d{5}-\d)', record.product_id.name)
|
|
||||||
# 如果匹配成功,提取结果
|
|
||||||
if match:
|
|
||||||
product_name = match.group(0)
|
|
||||||
sale_order_name = ''
|
|
||||||
match_sale = re.search(r'S(\d+)', record.product_id.name)
|
|
||||||
if match_sale:
|
|
||||||
sale_order_name = match_sale.group(0)
|
|
||||||
sale_order = self.env['sale.order'].sudo().search(
|
|
||||||
[('name', '=', sale_order_name)])
|
|
||||||
if sale_order:
|
|
||||||
filtered_order_line = sale_order.order_line.filtered(
|
|
||||||
lambda order_line: re.search(f'{product_name}$', order_line.product_id.name)
|
|
||||||
)
|
|
||||||
record.part_number = filtered_order_line.product_id.part_number if filtered_order_line else None
|
|
||||||
record.part_name = filtered_order_line.product_id.part_name if filtered_order_line else None
|
|
||||||
else:
|
|
||||||
record.part_number = record.product_id.part_number
|
|
||||||
record.part_name = record.product_id.part_name
|
|
||||||
# if record.product_id.detailed_type:
|
# if record.product_id.detailed_type:
|
||||||
# production_id = self.env['mrp.production'].search([('name', '=', record.order_id.origin)])
|
# production_id = self.env['mrp.production'].search([('name', '=', record.order_id.origin)])
|
||||||
# record.related_product = production_id.product_id if production_id else False
|
# record.related_product = production_id.product_id if production_id else False
|
||||||
|
|||||||
@@ -3,6 +3,5 @@ from odoo import fields, models, api
|
|||||||
|
|
||||||
class QualityCheck(models.Model):
|
class QualityCheck(models.Model):
|
||||||
_inherit = "quality.check"
|
_inherit = "quality.check"
|
||||||
_description = "质量检查"
|
|
||||||
|
|
||||||
is_inspect = fields.Boolean('需送检')
|
is_inspect = fields.Boolean('需送检')
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
import logging
|
import logging
|
||||||
import json
|
import json
|
||||||
from odoo import models, fields, api, _
|
from odoo import models, fields, api
|
||||||
from odoo.exceptions import UserError
|
from odoo.exceptions import UserError
|
||||||
|
|
||||||
_logger = logging.getLogger(__name__)
|
_logger = logging.getLogger(__name__)
|
||||||
@@ -24,8 +24,6 @@ class SaleOrder(models.Model):
|
|||||||
self.state = 'supply method'
|
self.state = 'supply method'
|
||||||
|
|
||||||
def action_confirm(self):
|
def action_confirm(self):
|
||||||
if self._get_forbidden_state_confirm() & set(self.mapped('state')):
|
|
||||||
raise UserError(_('订单状态已发生变化,请刷新当前页面'))
|
|
||||||
# 判断是否所有产品都选择了供货方式
|
# 判断是否所有产品都选择了供货方式
|
||||||
filter_line = self.order_line.filtered(lambda line: not line.supply_method)
|
filter_line = self.order_line.filtered(lambda line: not line.supply_method)
|
||||||
if filter_line:
|
if filter_line:
|
||||||
@@ -152,23 +150,6 @@ class SaleOrder(models.Model):
|
|||||||
purchase_embryo)
|
purchase_embryo)
|
||||||
return super(SaleOrder, self).action_confirm()
|
return super(SaleOrder, self).action_confirm()
|
||||||
|
|
||||||
def action_show_cancel_wizard(self):
|
|
||||||
wizard = self.env['sf.sale.order.cancel.wizard'].create({
|
|
||||||
'order_id': self.id,
|
|
||||||
})
|
|
||||||
|
|
||||||
# 创建关联单据行
|
|
||||||
self.env['sf.sale.order.cancel.line'].create_from_order(wizard.id, self)
|
|
||||||
|
|
||||||
return {
|
|
||||||
'name': '取消销售订单',
|
|
||||||
'type': 'ir.actions.act_window',
|
|
||||||
'res_model': 'sf.sale.order.cancel.wizard',
|
|
||||||
'view_mode': 'form',
|
|
||||||
'target': 'new',
|
|
||||||
'res_id': wizard.id,
|
|
||||||
}
|
|
||||||
|
|
||||||
class SaleOrderLine(models.Model):
|
class SaleOrderLine(models.Model):
|
||||||
_inherit = 'sale.order.line'
|
_inherit = 'sale.order.line'
|
||||||
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
part_number = fields.Char('零件图号', related='product_id.part_number', readonly=True)
|
||||||
@@ -185,6 +166,4 @@ class SaleOrderLine(models.Model):
|
|||||||
for line in self:
|
for line in self:
|
||||||
if vals['supply_method'] == 'automation' and line.manual_quotation:
|
if vals['supply_method'] == 'automation' and line.manual_quotation:
|
||||||
raise UserError('当前(%s)产品为人工编程产品,不能选择自动化产线加工' % ','.join(line.mapped('product_id.name')))
|
raise UserError('当前(%s)产品为人工编程产品,不能选择自动化产线加工' % ','.join(line.mapped('product_id.name')))
|
||||||
if vals['supply_method'] == 'purchase' and line.is_incoming_material:
|
|
||||||
raise UserError('当前(%s)产品为客供料,不能选择外购' % ','.join(line.mapped('product_id.name')))
|
|
||||||
return super(SaleOrderLine, self).write(vals)
|
return super(SaleOrderLine, self).write(vals)
|
||||||
|
|||||||
@@ -1,8 +1,5 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
import base64
|
import base64
|
||||||
import random
|
|
||||||
import re
|
|
||||||
|
|
||||||
import qrcode
|
import qrcode
|
||||||
from itertools import groupby
|
from itertools import groupby
|
||||||
from collections import defaultdict, namedtuple
|
from collections import defaultdict, namedtuple
|
||||||
@@ -183,14 +180,14 @@ class StockRule(models.Model):
|
|||||||
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
|
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(company_id).create(
|
||||||
productions_values)
|
productions_values)
|
||||||
# 将这一批制造订单的采购组根据成品设置为不同的采购组
|
# 将这一批制造订单的采购组根据成品设置为不同的采购组
|
||||||
# product_group_id = {}
|
product_group_id = {}
|
||||||
# for index, production in enumerate(productions):
|
for index, production in enumerate(productions):
|
||||||
# if production.product_id.id not in product_group_id.keys():
|
if production.product_id.id not in product_group_id.keys():
|
||||||
# product_group_id[production.product_id.id] = production.procurement_group_id.id
|
product_group_id[production.product_id.id] = production.procurement_group_id.id
|
||||||
# else:
|
else:
|
||||||
# productions_values[index].update({'name': production.name})
|
productions_values[index].update({'name': production.name})
|
||||||
# procurement_group_vals = production._prepare_procurement_group_vals(productions_values[index])
|
procurement_group_vals = production._prepare_procurement_group_vals(productions_values[index])
|
||||||
# production.procurement_group_id = self.env["procurement.group"].create(procurement_group_vals).id
|
production.procurement_group_id = self.env["procurement.group"].create(procurement_group_vals).id
|
||||||
|
|
||||||
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
||||||
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||||
@@ -200,7 +197,7 @@ class StockRule(models.Model):
|
|||||||
'''
|
'''
|
||||||
# productions._create_workorder()
|
# productions._create_workorder()
|
||||||
#
|
#
|
||||||
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||||
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
|
productions.filtered(lambda p: (not p.orderpoint_id and p.move_raw_ids) or \
|
||||||
(
|
(
|
||||||
p.move_dest_ids.procure_method != 'make_to_order' and not
|
p.move_dest_ids.procure_method != 'make_to_order' and not
|
||||||
@@ -292,7 +289,7 @@ class StockRule(models.Model):
|
|||||||
if production_item.product_id.id in product_id_to_production_names:
|
if production_item.product_id.id in product_id_to_production_names:
|
||||||
# 同一个产品多个制造订单对应一个编程单和模型库
|
# 同一个产品多个制造订单对应一个编程单和模型库
|
||||||
# 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递
|
# 只调用一次fetchCNC,并将所有生产订单的名称作为字符串传递
|
||||||
if not production_item.programming_no and production_item.production_type in ['自动化产线加工', '人工线下加工']:
|
if not production_item.programming_no and production_item.production_type == '自动化产线加工':
|
||||||
if not production_programming.programming_no:
|
if not production_programming.programming_no:
|
||||||
production_item.fetchCNC(
|
production_item.fetchCNC(
|
||||||
', '.join(product_id_to_production_names[production_item.product_id.id]))
|
', '.join(product_id_to_production_names[production_item.product_id.id]))
|
||||||
@@ -317,11 +314,6 @@ class StockRule(models.Model):
|
|||||||
i += 1
|
i += 1
|
||||||
technology_design_values.append(
|
technology_design_values.append(
|
||||||
self.env['sf.technology.design'].json_technology_design_str(k, route, i, False))
|
self.env['sf.technology.design'].json_technology_design_str(k, route, i, False))
|
||||||
elif production_item.production_type == '人工线下加工':
|
|
||||||
for route in product_routing_workcenter:
|
|
||||||
i += 1
|
|
||||||
technology_design_values.append(
|
|
||||||
self.env['sf.technology.design'].json_technology_design_str('ZM', route, i, False))
|
|
||||||
else:
|
else:
|
||||||
for route in product_routing_workcenter:
|
for route in product_routing_workcenter:
|
||||||
i += 1
|
i += 1
|
||||||
@@ -452,15 +444,25 @@ class ProductionLot(models.Model):
|
|||||||
"""Return the next serial number to be attributed to the product."""
|
"""Return the next serial number to be attributed to the product."""
|
||||||
if product.tracking == "serial":
|
if product.tracking == "serial":
|
||||||
last_serial = self.env['stock.lot'].search(
|
last_serial = self.env['stock.lot'].search(
|
||||||
[('company_id', '=', company.id), ('product_id', '=', product.id), ('name', 'ilike', product.name)],
|
[('company_id', '=', company.id), ('product_id', '=', product.id)],
|
||||||
limit=1, order='name desc')
|
limit=1, order='name desc')
|
||||||
move_line_id = self.env['stock.move.line'].sudo().search(
|
if last_serial:
|
||||||
[('company_id', '=', company.id), ('product_id', '=', product.id), ('lot_name', 'ilike', product.name)],
|
if product.categ_id.name == '刀具':
|
||||||
limit=1, order='lot_name desc')
|
return self.env['stock.lot'].get_tool_generate_lot_names1(company, product)
|
||||||
if last_serial or move_line_id:
|
else:
|
||||||
return self.env['stock.lot'].generate_lot_names1(product.name, last_serial.name if (
|
# 对last_serial的name进行检测,如果不是以产品名称+数字的形式的就重新搜索
|
||||||
not move_line_id or
|
if product.name.split('[')[0] not in last_serial.name:
|
||||||
(last_serial and last_serial.name > move_line_id.lot_name)) else move_line_id.lot_name, 2)[1]
|
last_serial = self.env['stock.lot'].search(
|
||||||
|
[('company_id', '=', company.id), ('product_id', '=', product.id),
|
||||||
|
('name', 'ilike', product.name.split('[')[0])],
|
||||||
|
limit=1, order='name desc')
|
||||||
|
if not last_serial:
|
||||||
|
return "%s-%03d" % (product.name, 1)
|
||||||
|
return self.env['stock.lot'].generate_lot_names1(product.name, last_serial.name, 2)[1]
|
||||||
|
now = datetime.now().strftime("%Y%m%d")
|
||||||
|
if product.cutting_tool_model_id:
|
||||||
|
split_codes = product.cutting_tool_model_id.code.split('-')
|
||||||
|
return "%s-T-%s-%s-%03d" % (split_codes[0], now, product.specification_id.name, 1)
|
||||||
return "%s-%03d" % (product.name, 1)
|
return "%s-%03d" % (product.name, 1)
|
||||||
|
|
||||||
qr_code_image = fields.Binary(string='二维码', compute='_generate_qr_code')
|
qr_code_image = fields.Binary(string='二维码', compute='_generate_qr_code')
|
||||||
@@ -604,18 +606,6 @@ class StockPicking(models.Model):
|
|||||||
return sequence_id
|
return sequence_id
|
||||||
|
|
||||||
def button_validate(self):
|
def button_validate(self):
|
||||||
# 校验“收料入库单、客供料入库单”是否已经分配序列号,如果没有分配则自动分配
|
|
||||||
if self.picking_type_id.use_existing_lots is False and self.picking_type_id.use_create_lots is True:
|
|
||||||
for move in self.move_ids:
|
|
||||||
if not move.move_line_nosuggest_ids:
|
|
||||||
move.action_show_details()
|
|
||||||
else:
|
|
||||||
# 对已经生成的序列号做唯一性校验,如果重复则重新生成新的序列号
|
|
||||||
line_lot_name = [line_id.lot_name for line_id in move.move_line_nosuggest_ids]
|
|
||||||
lot_ids = self.env['stock.lot'].sudo().search([('name', 'in', line_lot_name)])
|
|
||||||
if lot_ids:
|
|
||||||
move.action_clear_lines_show_details()
|
|
||||||
move.action_show_details()
|
|
||||||
res = super().button_validate()
|
res = super().button_validate()
|
||||||
picking_type_in = self.env.ref('sf_manufacturing.outcontract_picking_in').id
|
picking_type_in = self.env.ref('sf_manufacturing.outcontract_picking_in').id
|
||||||
if res is True and self.picking_type_id.id == picking_type_in:
|
if res is True and self.picking_type_id.id == picking_type_in:
|
||||||
@@ -625,12 +615,12 @@ class StockPicking(models.Model):
|
|||||||
workorder = move_in.subcontract_workorder_id
|
workorder = move_in.subcontract_workorder_id
|
||||||
workorders = workorder.production_id.workorder_ids
|
workorders = workorder.production_id.workorder_ids
|
||||||
subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True and wo.state!='cancel').sorted('sequence')
|
subcontract_workorders = workorders.filtered(lambda wo: wo.is_subcontract == True and wo.state!='cancel').sorted('sequence')
|
||||||
# if workorder == subcontract_workorders[-1]:
|
if workorder == subcontract_workorders[-1]:
|
||||||
# self.env['stock.quant']._update_reserved_quantity(
|
self.env['stock.quant']._update_reserved_quantity(
|
||||||
# move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty,
|
move_in.product_id, move_in.location_dest_id, move_in.product_uom_qty,
|
||||||
# lot_id=move_in.move_line_ids.lot_id,
|
lot_id=move_in.move_line_ids.lot_id,
|
||||||
# package_id=False, owner_id=False, strict=False
|
package_id=False, owner_id=False, strict=False
|
||||||
# )
|
)
|
||||||
workorder.button_finish()
|
workorder.button_finish()
|
||||||
picking_type_out = self.env.ref('sf_manufacturing.outcontract_picking_out').id
|
picking_type_out = self.env.ref('sf_manufacturing.outcontract_picking_out').id
|
||||||
if res and self.picking_type_id.id == picking_type_out:
|
if res and self.picking_type_id.id == picking_type_out:
|
||||||
@@ -646,16 +636,6 @@ class StockPicking(models.Model):
|
|||||||
stock_picking = stock_picking_list.filtered(lambda p: p.state not in ("done", "cancel"))
|
stock_picking = stock_picking_list.filtered(lambda p: p.state not in ("done", "cancel"))
|
||||||
if sale_id and not stock_picking:
|
if sale_id and not stock_picking:
|
||||||
sale_id.write({'state': 'delivered'})
|
sale_id.write({'state': 'delivered'})
|
||||||
if self.location_dest_id.name == '成品存货区' and self.state == 'done':
|
|
||||||
for move in self.move_ids:
|
|
||||||
for production in self.sale_order_id.mrp_production_ids:
|
|
||||||
moves = self.env['stock.move'].search([
|
|
||||||
('name', '=', production.name),
|
|
||||||
('state', '!=', 'cancel')
|
|
||||||
])
|
|
||||||
finish_move = next((move for move in moves if move.location_dest_id.name == '制造后'), None)
|
|
||||||
if finish_move.id in move.move_orig_ids.ids and finish_move.state == 'done':
|
|
||||||
production.workorder_ids.write({'back_button_display': False})
|
|
||||||
return res
|
return res
|
||||||
|
|
||||||
# 创建 外协出库入单
|
# 创建 外协出库入单
|
||||||
@@ -694,8 +674,8 @@ class StockPicking(models.Model):
|
|||||||
picking_in = self.create(
|
picking_in = self.create(
|
||||||
moves_in._get_new_picking_values_Res(item, workorder, 'WH/OCIN/'))
|
moves_in._get_new_picking_values_Res(item, workorder, 'WH/OCIN/'))
|
||||||
# pick_ids.append(picking_in.id)
|
# pick_ids.append(picking_in.id)
|
||||||
moves_in.write({'picking_id': picking_in.id})
|
moves_in.write(
|
||||||
moves_in._action_confirm()
|
{'picking_id': picking_in.id, 'state': 'waiting'})
|
||||||
moves_in._assign_picking_post_process(new=new_picking)
|
moves_in._assign_picking_post_process(new=new_picking)
|
||||||
# self.env.context.get('default_production_id')
|
# self.env.context.get('default_production_id')
|
||||||
moves_out = self.env['stock.move'].sudo().with_context(context).create(
|
moves_out = self.env['stock.move'].sudo().with_context(context).create(
|
||||||
@@ -705,8 +685,8 @@ class StockPicking(models.Model):
|
|||||||
picking_out = self.create(
|
picking_out = self.create(
|
||||||
moves_out._get_new_picking_values_Res(item, workorder, 'WH/OCOUT/'))
|
moves_out._get_new_picking_values_Res(item, workorder, 'WH/OCOUT/'))
|
||||||
# pick_ids.append(picking_out.id)
|
# pick_ids.append(picking_out.id)
|
||||||
moves_out.write({'picking_id': picking_out.id})
|
moves_out.write(
|
||||||
moves_out._action_confirm()
|
{'picking_id': picking_out.id, 'state': 'waiting'})
|
||||||
moves_out._assign_picking_post_process(new=new_picking)
|
moves_out._assign_picking_post_process(new=new_picking)
|
||||||
|
|
||||||
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
|
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
|
||||||
@@ -724,20 +704,6 @@ class StockPicking(models.Model):
|
|||||||
'draft', 'sent']:
|
'draft', 'sent']:
|
||||||
picking.state = 'waiting'
|
picking.state = 'waiting'
|
||||||
|
|
||||||
@api.constrains('state', 'move_ids_without_package')
|
|
||||||
def _check_move_ids_without_package(self):
|
|
||||||
"""
|
|
||||||
凡库存调拨单的【作业类型】=“收料入库、客供料入库”,且其产品行的【产品_库存_追溯】="按唯一序列号/按批次”的,当调拨单的【状态】=就绪时
|
|
||||||
自动生成预分配序列号
|
|
||||||
"""
|
|
||||||
for sp in self:
|
|
||||||
if (sp.picking_type_id.use_existing_lots is False and sp.picking_type_id.use_create_lots is True
|
|
||||||
and sp.state == 'assigned'):
|
|
||||||
if sp.move_ids_without_package:
|
|
||||||
for move_id in sp.move_ids_without_package:
|
|
||||||
if move_id.product_id.tracking in ['serial', 'lot'] and not move_id.move_line_nosuggest_ids:
|
|
||||||
move_id.action_show_details()
|
|
||||||
|
|
||||||
|
|
||||||
class ReStockMove(models.Model):
|
class ReStockMove(models.Model):
|
||||||
_inherit = 'stock.move'
|
_inherit = 'stock.move'
|
||||||
@@ -755,27 +721,25 @@ class ReStockMove(models.Model):
|
|||||||
move.part_number = move.product_id.part_number
|
move.part_number = move.product_id.part_number
|
||||||
move.part_name = move.product_id.part_name
|
move.part_name = move.product_id.part_name
|
||||||
elif move.product_id.categ_id.type == '坯料':
|
elif move.product_id.categ_id.type == '坯料':
|
||||||
product_name = ''
|
if move.origin:
|
||||||
match = re.search(r'(S\d{5}-\d)', move.product_id.name)
|
origin = move.origin.split(',')[0] if ',' in move.origin else move.origin
|
||||||
# 如果匹配成功,提取结果
|
mrp_productio_info = self.env['mrp.production'].sudo().search(
|
||||||
if match:
|
[('name', '=', origin)])
|
||||||
product_name = match.group(0)
|
if mrp_productio_info:
|
||||||
if move.picking_id.sale_order_id:
|
move.part_number = mrp_productio_info.part_number
|
||||||
sale_order = move.picking_id.sale_order_id
|
move.part_name = mrp_productio_info.part_name
|
||||||
else:
|
else:
|
||||||
sale_order_name = ''
|
purchase_order_info = self.env['purchase.order'].sudo().search(
|
||||||
match = re.search(r'(S\d+)', move.product_id.name)
|
[('name', '=', origin)])
|
||||||
if match:
|
if purchase_order_info:
|
||||||
sale_order_name = match.group(0)
|
mrp_production_ids = purchase_order_info._get_mrp_productions().ids
|
||||||
sale_order = self.env['sale.order'].sudo().search(
|
if mrp_production_ids:
|
||||||
[('name', '=', sale_order_name)])
|
mrp_productio_info = self.env['mrp.production'].sudo().search(
|
||||||
filtered_order_line = sale_order.order_line.filtered(
|
[('id', '=', mrp_production_ids[0])])
|
||||||
lambda production: re.search(f'{product_name}$', production.product_id.name)
|
if mrp_productio_info:
|
||||||
)
|
move.part_number = mrp_productio_info.part_number
|
||||||
|
move.part_name = mrp_productio_info.part_name
|
||||||
|
|
||||||
if filtered_order_line:
|
|
||||||
move.part_number = filtered_order_line.part_number
|
|
||||||
move.part_name = filtered_order_line.part_name
|
|
||||||
def _get_stock_move_values_Res(self, item, picking_type_id, group_id, move_dest_ids=False):
|
def _get_stock_move_values_Res(self, item, picking_type_id, group_id, move_dest_ids=False):
|
||||||
route_id = self.env.ref('sf_manufacturing.route_surface_technology_outsourcing').id
|
route_id = self.env.ref('sf_manufacturing.route_surface_technology_outsourcing').id
|
||||||
stock_rule = self.env['stock.rule'].sudo().search(
|
stock_rule = self.env['stock.rule'].sudo().search(
|
||||||
@@ -875,11 +839,9 @@ class ReStockMove(models.Model):
|
|||||||
self.next_serial = self._get_tool_next_serial(self.company_id, self.product_id, self.origin)
|
self.next_serial = self._get_tool_next_serial(self.company_id, self.product_id, self.origin)
|
||||||
else:
|
else:
|
||||||
self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id)
|
self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id)
|
||||||
if (self.picking_type_id.use_existing_lots is False
|
if self.picking_type_id.sequence_code == 'DL' and not self.move_line_nosuggest_ids:
|
||||||
and self.picking_type_id.use_create_lots is True and not self.move_line_nosuggest_ids):
|
|
||||||
self.action_assign_serial_show_details()
|
self.action_assign_serial_show_details()
|
||||||
elif self.product_id.tracking == "lot":
|
elif self.product_id.tracking == "lot":
|
||||||
if self.product_id.categ_id.name == '刀具':
|
|
||||||
self._put_tool_lot(self.company_id, self.product_id, self.origin)
|
self._put_tool_lot(self.company_id, self.product_id, self.origin)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
@@ -905,22 +867,37 @@ class ReStockMove(models.Model):
|
|||||||
),
|
),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
def put_move_line(self):
|
||||||
|
"""
|
||||||
|
确认订单时,自动分配序列号
|
||||||
|
"""
|
||||||
|
if self.product_id.tracking == "serial":
|
||||||
|
if self.product_id.categ_id.name == '刀具':
|
||||||
|
self.next_serial = self._get_tool_next_serial(self.company_id, self.product_id, self.origin)
|
||||||
|
else:
|
||||||
|
self.next_serial = self.env['stock.lot']._get_next_serial(self.company_id, self.product_id)
|
||||||
|
self._generate_serial_numbers()
|
||||||
|
for item in self.move_line_nosuggest_ids:
|
||||||
|
if item.lot_name:
|
||||||
|
lot_name = item.lot_name
|
||||||
|
if item.product_id.categ_id.name == '坯料':
|
||||||
|
lot_name = lot_name.split('[', 1)[0]
|
||||||
|
item.lot_qr_code = self.compute_lot_qr_code(lot_name)
|
||||||
|
|
||||||
def _put_tool_lot(self, company, product, origin):
|
def _put_tool_lot(self, company, product, origin):
|
||||||
if product.tracking == "lot" and self.product_id.categ_id.name == '刀具':
|
if product.tracking == "lot" and self.product_id.categ_id.name == '刀具':
|
||||||
if not self.move_line_nosuggest_ids:
|
if not self.move_line_nosuggest_ids:
|
||||||
lot_code = '%s-%s-%s' % ('%s-T-DJWL-%s' % (
|
lot_code = '%s-%s-%s' % ('%s-T-DJWL-%s' % (
|
||||||
product.cutting_tool_model_id.code.split('-')[0], product.cutting_tool_material_id.code),
|
product.cutting_tool_model_id.code.split('-')[0], product.cutting_tool_material_id.code),
|
||||||
datetime.now().strftime("%Y%m%d"), origin)
|
datetime.now().strftime("%Y%m%d"), origin)
|
||||||
move_line_ids = self.env['stock.move.line'].sudo().search(
|
move_line_ids = self.env['stock.move.line'].sudo().search([('lot_name', 'like', lot_code)], limit=1,
|
||||||
[('company_id', '=', company.id), ('lot_name', 'like', lot_code)], limit=1, order='id desc')
|
order='id desc')
|
||||||
if not move_line_ids:
|
if not move_line_ids:
|
||||||
lot_code = '%s-001' % lot_code
|
lot_code = '%s-001' % lot_code
|
||||||
else:
|
else:
|
||||||
lot_code = '%s-%03d' % (lot_code, int(move_line_ids.lot_name[-3:]) + 1)
|
lot_code = '%s-%03d' % (lot_code, int(move_line_ids.lot_name[-3:]) + 1)
|
||||||
lot_names = self.env['stock.lot'].generate_lot_names(lot_code, 1)
|
lot_names = self.env['stock.lot'].generate_lot_names(lot_code, 1)
|
||||||
move_lines_commands = self._generate_serial_move_line_commands_tool_lot(lot_names)
|
move_lines_commands = self._generate_serial_move_line_commands_tool_lot(lot_names)
|
||||||
for move_lines_command in move_lines_commands:
|
|
||||||
move_lines_command[2]['qty_done'] = self.product_uom_qty
|
|
||||||
self.write({'move_line_nosuggest_ids': move_lines_commands})
|
self.write({'move_line_nosuggest_ids': move_lines_commands})
|
||||||
for item in self.move_line_nosuggest_ids:
|
for item in self.move_line_nosuggest_ids:
|
||||||
if item.lot_name:
|
if item.lot_name:
|
||||||
@@ -948,16 +925,10 @@ class ReStockMove(models.Model):
|
|||||||
last_serial = self.env['stock.lot'].search(
|
last_serial = self.env['stock.lot'].search(
|
||||||
[('company_id', '=', company.id), ('product_id', '=', product.id), ('name', 'ilike', origin)],
|
[('company_id', '=', company.id), ('product_id', '=', product.id), ('name', 'ilike', origin)],
|
||||||
limit=1, order='id DESC')
|
limit=1, order='id DESC')
|
||||||
move_line_id = self.env['stock.move.line'].sudo().search(
|
|
||||||
[('company_id', '=', company.id), ('product_id', '=', product.id), ('lot_name', 'ilike', origin)],
|
|
||||||
limit=1, order='lot_name desc')
|
|
||||||
split_codes = product.cutting_tool_model_id.code.split('-')
|
split_codes = product.cutting_tool_model_id.code.split('-')
|
||||||
if last_serial or move_line_id:
|
if last_serial:
|
||||||
return "%s-T-%s-%s-%03d" % (
|
return "%s-T-%s-%s-%03d" % (
|
||||||
split_codes[0], origin, product.specification_id.name,
|
split_codes[0], origin, product.specification_id.name, int(last_serial.name[-3:]) + 1)
|
||||||
int(last_serial.name[-3:] if (not move_line_id or
|
|
||||||
(last_serial and last_serial.name > move_line_id.lot_name))
|
|
||||||
else move_line_id.lot_name[-3:]) + 1)
|
|
||||||
else:
|
else:
|
||||||
return "%s-T-%s-%s-%03d" % (split_codes[0], origin, product.specification_id.name, 1)
|
return "%s-T-%s-%s-%03d" % (split_codes[0], origin, product.specification_id.name, 1)
|
||||||
|
|
||||||
@@ -1053,15 +1024,6 @@ class ReStockMove(models.Model):
|
|||||||
subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True,
|
subcontract_workorder_id = fields.Many2one('mrp.workorder', '外协工单组件', check_company=True,
|
||||||
index='btree_not_null')
|
index='btree_not_null')
|
||||||
|
|
||||||
def button_update_the_sequence_number(self):
|
|
||||||
"""
|
|
||||||
更新序列号 功能按钮
|
|
||||||
"""
|
|
||||||
self.move_line_nosuggest_ids.unlink()
|
|
||||||
if self.state != 'assigned':
|
|
||||||
self.state = 'assigned'
|
|
||||||
return self.action_show_details()
|
|
||||||
|
|
||||||
|
|
||||||
class ReStockQuant(models.Model):
|
class ReStockQuant(models.Model):
|
||||||
_inherit = 'stock.quant'
|
_inherit = 'stock.quant'
|
||||||
|
|||||||
@@ -192,5 +192,3 @@ access_sf_programming_reason,sf_programming_reason,model_sf_programming_reason,b
|
|||||||
access_sf_programming_record,sf_programming_record,model_sf_programming_record,base.group_user,1,1,1,0
|
access_sf_programming_record,sf_programming_record,model_sf_programming_record,base.group_user,1,1,1,0
|
||||||
access_sf_work_individuation_page,sf_work_individuation_page,model_sf_work_individuation_page,sf_base.group_sf_mrp_user,1,1,1,0
|
access_sf_work_individuation_page,sf_work_individuation_page,model_sf_work_individuation_page,sf_base.group_sf_mrp_user,1,1,1,0
|
||||||
access_sf_work_individuation_page_group_plan_dispatch,sf_work_individuation_page_group_plan_dispatch,model_sf_work_individuation_page,sf_base.group_plan_dispatch,1,1,0,0
|
access_sf_work_individuation_page_group_plan_dispatch,sf_work_individuation_page_group_plan_dispatch,model_sf_work_individuation_page,sf_base.group_plan_dispatch,1,1,0,0
|
||||||
access_sf_sale_order_cancel_wizard,sf_sale_order_cancel_wizard,model_sf_sale_order_cancel_wizard,sf_base.group_sf_order_user,1,1,1,0
|
|
||||||
access_sf_sale_order_cancel_line,sf_sale_order_cancel_line,model_sf_sale_order_cancel_line,sf_base.group_sf_order_user,1,0,1,1
|
|
||||||
|
@@ -74,9 +74,7 @@
|
|||||||
<xpath expr="//field[@name='production_real_duration']" position="attributes">
|
<xpath expr="//field[@name='production_real_duration']" position="attributes">
|
||||||
<attribute name="invisible">1</attribute>
|
<attribute name="invisible">1</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='state']" position="after">
|
|
||||||
<field name="programming_state" optional="hide"/>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -116,13 +114,12 @@
|
|||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//sheet//group//group//div[3]" position="after">
|
<xpath expr="//sheet//group//group//div[3]" position="after">
|
||||||
<field name="production_type" readonly="1"/>
|
<field name="production_type" readonly="1"/>
|
||||||
<field name="production_product_type" invisible="1"/>
|
|
||||||
<field name="manual_quotation" readonly="1"
|
<field name="manual_quotation" readonly="1"
|
||||||
attrs="{'invisible': ['|', ('production_type', 'not in', ['自动化产线加工', '人工线下加工']), ('production_product_type', '!=', '成品')]}"/>
|
attrs="{'invisible': [('production_type', 'not in', ['自动化产线加工'])]}"/>
|
||||||
<field name="programming_no" readonly="1"
|
<field name="programming_no" readonly="1"
|
||||||
attrs="{'invisible': ['|', ('production_type', 'not in', ['自动化产线加工', '人工线下加工']), ('production_product_type', '!=', '成品')]}"/>
|
attrs="{'invisible': [('production_type', 'not in', ['自动化产线加工'])]}"/>
|
||||||
<field name="programming_state" readonly="1"
|
<field name="programming_state" readonly="1"
|
||||||
attrs="{'invisible': ['|', ('production_type', 'not in', ['自动化产线加工', '人工线下加工']), ('production_product_type', '!=', '成品')]}"
|
attrs="{'invisible': [('production_type', 'not in', ['自动化产线加工'])]}"
|
||||||
decoration-success="programming_state == '已编程'"
|
decoration-success="programming_state == '已编程'"
|
||||||
decoration-warning="programming_state =='编程中'"
|
decoration-warning="programming_state =='编程中'"
|
||||||
decoration-danger="programming_state =='已编程未下发'"/>
|
decoration-danger="programming_state =='已编程未下发'"/>
|
||||||
@@ -417,9 +414,7 @@
|
|||||||
<span class="o_stat_text">子MO</span>
|
<span class="o_stat_text">子MO</span>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//sheet//notebook//page[last()]" position="after">
|
<xpath expr="//sheet//notebook//page[last()]" position="after">
|
||||||
<page string="编程记录" attrs="{'invisible': ['|', ('production_type', 'not in', ['自动化产线加工', '人工线下加工']), ('production_product_type', '!=', '成品')]}">
|
<page string="编程记录">
|
||||||
<field name="production_type" invisible="1"/>
|
|
||||||
<field name="production_product_type" invisible="1"/>
|
|
||||||
<field name="programming_record_ids" widget="one2many" attrs="{'readonly': [('id', '!=', False)]}">
|
<field name="programming_record_ids" widget="one2many" attrs="{'readonly': [('id', '!=', False)]}">
|
||||||
<tree>
|
<tree>
|
||||||
<field name="number"/>
|
<field name="number"/>
|
||||||
@@ -635,8 +630,6 @@
|
|||||||
<field name="state" icon="fa-filter" enable_counters="1"/>
|
<field name="state" icon="fa-filter" enable_counters="1"/>
|
||||||
<field name="delivery_status" icon="fa-filter" enable_counters="1"/>
|
<field name="delivery_status" icon="fa-filter" enable_counters="1"/>
|
||||||
<field name="production_type" icon="fa-filter" enable_counters="1"/>
|
<field name="production_type" icon="fa-filter" enable_counters="1"/>
|
||||||
<field name="programming_state" icon="fa-filter" enable_counters="1"/>
|
|
||||||
|
|
||||||
</searchpanel>
|
</searchpanel>
|
||||||
</xpath>
|
</xpath>
|
||||||
<filter name='todo' position="replace"/>
|
<filter name='todo' position="replace"/>
|
||||||
@@ -798,7 +791,7 @@
|
|||||||
groups="sf_base.group_plan_dispatch,sf_base.group_sf_mrp_manager"
|
groups="sf_base.group_plan_dispatch,sf_base.group_sf_mrp_manager"
|
||||||
sequence="1"/>
|
sequence="1"/>
|
||||||
|
|
||||||
<menuitem id="stock.stock_picking_type_menu"
|
<menuitem id="stock_picking_type_menu"
|
||||||
name="驾驶舱"
|
name="驾驶舱"
|
||||||
parent="stock.menu_stock_root"
|
parent="stock.menu_stock_root"
|
||||||
action="stock.stock_picking_type_action"
|
action="stock.stock_picking_type_action"
|
||||||
|
|||||||
@@ -48,7 +48,6 @@
|
|||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='date_planned_finished']" position="replace">
|
<xpath expr="//field[@name='date_planned_finished']" position="replace">
|
||||||
<field name="date_planned_finished" string="计划结束日期" optional="hide"/>
|
<field name="date_planned_finished" string="计划结束日期" optional="hide"/>
|
||||||
<field name="back_button_display" invisible="1"/>
|
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//button[@name='button_start']" position="attributes">
|
<xpath expr="//button[@name='button_start']" position="attributes">
|
||||||
<!-- <attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft',-->
|
<!-- <attribute name="attrs">{'invisible': ['|', '|', '|','|','|', ('production_state','in', ('draft',-->
|
||||||
@@ -59,11 +58,6 @@
|
|||||||
<attribute name="attrs">{'invisible': [('state', '!=', 'ready')]}
|
<attribute name="attrs">{'invisible': [('state', '!=', 'ready')]}
|
||||||
</attribute>
|
</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<xpath expr="//button[@name='button_start']" position="after">
|
|
||||||
<button name="button_back" string="回退" type="object" class="btn-primary"
|
|
||||||
attrs="{'invisible': [('back_button_display', '=', False)]}" confirm="是否确认回退"/>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="attributes">
|
<xpath expr="//button[@name='%(mrp.act_mrp_block_workcenter_wo)d']" position="attributes">
|
||||||
<attribute name="attrs">{'invisible':
|
<attribute name="attrs">{'invisible':
|
||||||
['|',("user_permissions","=",False),("name","=","获取CNC加工程序")]}
|
['|',("user_permissions","=",False),("name","=","获取CNC加工程序")]}
|
||||||
@@ -169,8 +163,6 @@
|
|||||||
<field name='is_delivery' invisible="1"/>
|
<field name='is_delivery' invisible="1"/>
|
||||||
<field name="is_trayed" invisible="1"/>
|
<field name="is_trayed" invisible="1"/>
|
||||||
<field name="is_inspect" invisible="1"/>
|
<field name="is_inspect" invisible="1"/>
|
||||||
<field name="back_button_display" invisible="1"/>
|
|
||||||
<!-- <field name="rework_flag" invisible="1"/>-->
|
|
||||||
<!-- <field name='is_send_program_again' invisible="1"/>-->
|
<!-- <field name='is_send_program_again' invisible="1"/>-->
|
||||||
<!-- 工单form页面的开始停工按钮等 -->
|
<!-- 工单form页面的开始停工按钮等 -->
|
||||||
<!-- <button name="button_start" type="object" string="开始" class="btn-success" -->
|
<!-- <button name="button_start" type="object" string="开始" class="btn-success" -->
|
||||||
@@ -185,14 +177,12 @@
|
|||||||
|
|
||||||
<!-- <button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始"-->
|
<!-- <button name="button_start" type="object" string="开始" class="btn-success" confirm="是否确认开始"-->
|
||||||
<!-- attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>-->
|
<!-- attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel','to be detected')), ('is_user_working', '!=', False)]}"/>-->
|
||||||
<button name="button_back" string="回退" type="object" class="btn-primary"
|
|
||||||
attrs="{'invisible': [('back_button_display', '=', False)]}" confirm="是否确认回退"/>
|
|
||||||
<button name="button_start" type="object" string="开始" class="btn-success"
|
<button name="button_start" type="object" string="开始" class="btn-success"
|
||||||
attrs="{'invisible': [('state', '!=', 'ready')]}"/>
|
attrs="{'invisible': [('state', '!=', 'ready')]}"/>
|
||||||
<button name="button_pending" type="object" string="暂停" class="btn-warning"
|
<button name="button_pending" type="object" string="暂停" class="btn-warning"
|
||||||
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
|
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
|
||||||
<button name="button_finish" type="object" string="完成" class="btn-success" confirm="是否确认完工"
|
<button name="button_finish" type="object" string="完成" class="btn-success" confirm="是否确认完工"
|
||||||
attrs="{'invisible': ['|', '|', '|',('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False),'&','&',('state', 'in', ('progress')), ('is_inspect', '=', True), ('routing_type','!=','CNC加工')]}"/>
|
attrs="{'invisible': ['|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False)]}"/>
|
||||||
|
|
||||||
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="阻塞"
|
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="阻塞"
|
||||||
context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
|
context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
|
||||||
@@ -202,8 +192,7 @@
|
|||||||
attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked')]}"/>
|
attrs="{'invisible': ['|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '!=', 'blocked')]}"/>
|
||||||
<button name="do_inspect" type="object" string="送检" class="btn-success" confirm="是否确认送检"
|
<button name="do_inspect" type="object" string="送检" class="btn-success" confirm="是否确认送检"
|
||||||
attrs="{'invisible': ['|', '|', ('state', 'not in', ('progress')), ('is_inspect', '=', False), ('routing_type','=','CNC加工')]}"/>
|
attrs="{'invisible': ['|', '|', ('state', 'not in', ('progress')), ('is_inspect', '=', False), ('routing_type','=','CNC加工')]}"/>
|
||||||
<button name="do_inspect" type="object" string="送检" class="btn-success" confirm="是否确认送检"
|
|
||||||
attrs="{'invisible': ['|', '|', ('state', 'not in', ('progress')), ('is_inspect', '=', False), ('production_line_state','!=','已下产线')]}"/>
|
|
||||||
<!-- <button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="停工" -->
|
<!-- <button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="停工" -->
|
||||||
<!-- context="{'default_workcenter_id': workcenter_id}" class="btn-danger" -->
|
<!-- context="{'default_workcenter_id': workcenter_id}" class="btn-danger" -->
|
||||||
<!-- groups="sf_base.group_sf_mrp_user" -->
|
<!-- groups="sf_base.group_sf_mrp_user" -->
|
||||||
@@ -222,12 +211,9 @@
|
|||||||
attrs="{'invisible': ['|', '|', '|', ('routing_type','!=','装夹预调'),('state','!=','progress'), ('is_trayed', '=', False), ('state', 'in', ('done'))]}"/>
|
attrs="{'invisible': ['|', '|', '|', ('routing_type','!=','装夹预调'),('state','!=','progress'), ('is_trayed', '=', False), ('state', 'in', ('done'))]}"/>
|
||||||
<button name="print_method" type="object" string="打印二维码" class="btn-primary"
|
<button name="print_method" type="object" string="打印二维码" class="btn-primary"
|
||||||
attrs="{'invisible': ['|',('routing_type','!=','解除装夹'),('state','!=','done')]}"/>
|
attrs="{'invisible': ['|',('routing_type','!=','解除装夹'),('state','!=','done')]}"/>
|
||||||
<!-- <button type="object" class="oe_highlight jikimo_button_confirm" name="button_rework"-->
|
|
||||||
<!-- string="返工"-->
|
|
||||||
<!-- attrs='{"invisible": [("rework_flag","=",True)]}' confirm="是否返工"/>-->
|
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//page[1]" position="before">
|
<xpath expr="//page[1]" position="before">
|
||||||
<page string="开料要求" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "CMR")]}'>
|
<page string="开料要求" attrs='{"invisible": [("routing_type","not in",("切割", "线切割", "人工线下加工"))]}'>
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="product_tmpl_id_materials_id" widget="many2one"/>
|
<field name="product_tmpl_id_materials_id" widget="many2one"/>
|
||||||
@@ -253,7 +239,7 @@
|
|||||||
invisible="1" sum="real duration"/>
|
invisible="1" sum="real duration"/>
|
||||||
<field name="glb_file" readonly="1" widget="Viewer3D" string="加工模型"/>
|
<field name="glb_file" readonly="1" widget="Viewer3D" string="加工模型"/>
|
||||||
<field name="manual_quotation" readonly="1"
|
<field name="manual_quotation" readonly="1"
|
||||||
attrs="{'invisible': [('routing_type', 'not in', ['CNC加工', '人工线下加工'])]}"/>
|
attrs="{'invisible': [('routing_type', '!=', 'CNC加工')]}"/>
|
||||||
<field name="processing_panel" readonly="1"
|
<field name="processing_panel" readonly="1"
|
||||||
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
|
attrs='{"invisible": [("routing_type","in",("获取CNC加工程序","切割"))]}'/>
|
||||||
<field name="equipment_id" readonly="1"
|
<field name="equipment_id" readonly="1"
|
||||||
@@ -324,7 +310,7 @@
|
|||||||
|
|
||||||
|
|
||||||
<xpath expr="//page[1]" position="before">
|
<xpath expr="//page[1]" position="before">
|
||||||
<page string="工件装夹" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "WCP")]}'>
|
<page string="工件装夹" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'>
|
||||||
<group>
|
<group>
|
||||||
<!-- <field name="_barcode_scanned" widget="barcode_handler"/> -->
|
<!-- <field name="_barcode_scanned" widget="barcode_handler"/> -->
|
||||||
<group string="托盘">
|
<group string="托盘">
|
||||||
@@ -346,7 +332,7 @@
|
|||||||
placeholder="如有预调程序信息请在此处输入....."/>
|
placeholder="如有预调程序信息请在此处输入....."/>
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
<page string="前置三元检测定位参数" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "ITD_PP")]}'>
|
<page string="前置三元检测定位参数" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'>
|
||||||
|
|
||||||
<div>左面:</div>
|
<div>左面:</div>
|
||||||
<div class="o_address_format">
|
<div class="o_address_format">
|
||||||
@@ -503,15 +489,16 @@
|
|||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
|
|
||||||
<page string="2D加工图纸" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "2D_MD")]}'>
|
<page string="2D加工图纸" attrs="{'invisible': [('routing_type','!=','装夹预调')]}">
|
||||||
<field name="machining_drawings" widget="adaptive_viewer"/>
|
<field name="machining_drawings" widget="adaptive_viewer"/>
|
||||||
</page>
|
</page>
|
||||||
|
|
||||||
<page string="质检标准" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "QIS")]}'>
|
<page string="质检标准" attrs="{'invisible': [('routing_type','!=','装夹预调')]}">
|
||||||
<field name="quality_standard" widget="adaptive_viewer"/>
|
<field name="quality_standard" widget="adaptive_viewer"/>
|
||||||
</page>
|
</page>
|
||||||
|
|
||||||
<page string="工件配送" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "WD")]}'>
|
<page string="工件配送"
|
||||||
|
attrs="{'invisible': [('routing_type','!=','装夹预调')]}">
|
||||||
<field name="workpiece_delivery_ids">
|
<field name="workpiece_delivery_ids">
|
||||||
<tree editable="bottom">
|
<tree editable="bottom">
|
||||||
<field name="production_id" invisible="1"/>
|
<field name="production_id" invisible="1"/>
|
||||||
@@ -539,22 +526,14 @@
|
|||||||
attrs='{"invisible": ["|", ("state","!=","progress"), ("routing_type","!=","装夹预调")]}'/>
|
attrs='{"invisible": ["|", ("state","!=","progress"), ("routing_type","!=","装夹预调")]}'/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<!-- =====原生页签,暂时不进行配置===== -->
|
|
||||||
<!-- <xpath expr="//page[@name='components']" position="attributes">-->
|
|
||||||
<!-- <attribute name="attrs">{"invisible": ["!", ("individuation_page_list", "ilike", "ML")]}</attribute>-->
|
|
||||||
<!-- </xpath>-->
|
|
||||||
<!-- <xpath expr="//page[@name='time_tracking']" position="attributes">-->
|
|
||||||
<!-- <attribute name="attrs">{"invisible": ["!", ("individuation_page_list", "ilike", "TT")]}</attribute>-->
|
|
||||||
<!-- </xpath>-->
|
|
||||||
<!-- ============================= -->
|
|
||||||
|
|
||||||
<xpath expr="//page[1]" position="before">
|
<xpath expr="//page[1]" position="before">
|
||||||
<field name="results" invisible="1"/>
|
<field name="results" invisible="1"/>
|
||||||
<field name="individuation_page_list" invisible="1"/>
|
<field name="individuation_page_PTD" invisible="1"/>
|
||||||
<page string="后置三元检测" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "PTD")]}'>
|
<page string="后置三元检测" attrs='{"invisible": [("individuation_page_PTD", "=", False)]}'>
|
||||||
<group>
|
<group>
|
||||||
<field name="test_results"
|
<field name="test_results"
|
||||||
attrs='{"readonly":["&","|",("state","!=","to be detected"), "|",("routing_type","=","CNC加工"),("is_inspect", "=", True),("state","in",["done","rework"])],
|
attrs='{"readonly":[("state","!=","to be detected"), "|",("routing_type","=","CNC加工"),("is_inspect", "=", True)],
|
||||||
"invisible":[("results","!=",False)]}'/>
|
"invisible":[("results","!=",False)]}'/>
|
||||||
<!-- <field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/>-->
|
<!-- <field name="is_remanufacture" attrs='{"invisible":[("test_results","!=","报废")]}'/>-->
|
||||||
<!-- <field name="is_fetchcnc"-->
|
<!-- <field name="is_fetchcnc"-->
|
||||||
@@ -573,16 +552,16 @@
|
|||||||
<!-- attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/>-->
|
<!-- attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/>-->
|
||||||
<!-- </div>-->
|
<!-- </div>-->
|
||||||
</page>
|
</page>
|
||||||
<page string="2D加工图纸" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "2D_MD")]}'>
|
<page string="2D加工图纸" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||||
<field name="machining_drawings" widget="adaptive_viewer"/>
|
<field name="machining_drawings" widget="adaptive_viewer"/>
|
||||||
</page>
|
</page>
|
||||||
|
|
||||||
<page string="质检标准" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "QIS")]}'>
|
<page string="质检标准" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||||
<field name="quality_standard" widget="adaptive_viewer"/>
|
<field name="quality_standard" widget="adaptive_viewer"/>
|
||||||
</page>
|
</page>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//page[1]" position="before">
|
<xpath expr="//page[1]" position="before">
|
||||||
<page string="CNC程序" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "CNC_P")]}'>
|
<page string="CNC程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||||
<field name="cnc_ids" widget="one2many" string="工作程序" default_order="sequence_number,id"
|
<field name="cnc_ids" widget="one2many" string="工作程序" default_order="sequence_number,id"
|
||||||
readonly="0">
|
readonly="0">
|
||||||
<tree>
|
<tree>
|
||||||
@@ -606,7 +585,7 @@
|
|||||||
</field>
|
</field>
|
||||||
|
|
||||||
</page>
|
</page>
|
||||||
<page string="CMM程序" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "CMM_P")]}'>
|
<page string="CMM程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||||
<field name="cmm_ids" widget="one2many" string="CMM程序" readonly="1">
|
<field name="cmm_ids" widget="one2many" string="CMM程序" readonly="1">
|
||||||
<tree>
|
<tree>
|
||||||
<field name="sequence_number"/>
|
<field name="sequence_number"/>
|
||||||
@@ -619,7 +598,7 @@
|
|||||||
</page>
|
</page>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//page[1]" position="before">
|
<xpath expr="//page[1]" position="before">
|
||||||
<page string="解除装夹" attrs='{"invisible": ["!", ("individuation_page_list", "ilike", "DCP")]}'>
|
<page string="解除装夹" attrs='{"invisible": [("routing_type","!=","解除装夹")]}'>
|
||||||
<!-- <field name="tray_id" readonly="1"/>-->
|
<!-- <field name="tray_id" readonly="1"/>-->
|
||||||
<!-- <div class="col-12 col-lg-6 o_setting_box">-->
|
<!-- <div class="col-12 col-lg-6 o_setting_box">-->
|
||||||
<!-- <button type="object" class="oe_highlight" name="unbindtray" string="解除装夹"-->
|
<!-- <button type="object" class="oe_highlight" name="unbindtray" string="解除装夹"-->
|
||||||
@@ -659,8 +638,7 @@
|
|||||||
<field name="inherit_id" ref="sf_manufacturing.view_mrp_production_workorder_tray_form_inherit_sf"/>
|
<field name="inherit_id" ref="sf_manufacturing.view_mrp_production_workorder_tray_form_inherit_sf"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//form//sheet//group//group[2]" position="replace">
|
<xpath expr="//form//sheet//group//group[2]" position="replace">
|
||||||
<group string="装夹图纸"
|
<group string="装夹图纸" attrs="{'invisible': [('routing_type', '!=', '装夹预调')]}">
|
||||||
attrs="{'invisible': [('routing_type', 'not in', ['装夹预调', '人工线下加工'])]}">
|
|
||||||
<!-- 隐藏加工图纸字段名 -->
|
<!-- 隐藏加工图纸字段名 -->
|
||||||
<field name="processing_drawing" widget="pdf_viewer" string="" readonly="1"/>
|
<field name="processing_drawing" widget="pdf_viewer" string="" readonly="1"/>
|
||||||
<!-- <field name="production_id" invisible="0"/>-->
|
<!-- <field name="production_id" invisible="0"/>-->
|
||||||
@@ -803,10 +781,6 @@
|
|||||||
<filter name="filter_to_be_issued" string="待下发" domain="[('status', 'in', ['待下发'])]"/>
|
<filter name="filter_to_be_issued" string="待下发" domain="[('status', 'in', ['待下发'])]"/>
|
||||||
<filter name="filter_issued" string="已下发" domain="[('status', 'in', ['已下发'])]"/>
|
<filter name="filter_issued" string="已下发" domain="[('status', 'in', ['已下发'])]"/>
|
||||||
<filter name="filter_delivered" string="已配送" domain="[('status', 'in', ['已配送'])]"/>
|
<filter name="filter_delivered" string="已配送" domain="[('status', 'in', ['已配送'])]"/>
|
||||||
<separator/>
|
|
||||||
<filter name="filter_type_to_production_line" string="上产线" domain="[('type', '=', '上产线')]"/>
|
|
||||||
<filter name="filter_type_to_empty_racks" string="运送空料架" domain="[('type', '=', '运送空料架')]"/>
|
|
||||||
<filter name="filter_type_production_line_back" string="下产线" domain="[('type', '=', '下产线')]"/>
|
|
||||||
<field name="rfid_code"/>
|
<field name="rfid_code"/>
|
||||||
<field name="production_id"/>
|
<field name="production_id"/>
|
||||||
<field name="feeder_station_start_id"/>
|
<field name="feeder_station_start_id"/>
|
||||||
@@ -829,7 +803,7 @@
|
|||||||
<field name="res_model">sf.workpiece.delivery</field>
|
<field name="res_model">sf.workpiece.delivery</field>
|
||||||
<field name="search_view_id" ref="sf_workpiece_delivery_search"/>
|
<field name="search_view_id" ref="sf_workpiece_delivery_search"/>
|
||||||
<field name="context">{'search_default_filter_to_be_issued': 1,
|
<field name="context">{'search_default_filter_to_be_issued': 1,
|
||||||
'search_default_filter_type_to_production_line': 1}
|
'search_default_filter_issued': 1}
|
||||||
</field>
|
</field>
|
||||||
<field name="view_mode">tree,form</field>
|
<field name="view_mode">tree,form</field>
|
||||||
<field name="domain">
|
<field name="domain">
|
||||||
|
|||||||
@@ -19,34 +19,18 @@
|
|||||||
<field name="supply_method" attrs="{'invisible': [('state', '=', 'draft')], 'required': [('state', '=', 'supply method')]}" />
|
<field name="supply_method" attrs="{'invisible': [('state', '=', 'draft')], 'required': [('state', '=', 'supply method')]}" />
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='model_glb_file']" position="before">
|
<xpath expr="//field[@name='order_line']/tree/field[@name='model_glb_file']" position="before">
|
||||||
<field name="part_number" optional="show" class="section_and_note_text"/>
|
<field name="part_number" optional="show"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<!-- <xpath expr="//header/button[@name='action_cancel']" position="attributes"> -->
|
|
||||||
<!-- <attribute name="attrs">{'invisible': [('state', '!=', 'draft')]}</attribute> -->
|
|
||||||
<!-- </xpath> -->
|
|
||||||
<xpath expr="//header/button[@name='action_cancel']" position="attributes">
|
<xpath expr="//header/button[@name='action_cancel']" position="attributes">
|
||||||
<attribute name="attrs">{'invisible': [('state', 'not in', ['draft', 'supply method'])]}</attribute>
|
<attribute name="attrs">{'invisible': [('state', '!=', 'draft')]}</attribute>
|
||||||
<attribute name="confirm">警告:取消操作将不可逆,是否确定要取消该单据?</attribute>
|
</xpath>
|
||||||
|
<xpath expr="//header/button[@name='action_cancel']" position="attributes">
|
||||||
|
<attribute name="attrs">{'invisible': [('state', '!=', 'draft')]}</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//header/button[@name='action_quotation_send'][5]" position="attributes">
|
<xpath expr="//header/button[@name='action_quotation_send'][5]" position="attributes">
|
||||||
<attribute name="attrs">{'invisible': ['|','&',('check_status', '!=', 'approved'),('state', 'in', ['draft','cancel','supply method']),'&',('check_status', '=', 'approved'),('state', 'in', ['sale','cancel','supply method'])]}</attribute>
|
<attribute name="attrs">{'invisible': ['|','&',('check_status', '!=', 'approved'),('state', 'in', ['draft','cancel','supply method']),'&',('check_status', '=', 'approved'),('state', 'in', ['sale','cancel','supply method'])]}</attribute>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<xpath expr="//header/button[@name='action_cancel']" position="after">
|
|
||||||
<button
|
|
||||||
name="action_show_cancel_wizard"
|
|
||||||
string="取消"
|
|
||||||
type="object"
|
|
||||||
attrs="{'invisible': [('state', 'not in', ['sale', 'processing'])]}"
|
|
||||||
/>
|
|
||||||
<button
|
|
||||||
name="action_show_cancel_wizard"
|
|
||||||
string="取消清单"
|
|
||||||
type="object"
|
|
||||||
attrs="{'invisible': [('state', 'not in', ['cancel'])]}"
|
|
||||||
/>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
|
|||||||
@@ -67,16 +67,6 @@
|
|||||||
<filter string="追溯参考" name="retrospect" domain="[]"
|
<filter string="追溯参考" name="retrospect" domain="[]"
|
||||||
context="{'group_by': 'retrospect_ref'}"/>
|
context="{'group_by': 'retrospect_ref'}"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='picking_type_id']" position="after">
|
|
||||||
<field name="product_id"
|
|
||||||
string="零件图号"
|
|
||||||
filter_domain="[('product_id.part_number', 'ilike', self)]"
|
|
||||||
/>
|
|
||||||
<field name="product_id"
|
|
||||||
string="零件名称"
|
|
||||||
filter_domain="[('product_id.part_name', 'ilike', self)]"
|
|
||||||
/>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
@@ -84,30 +74,5 @@
|
|||||||
<field name="view_ids" eval="[(5, 0, 0),
|
<field name="view_ids" eval="[(5, 0, 0),
|
||||||
(0, 0, {'view_mode': 'tree', 'view_id': ref('stock.vpicktree')})]"/>
|
(0, 0, {'view_mode': 'tree', 'view_id': ref('stock.vpicktree')})]"/>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="sf_view_stock_move_operations" model="ir.ui.view">
|
|
||||||
<field name="name">sf.stock.move.operations.form</field>
|
|
||||||
<field name="model">stock.move</field>
|
|
||||||
<field name="inherit_id" ref="stock.view_stock_move_operations"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//form//field[@name='next_serial']" position="attributes">
|
|
||||||
<attribute name="invisible">True</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//form//field[@name='next_serial_count']" position="attributes">
|
|
||||||
<attribute name="invisible">True</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//form//button[@name='action_assign_serial_show_details']" position="after">
|
|
||||||
<button name="button_update_the_sequence_number" type="object" class="btn-link" data-hotkey="k" title="Assign Serial Numbers">
|
|
||||||
<span>更新序列号</span>
|
|
||||||
</button>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//form//button[@name='action_assign_serial_show_details']" position="attributes">
|
|
||||||
<attribute name="invisible">True</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//form//button[@name='action_clear_lines_show_details']" position="attributes">
|
|
||||||
<attribute name="invisible">True</attribute>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -5,4 +5,3 @@ from . import production_technology_wizard
|
|||||||
from . import production_technology_re_adjust_wizard
|
from . import production_technology_re_adjust_wizard
|
||||||
from . import mrp_workorder_batch_replan_wizard
|
from . import mrp_workorder_batch_replan_wizard
|
||||||
from . import sf_programming_reason
|
from . import sf_programming_reason
|
||||||
from . import sale_order_cancel
|
|
||||||
|
|||||||
@@ -1,9 +1,10 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
# Part of YiZuo. See LICENSE file for full copyright and licensing details.
|
# Part of YiZuo. See LICENSE file for full copyright and licensing details.
|
||||||
import logging
|
import cProfile
|
||||||
from itertools import groupby
|
import io
|
||||||
|
import pstats
|
||||||
|
from concurrent.futures import ThreadPoolExecutor
|
||||||
from odoo import models, api, fields, _
|
from odoo import models, api, fields, _
|
||||||
from odoo.exceptions import UserError
|
|
||||||
|
|
||||||
|
|
||||||
class ProductionTechnologyWizard(models.TransientModel):
|
class ProductionTechnologyWizard(models.TransientModel):
|
||||||
@@ -14,17 +15,12 @@ class ProductionTechnologyWizard(models.TransientModel):
|
|||||||
origin = fields.Char(string='源单据')
|
origin = fields.Char(string='源单据')
|
||||||
is_technology_confirm = fields.Boolean(default=True)
|
is_technology_confirm = fields.Boolean(default=True)
|
||||||
|
|
||||||
def confirm(self):
|
def _process_production(self,productions,technology_designs):
|
||||||
if self.is_technology_confirm is True and self.production_id.product_id.categ_id.type in ['成品', '坯料']:
|
|
||||||
domain = [('origin', '=', self.origin), ('state', '=', 'technology_to_confirmed'),
|
|
||||||
('product_id', '=', self.production_id.product_id.id)]
|
|
||||||
else:
|
|
||||||
domain = [('id', '=', self.production_id.id)]
|
|
||||||
technology_designs = self.env['sf.technology.design'].sudo().search(
|
|
||||||
[('production_id', '=', self.production_id.id), ('active', 'in', [True, False])])
|
|
||||||
# technology_designs = self.production_id.technology_design_ids
|
|
||||||
productions = self.env['mrp.production'].search(domain)
|
|
||||||
for production in productions:
|
for production in productions:
|
||||||
|
# self._process_production_special_design(production,technology_designs)
|
||||||
|
with ThreadPoolExecutor(max_workers=4) as executor:
|
||||||
|
executor.submit(self._process_production_special_design, production,technology_designs)
|
||||||
|
def _process_production_special_design(self,production,technology_designs):
|
||||||
if production != self.production_id:
|
if production != self.production_id:
|
||||||
self.env['sf.technology.design'].sudo().unified_procedure_multiple_work_orders(technology_designs,
|
self.env['sf.technology.design'].sudo().unified_procedure_multiple_work_orders(technology_designs,
|
||||||
production)
|
production)
|
||||||
@@ -39,7 +35,8 @@ class ProductionTechnologyWizard(models.TransientModel):
|
|||||||
# 工单采购单外协出入库单皆需取消
|
# 工单采购单外协出入库单皆需取消
|
||||||
domain = [('production_id', '=', special.production_id.id)]
|
domain = [('production_id', '=', special.production_id.id)]
|
||||||
if special.process_parameters_id:
|
if special.process_parameters_id:
|
||||||
domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id), ('state', '!=', 'cancel')]
|
domain += [('surface_technics_parameters_id', '=', special.process_parameters_id.id),
|
||||||
|
('state', '!=', 'cancel')]
|
||||||
else:
|
else:
|
||||||
domain += [('technology_design_id', '=', special.id), ('state', '!=', 'cancel')]
|
domain += [('technology_design_id', '=', special.id), ('state', '!=', 'cancel')]
|
||||||
workorder = self.env['mrp.workorder'].search(domain)
|
workorder = self.env['mrp.workorder'].search(domain)
|
||||||
@@ -61,7 +58,8 @@ class ProductionTechnologyWizard(models.TransientModel):
|
|||||||
else:
|
else:
|
||||||
if special.production_id.workorder_ids:
|
if special.production_id.workorder_ids:
|
||||||
workorder = self.env['mrp.workorder'].search(
|
workorder = self.env['mrp.workorder'].search(
|
||||||
[('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id), ('state', '!=', 'cancel')])
|
[('technology_design_id', '=', special.id), ('production_id', '=', special.production_id.id),
|
||||||
|
('state', '!=', 'cancel')])
|
||||||
if not workorder:
|
if not workorder:
|
||||||
if special.route_id.routing_type == '表面工艺':
|
if special.route_id.routing_type == '表面工艺':
|
||||||
product_production_process = self.env['product.template'].search(
|
product_production_process = self.env['product.template'].search(
|
||||||
@@ -82,17 +80,34 @@ class ProductionTechnologyWizard(models.TransientModel):
|
|||||||
else:
|
else:
|
||||||
if workorder.blocked_by_workorder_ids:
|
if workorder.blocked_by_workorder_ids:
|
||||||
workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0]
|
workorder.blocked_by_workorder_ids = blocked_by_workorder_ids[0]
|
||||||
productions._create_workorder(False)
|
def confirm(self):
|
||||||
|
if self.is_technology_confirm is True and self.production_id.product_id.categ_id.type in ['成品', '坯料']:
|
||||||
|
domain = [('origin', '=', self.origin), ('state', '=', 'technology_to_confirmed'),
|
||||||
|
('product_id', '=', self.production_id.product_id.id)]
|
||||||
|
else:
|
||||||
|
domain = [('id', '=', self.production_id.id)]
|
||||||
|
technology_designs = self.env['sf.technology.design'].sudo().search(
|
||||||
|
[('production_id', '=', self.production_id.id), ('active', 'in', [True, False])])
|
||||||
|
# technology_designs = self.production_id.technology_design_ids
|
||||||
|
productions = self.env['mrp.production'].search(domain)
|
||||||
|
pr = cProfile.Profile()
|
||||||
|
pr.enable()
|
||||||
|
self._process_production(productions,technology_designs)
|
||||||
|
productions = productions._create_workorder(False)
|
||||||
if self.production_id.product_id.categ_id.type == '成品':
|
if self.production_id.product_id.categ_id.type == '成品':
|
||||||
productions.get_subcontract_pick_purchase()
|
self.production_id.get_subcontract_pick_purchase(productions)
|
||||||
productions.is_adjust = False
|
|
||||||
for item in productions:
|
for item in productions:
|
||||||
|
item.is_adjust = False
|
||||||
workorder = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted(
|
workorder = item.workorder_ids.filtered(lambda wo: wo.state not in ('cancel')).sorted(
|
||||||
key=lambda a: a.sequence)
|
key=lambda a: a.sequence)
|
||||||
first_element = workorder[0] if workorder else None
|
if workorder[0].state in ['pending']:
|
||||||
if not first_element:
|
if workorder[0].production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程':
|
||||||
raise UserError('工艺确认后,工单未生成,请检查配置')
|
workorder[0].state = 'waiting'
|
||||||
if first_element.state in ['pending']:
|
pr.disable() # 停止性能分析
|
||||||
if first_element.production_id.product_id.categ_id.type == '成品' and item.programming_state != '已编程':
|
|
||||||
first_element.state = 'waiting'
|
# 将结果输出到 StringIO
|
||||||
|
s = io.StringIO()
|
||||||
|
ps = pstats.Stats(pr, stream=s)
|
||||||
|
ps.strip_dirs().sort_stats('cumulative').print_stats()
|
||||||
|
analysis_output = s.getvalue()
|
||||||
return productions
|
return productions
|
||||||
|
|||||||
@@ -35,7 +35,6 @@ class ReworkWizard(models.TransientModel):
|
|||||||
is_reprogramming = fields.Boolean(string='申请重新编程', default=False)
|
is_reprogramming = fields.Boolean(string='申请重新编程', default=False)
|
||||||
is_reprogramming_readonly = fields.Boolean(string='申请重新编程(只读)', default=False)
|
is_reprogramming_readonly = fields.Boolean(string='申请重新编程(只读)', default=False)
|
||||||
is_clamp_measure = fields.Boolean(string='保留装夹测量数据', default=True)
|
is_clamp_measure = fields.Boolean(string='保留装夹测量数据', default=True)
|
||||||
is_clamping = fields.Boolean(string='制造订单是否存在装夹预调工单')
|
|
||||||
reprogramming_num = fields.Integer('重新编程次数', default=0)
|
reprogramming_num = fields.Integer('重新编程次数', default=0)
|
||||||
programming_state = fields.Selection(
|
programming_state = fields.Selection(
|
||||||
[('待编程', '待编程'), ('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'),
|
[('待编程', '待编程'), ('编程中', '编程中'), ('已编程', '已编程'), ('已编程未下发', '已编程未下发'),
|
||||||
|
|||||||
@@ -13,7 +13,6 @@
|
|||||||
<field name="routing_type" invisible="True"/>
|
<field name="routing_type" invisible="True"/>
|
||||||
<field name="processing_panel_id" invisible="1"/>
|
<field name="processing_panel_id" invisible="1"/>
|
||||||
<field name="hidden_workorder_ids" class="css_not_available_msg"/>
|
<field name="hidden_workorder_ids" class="css_not_available_msg"/>
|
||||||
<field name="is_clamping" invisible="1"/>
|
|
||||||
<group>
|
<group>
|
||||||
<field name="hidden_workorder_ids" invisible="1"/>
|
<field name="hidden_workorder_ids" invisible="1"/>
|
||||||
<field options="{'no_create': True,'no_open': True}" readonly="1" name="workorder_ids"
|
<field options="{'no_create': True,'no_open': True}" readonly="1" name="workorder_ids"
|
||||||
@@ -27,7 +26,7 @@
|
|||||||
</tree>
|
</tree>
|
||||||
</field>
|
</field>
|
||||||
</group>
|
</group>
|
||||||
<div attrs='{"invisible": ["|", ("routing_type","=","装夹预调"), ("is_clamping", "=", False)]}'>
|
<div attrs='{"invisible": [("routing_type","=","装夹预调")]}'>
|
||||||
<span style='font-weight:bold;'>保留装夹测量数据
|
<span style='font-weight:bold;'>保留装夹测量数据
|
||||||
<field name="is_clamp_measure" force_save="1"/>
|
<field name="is_clamp_measure" force_save="1"/>
|
||||||
</span>
|
</span>
|
||||||
|
|||||||
@@ -1,659 +0,0 @@
|
|||||||
from odoo import models, fields, api
|
|
||||||
from odoo.exceptions import UserError
|
|
||||||
|
|
||||||
|
|
||||||
class SFSaleOrderCancelWizard(models.TransientModel):
|
|
||||||
_name = 'sf.sale.order.cancel.wizard'
|
|
||||||
_description = '销售订单取消向导'
|
|
||||||
|
|
||||||
order_id = fields.Many2one('sale.order', string='销售订单')
|
|
||||||
related_docs = fields.One2many('sf.sale.order.cancel.line', 'wizard_id', string='相关单据')
|
|
||||||
has_movement = fields.Boolean(compute='_compute_has_movement', string='是否有异动')
|
|
||||||
display_message = fields.Char(compute='_compute_display_message', string='显示消息')
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def default_get(self, fields_list):
|
|
||||||
defaults = super().default_get(fields_list)
|
|
||||||
if self._context.get('active_id'):
|
|
||||||
order = self.env['sale.order'].browse(self._context.get('active_id'))
|
|
||||||
defaults['order_id'] = order.id
|
|
||||||
# 创建向导时自动创建关联单据行
|
|
||||||
wizard = self.create(defaults)
|
|
||||||
self.env['sf.sale.order.cancel.line'].create_from_order(wizard.id, order)
|
|
||||||
defaults['related_docs'] = wizard.related_docs.ids
|
|
||||||
return defaults
|
|
||||||
|
|
||||||
@api.depends('related_docs.cancel_reason')
|
|
||||||
def _compute_has_movement(self):
|
|
||||||
for wizard in self:
|
|
||||||
docs_has_movement = any(doc.cancel_reason for doc in wizard.related_docs)
|
|
||||||
order_canceled = wizard.order_id.state == 'cancel'
|
|
||||||
wizard.has_movement = docs_has_movement or order_canceled
|
|
||||||
|
|
||||||
@api.depends('has_movement', 'related_docs', 'related_docs.doc_state')
|
|
||||||
def _compute_display_message(self):
|
|
||||||
for wizard in self:
|
|
||||||
# 如果没有相关记录,显示为空
|
|
||||||
if not wizard.related_docs:
|
|
||||||
wizard.display_message = '无下游单据'
|
|
||||||
continue
|
|
||||||
|
|
||||||
# 检查是否所有记录都是已取消状态
|
|
||||||
all_canceled = all(doc.doc_state == '已取消' for doc in wizard.related_docs)
|
|
||||||
if all_canceled:
|
|
||||||
wizard.display_message = '取消的下游单据如下:'
|
|
||||||
else:
|
|
||||||
wizard.display_message = '部分或全部下游单据存在异动,无法取消,详情如下:' if wizard.has_movement else '确认所有下游单据全部取消?'
|
|
||||||
|
|
||||||
def action_confirm_cancel(self):
|
|
||||||
self.ensure_one()
|
|
||||||
|
|
||||||
# 删除现有关联单据行
|
|
||||||
self.related_docs.unlink()
|
|
||||||
|
|
||||||
# 重新生成最新关联单据行
|
|
||||||
self.env['sf.sale.order.cancel.line'].create_from_order(self.id, self.order_id)
|
|
||||||
|
|
||||||
# 强制重新计算校验字段
|
|
||||||
self._compute_has_movement()
|
|
||||||
self._compute_display_message()
|
|
||||||
|
|
||||||
# 检查是否存在异动
|
|
||||||
if self.has_movement:
|
|
||||||
raise UserError(
|
|
||||||
"存在下游单据异动,无法取消订单!\n"
|
|
||||||
"请关闭向导重新进入,以查看最新状态!"
|
|
||||||
)
|
|
||||||
|
|
||||||
# 取消销售订单关联的采购单
|
|
||||||
purchase_orders = self.env['purchase.order'].search([
|
|
||||||
('origin', '=', self.order_id.name)
|
|
||||||
])
|
|
||||||
if purchase_orders:
|
|
||||||
purchase_orders.write({'state': 'cancel'})
|
|
||||||
|
|
||||||
# 取消销售订单
|
|
||||||
result = self.order_id.action_cancel()
|
|
||||||
|
|
||||||
# 取消关联的制造订单及其采购单
|
|
||||||
manufacturing_orders = self.env['mrp.production'].search([
|
|
||||||
('origin', '=', self.order_id.name)
|
|
||||||
])
|
|
||||||
for mo in manufacturing_orders:
|
|
||||||
# 取消制造订单关联的采购单,但保持关联关系
|
|
||||||
mo_purchase_orders = self.env['purchase.order'].search([
|
|
||||||
('origin', '=', mo.name)
|
|
||||||
])
|
|
||||||
if mo_purchase_orders:
|
|
||||||
mo_purchase_orders.write({'state': 'cancel'})
|
|
||||||
|
|
||||||
# 取消制造订单的质检单
|
|
||||||
mo_quality_checks = self.env['quality.check'].search([
|
|
||||||
('production_id', '=', mo.id)
|
|
||||||
])
|
|
||||||
if mo_quality_checks:
|
|
||||||
mo_quality_checks.write({'quality_state': 'cancel'})
|
|
||||||
|
|
||||||
# 取消制造订单的子制造订单
|
|
||||||
child_mo_ids = self.env['mrp.production'].search([
|
|
||||||
('origin', '=', mo.name)
|
|
||||||
])
|
|
||||||
|
|
||||||
if child_mo_ids:
|
|
||||||
# child_mo_ids |= mo.child_ids
|
|
||||||
# for child_mo in child_mo_ids:
|
|
||||||
for child_mo in child_mo_ids:
|
|
||||||
child_mo.action_cancel()
|
|
||||||
|
|
||||||
# 取消工单的外协单
|
|
||||||
for workorder in mo.workorder_ids:
|
|
||||||
if workorder.picking_ids:
|
|
||||||
for pkd in workorder.picking_ids:
|
|
||||||
pkd.write({'state': 'cancel'})
|
|
||||||
|
|
||||||
# 取消制造订单
|
|
||||||
mo.action_cancel()
|
|
||||||
|
|
||||||
# 取消制造订单关联的编程单
|
|
||||||
mo._change_programming_state()
|
|
||||||
|
|
||||||
# 取消组件的制造单关联的采购单
|
|
||||||
for comp_mo in self.env['mrp.production'].search([
|
|
||||||
('origin', '=', mo.name)
|
|
||||||
]):
|
|
||||||
comp_purchase_orders = self.env['purchase.order'].search([
|
|
||||||
('origin', '=', comp_mo.name)
|
|
||||||
])
|
|
||||||
if comp_purchase_orders:
|
|
||||||
comp_purchase_orders.button_cancel()
|
|
||||||
|
|
||||||
return result
|
|
||||||
|
|
||||||
|
|
||||||
class SFSaleOrderCancelLine(models.TransientModel):
|
|
||||||
_name = 'sf.sale.order.cancel.line'
|
|
||||||
_description = '销售订单取消行'
|
|
||||||
|
|
||||||
wizard_id = fields.Many2one('sf.sale.order.cancel.wizard')
|
|
||||||
sequence = fields.Integer('序号')
|
|
||||||
category = fields.Char('大类')
|
|
||||||
doc_name = fields.Char('单据名称')
|
|
||||||
operation_type = fields.Char('作业类型')
|
|
||||||
doc_number = fields.Char('单据编号')
|
|
||||||
line_number = fields.Char('行号')
|
|
||||||
product_name = fields.Char('产品名称')
|
|
||||||
quantity = fields.Float('数量')
|
|
||||||
doc_state = fields.Char('单据状态')
|
|
||||||
cancel_reason = fields.Char('禁止取消原因')
|
|
||||||
|
|
||||||
quantity_str = fields.Char(
|
|
||||||
string="数量(字符串)",
|
|
||||||
compute="_compute_quantity_str",
|
|
||||||
store=False, # 默认不存储,除非需要搜索/排序
|
|
||||||
)
|
|
||||||
|
|
||||||
@api.depends("quantity")
|
|
||||||
def _compute_quantity_str(self):
|
|
||||||
for record in self:
|
|
||||||
# 处理所有可能的 False/0 情况
|
|
||||||
record.quantity_str = str(int(record.quantity)) if record.quantity not in [False, 0] else ""
|
|
||||||
|
|
||||||
@api.model
|
|
||||||
def create_from_order(self, wizard_id, order):
|
|
||||||
sequence = 1
|
|
||||||
lines = []
|
|
||||||
map_dict = {
|
|
||||||
'waiting': '等待其他作业',
|
|
||||||
'to approve': '待批准',
|
|
||||||
'technology_to_confirmed': '待工艺确认',
|
|
||||||
'confirmed': '已确认',
|
|
||||||
'pending': '等待其他工单',
|
|
||||||
'none': '待处理',
|
|
||||||
'draft': '询价',
|
|
||||||
'cancel': '已取消',
|
|
||||||
'pass': '通过的',
|
|
||||||
'fail': '失败的',
|
|
||||||
'done': '已完成',
|
|
||||||
'rework': '返工',
|
|
||||||
'purchase': '采购订单',
|
|
||||||
'ready': '就绪',
|
|
||||||
'approved': '已批准',
|
|
||||||
'pending_cam': '待加工',
|
|
||||||
'progress': '加工中',
|
|
||||||
'assigned': '就绪'
|
|
||||||
}
|
|
||||||
|
|
||||||
module_name_dict = {
|
|
||||||
'purchase': '采购',
|
|
||||||
'quality': '质量',
|
|
||||||
'mrp': '制造',
|
|
||||||
'stock': '库存',
|
|
||||||
'account': '会计',
|
|
||||||
'hr': '员工',
|
|
||||||
'project': '项目',
|
|
||||||
'crm': '销售',
|
|
||||||
'point_of_sale': '销售',
|
|
||||||
'website': '网站',
|
|
||||||
'sf_plan': '计划',
|
|
||||||
}
|
|
||||||
|
|
||||||
# 检查销售订单
|
|
||||||
if order.invoice_ids:
|
|
||||||
a = 0
|
|
||||||
for invoice in order.invoice_ids:
|
|
||||||
a += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': '销售',
|
|
||||||
'doc_name': '销售订单',
|
|
||||||
'operation_type': '',
|
|
||||||
'doc_number': invoice.name,
|
|
||||||
'line_number': a,
|
|
||||||
'product_name': invoice.product_id.name,
|
|
||||||
'quantity': invoice.quantity,
|
|
||||||
'doc_state': invoice.state,
|
|
||||||
'cancel_reason': '已有异动' if invoice.state != 'draft' else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
sequence += 1
|
|
||||||
|
|
||||||
# 检查交货单
|
|
||||||
if order.picking_ids:
|
|
||||||
for picking in order.picking_ids:
|
|
||||||
b = 0
|
|
||||||
for move in picking.move_ids:
|
|
||||||
b += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
# 'category': '库存',
|
|
||||||
'category': module_name_dict[picking._original_module],
|
|
||||||
# 'doc_name': '交货单',
|
|
||||||
'doc_name': picking._description,
|
|
||||||
'operation_type': picking.picking_type_id.name,
|
|
||||||
'doc_number': picking.name,
|
|
||||||
'line_number': b,
|
|
||||||
'product_name': f'[{move.product_id.default_code}] {move.product_id.name}' if move else '',
|
|
||||||
# 'quantity': picking.product_qty if hasattr(picking, 'product_qty') else 0,
|
|
||||||
'quantity': move.product_uom_qty,
|
|
||||||
'doc_state': map_dict.get(picking.state, picking.state),
|
|
||||||
'cancel_reason': '已有异动' if picking.state not in ['draft', 'cancel', 'waiting'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
sequence += 1
|
|
||||||
|
|
||||||
# # 成品质检单
|
|
||||||
# fin_quality_checks = self.env['quality.check'].search([
|
|
||||||
# ('picking_id', '=', picking.id)
|
|
||||||
# ])
|
|
||||||
# if fin_quality_checks:
|
|
||||||
# b1 = 0
|
|
||||||
# for fin_qc in fin_quality_checks:
|
|
||||||
# b1 += 1
|
|
||||||
# vals = {
|
|
||||||
# 'wizard_id': wizard_id,
|
|
||||||
# 'sequence': sequence,
|
|
||||||
# 'category': '制造',
|
|
||||||
# 'doc_name': '质检单',
|
|
||||||
# 'operation_type': '',
|
|
||||||
# 'doc_number': fin_qc.name,
|
|
||||||
# 'line_number': b1,
|
|
||||||
# 'product_name': f'[{fin_qc.product_id.default_code}] {fin_qc.product_id.name}',
|
|
||||||
# 'quantity': 1,
|
|
||||||
# 'doc_state': map_dict.get(fin_qc.quality_state, fin_qc.quality_state),
|
|
||||||
# 'cancel_reason': '已有异动' if fin_qc.quality_state not in ['none', 'cancel', 'waiting'] else ''
|
|
||||||
# }
|
|
||||||
# lines.append(self.create(vals))
|
|
||||||
|
|
||||||
# 检查所有的质检单
|
|
||||||
quality_checks = self.env['quality.check'].search([
|
|
||||||
('product_id.name', 'like', f'%{order.name}%')])
|
|
||||||
if quality_checks:
|
|
||||||
b1 = 0
|
|
||||||
for quality_check in quality_checks:
|
|
||||||
b1 += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[quality_check._original_module],
|
|
||||||
'doc_name': quality_check._description,
|
|
||||||
'operation_type': '',
|
|
||||||
'doc_number': f'{quality_check.name}-{quality_check.title}',
|
|
||||||
'line_number': 1,
|
|
||||||
'product_name': f'[{quality_check.product_id.default_code}] {quality_check.product_id.name}' if quality_check.product_id.default_code else quality_check.product_id.name,
|
|
||||||
'quantity': 1,
|
|
||||||
'doc_state': map_dict.get(quality_check.quality_state, quality_check.quality_state),
|
|
||||||
'cancel_reason': '已有异动' if quality_check.quality_state not in ['none', 'cancel', 'waiting'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
|
|
||||||
# 检查组件的制造单
|
|
||||||
# component_mos = self.env['mrp.production'].search([
|
|
||||||
# ('origin', '=', mo.name)])
|
|
||||||
component_mos = self.env['mrp.production'].search([
|
|
||||||
('product_id.name', 'like', f'%R-{order.name}%')])
|
|
||||||
h = 0
|
|
||||||
if component_mos:
|
|
||||||
for comp_mo in component_mos:
|
|
||||||
h += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[comp_mo._original_module],
|
|
||||||
'doc_name': comp_mo._description,
|
|
||||||
'operation_type': '',
|
|
||||||
'doc_number': comp_mo.name,
|
|
||||||
'line_number': h,
|
|
||||||
'product_name': f'{comp_mo.product_id.name}',
|
|
||||||
'quantity': comp_mo.product_qty,
|
|
||||||
'doc_state': map_dict.get(comp_mo.state, comp_mo.state),
|
|
||||||
'cancel_reason': '已有异动' if comp_mo.state not in ['technology_to_confirmed',
|
|
||||||
'cancel'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
sequence += 1
|
|
||||||
|
|
||||||
for pinking_id in comp_mo.picking_ids:
|
|
||||||
y = 0
|
|
||||||
for move in pinking_id.move_ids:
|
|
||||||
y += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[pinking_id._original_module],
|
|
||||||
'doc_name': pinking_id._description,
|
|
||||||
'doc_number': f'{comp_mo.name}-{pinking_id.name}',
|
|
||||||
'line_number': y,
|
|
||||||
'operation_type': pinking_id.picking_type_id.name,
|
|
||||||
'product_name': move.product_id.name if move.product_id else '',
|
|
||||||
'quantity': move.product_uom_qty,
|
|
||||||
'doc_state': map_dict.get(pinking_id.state, pinking_id.state),
|
|
||||||
'cancel_reason': '已有异动' if pinking_id.state not in ['cancel', 'waiting',
|
|
||||||
'assigned'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
|
|
||||||
# 检查销售订单直接关联的采购单
|
|
||||||
purchase_orders = self.env['purchase.order'].search([
|
|
||||||
('origin', 'like', f'%{order.name}%')
|
|
||||||
])
|
|
||||||
if purchase_orders:
|
|
||||||
c = 0
|
|
||||||
for po in purchase_orders:
|
|
||||||
for order_line in po.order_line:
|
|
||||||
c += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[po._original_module],
|
|
||||||
'doc_name': po._description,
|
|
||||||
'operation_type': '',
|
|
||||||
'doc_number': po.name,
|
|
||||||
'line_number': c,
|
|
||||||
'product_name': f'[{order_line.product_id.default_code}] {order_line.product_id.name}',
|
|
||||||
'quantity': order_line.product_qty if order_line else 0,
|
|
||||||
'doc_state': map_dict.get(po.state, po.state),
|
|
||||||
'cancel_reason': '已有异动' if po.state not in ['draft', 'cancel'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
sequence += 1
|
|
||||||
|
|
||||||
# 客供料的入库单
|
|
||||||
for pod in purchase_orders:
|
|
||||||
pkds = self.env['stock.picking'].search([
|
|
||||||
('origin', '=', pod.name)
|
|
||||||
])
|
|
||||||
if pkds:
|
|
||||||
for pkd in pkds:
|
|
||||||
x3 = 0
|
|
||||||
for move in pkd.move_ids:
|
|
||||||
x3 += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[pkd._original_module],
|
|
||||||
'doc_name': pkd._description,
|
|
||||||
'doc_number': pkd.name,
|
|
||||||
'line_number': x3,
|
|
||||||
'operation_type': pkd.picking_type_id.name,
|
|
||||||
'product_name': f'[{move.product_id.default_code}] {move.product_id.name}',
|
|
||||||
'quantity': move.product_uom_qty,
|
|
||||||
'doc_state': map_dict.get(pkd.state, pkd.state),
|
|
||||||
'cancel_reason': '已有异动' if pkd.state not in ['waiting', 'cancel', 'confirmed'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
|
|
||||||
#
|
|
||||||
for child_pkd in self.env['stock.picking'].search([
|
|
||||||
('origin', '=', pkd.name)
|
|
||||||
]):
|
|
||||||
x4 = 0
|
|
||||||
for child_move in child_pkd.move_ids:
|
|
||||||
x4 += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[child_pkd._original_module],
|
|
||||||
'doc_name': child_pkd._description,
|
|
||||||
'doc_number': child_pkd.name,
|
|
||||||
'line_number': x4,
|
|
||||||
'operation_type': child_pkd.picking_type_id.name,
|
|
||||||
'product_name': child_move.product_id.name if child_move.product_id else '',
|
|
||||||
'quantity': child_move.product_uom_qty,
|
|
||||||
'doc_state': map_dict.get(child_pkd.state, child_pkd.state),
|
|
||||||
'cancel_reason': '已有异动' if child_pkd.state not in ['waiting',
|
|
||||||
'cancel', 'confirmed'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
|
|
||||||
# 检查制造订单
|
|
||||||
manufacturing_orders = self.env['mrp.production'].search([
|
|
||||||
('origin', '=', order.name)
|
|
||||||
])
|
|
||||||
d = 0
|
|
||||||
# 在领料单处只进行一次
|
|
||||||
flag = True
|
|
||||||
program_list = []
|
|
||||||
for mo in manufacturing_orders:
|
|
||||||
# 添加制造订单本身
|
|
||||||
d += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[mo._original_module],
|
|
||||||
'doc_name': mo._description,
|
|
||||||
'doc_number': mo.name,
|
|
||||||
'operation_type': '',
|
|
||||||
'line_number': d,
|
|
||||||
'product_name': f'[{mo.product_id.default_code}] {mo.product_id.name}',
|
|
||||||
'quantity': mo.product_qty,
|
|
||||||
'doc_state': map_dict.get(mo.state, mo.state),
|
|
||||||
'cancel_reason': '已有异动' if mo.state not in ['technology_to_confirmed', 'cancel'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
sequence += 1
|
|
||||||
|
|
||||||
# 检查制造订单关联的采购单
|
|
||||||
purchase_orders = self.env['purchase.order'].search([
|
|
||||||
('origin', 'like', f'%{mo.name}%')
|
|
||||||
])
|
|
||||||
if purchase_orders:
|
|
||||||
e = 0
|
|
||||||
for po in purchase_orders:
|
|
||||||
for order_line in po.order_line:
|
|
||||||
e += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[po._original_module],
|
|
||||||
'doc_name': po._description,
|
|
||||||
'doc_number': po.name,
|
|
||||||
'line_number': e,
|
|
||||||
'operation_type': '',
|
|
||||||
'product_name': order_line.product_id.name if order_line else '',
|
|
||||||
'quantity': order_line.product_qty if order_line else 0,
|
|
||||||
'doc_state': map_dict.get(po.state, po.state),
|
|
||||||
'cancel_reason': '已有异动' if po.state not in ['draft', 'cancel'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
sequence += 1
|
|
||||||
|
|
||||||
# 制造询价单的入库单
|
|
||||||
for pod in purchase_orders:
|
|
||||||
pkds = self.env['stock.picking'].search([
|
|
||||||
('origin', '=', pod.name)
|
|
||||||
])
|
|
||||||
if pkds:
|
|
||||||
for pkd in pkds:
|
|
||||||
x1 = 0
|
|
||||||
for move in pkd.move_ids:
|
|
||||||
x1 += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[pkd._original_module],
|
|
||||||
'doc_name': pkd._description,
|
|
||||||
'doc_number': pkd.name,
|
|
||||||
'line_number': x1,
|
|
||||||
'operation_type': pkd.picking_type_id.name,
|
|
||||||
'product_name': move.product_id.name if move.product_id else '',
|
|
||||||
'quantity': move.product_uom_qty,
|
|
||||||
'doc_state': map_dict.get(pkd.state, pkd.state),
|
|
||||||
'cancel_reason': '已有异动' if pkd.state not in ['draft', 'cancel'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
|
|
||||||
#
|
|
||||||
for child_pkd in self.env['stock.picking'].search([
|
|
||||||
('origin', '=', pkd.name)
|
|
||||||
]):
|
|
||||||
x2 = 0
|
|
||||||
for child_move in child_pkd.move_ids:
|
|
||||||
x2 += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[child_pkd._original_module],
|
|
||||||
'doc_name': child_pkd._description,
|
|
||||||
'doc_number': child_pkd.name,
|
|
||||||
'line_number': x2,
|
|
||||||
'operation_type': child_pkd.picking_type_id.name,
|
|
||||||
'product_name': child_move.product_id.name if child_move.product_id else '',
|
|
||||||
'quantity': child_move.product_uom_qty,
|
|
||||||
'doc_state': map_dict.get(child_pkd.state, child_pkd.state),
|
|
||||||
'cancel_reason': '已有异动' if child_pkd.state not in ['draft', 'cancel'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
|
|
||||||
# 检查制造订单的领料单
|
|
||||||
|
|
||||||
if mo.picking_ids and flag:
|
|
||||||
for picking in mo.picking_ids:
|
|
||||||
f = 0
|
|
||||||
for move in picking.move_ids:
|
|
||||||
f += 1
|
|
||||||
is_changed = False
|
|
||||||
if picking.state not in ['draft', 'cancel', 'waiting']:
|
|
||||||
is_changed = True
|
|
||||||
if picking.picking_type_id.name == '客供料入库' and picking.state in ['cancel', 'assigned']:
|
|
||||||
is_changed = False
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[picking._original_module],
|
|
||||||
'doc_name': picking._description,
|
|
||||||
'doc_number': picking.name,
|
|
||||||
'line_number': f,
|
|
||||||
'operation_type': picking.picking_type_id.name,
|
|
||||||
'product_name': move.product_id.name if move.product_id else '',
|
|
||||||
'quantity': move.product_uom_qty,
|
|
||||||
'doc_state': map_dict.get(picking.state, picking.state),
|
|
||||||
'cancel_reason': '已有异动' if is_changed else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
sequence += 1
|
|
||||||
flag = False
|
|
||||||
|
|
||||||
# 检查制造订单的工单
|
|
||||||
if mo.workorder_ids:
|
|
||||||
g = 0
|
|
||||||
for workorder in mo.workorder_ids:
|
|
||||||
g += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[workorder._original_module],
|
|
||||||
'doc_name': workorder._description,
|
|
||||||
'doc_number': f'{mo.name}-{workorder.processing_panel}-{workorder.name}' if workorder.processing_panel else f'{mo.name}-{workorder.name}',
|
|
||||||
'line_number': g,
|
|
||||||
'operation_type': '',
|
|
||||||
'product_name': f'[{mo.product_id.default_code}] {mo.product_id.name}',
|
|
||||||
'quantity': workorder.qty_production,
|
|
||||||
'doc_state': map_dict.get(workorder.state, workorder.state),
|
|
||||||
'cancel_reason': '已有异动' if workorder.state not in ['draft', 'cancel', 'pending',
|
|
||||||
'waiting'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
sequence += 1
|
|
||||||
|
|
||||||
# 工艺外协处理
|
|
||||||
if workorder.picking_ids:
|
|
||||||
for pkd in workorder.picking_ids:
|
|
||||||
z = 0
|
|
||||||
for move in pkd.move_ids:
|
|
||||||
z += 1
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': module_name_dict[pkd._original_module],
|
|
||||||
'doc_name': pkd._description,
|
|
||||||
'doc_number': f'{mo.name}-{workorder.name}-{pkd.name}',
|
|
||||||
'line_number': z,
|
|
||||||
'operation_type': pkd.picking_type_id.name,
|
|
||||||
'product_name': move.product_id.name if move.product_id else '',
|
|
||||||
'quantity': move.product_uom_qty,
|
|
||||||
'doc_state': map_dict.get(pkd.state, pkd.state),
|
|
||||||
'cancel_reason': '已有异动' if pkd.state not in ['cancel', 'waiting'] else ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
|
|
||||||
# # 检查制造订单组件的采购单和制造单
|
|
||||||
# for move in mo.move_raw_ids:
|
|
||||||
# # 检查组件的采购单
|
|
||||||
# component_pos = self.env['purchase.order'].search([
|
|
||||||
# ('origin', '=', mo.name),
|
|
||||||
# ('order_line.product_id', '=', move.product_id.id)
|
|
||||||
# ])
|
|
||||||
# for po in component_pos:
|
|
||||||
# vals = {
|
|
||||||
# 'wizard_id': wizard_id,
|
|
||||||
# 'sequence': sequence,
|
|
||||||
# 'category': '制造',
|
|
||||||
# 'doc_name': '组件采购单',
|
|
||||||
# 'operation_type': '组件采购',
|
|
||||||
# 'doc_number': po.name,
|
|
||||||
# 'product_name': move.product_id.name,
|
|
||||||
# 'quantity': po.order_line[0].product_qty if po.order_line else 0,
|
|
||||||
# 'doc_state': po.state,
|
|
||||||
# 'cancel_reason': '已有异动' if po.state not in ['draft', 'cancel'] else ''
|
|
||||||
# }
|
|
||||||
# lines.append(self.create(vals))
|
|
||||||
# sequence += 1
|
|
||||||
|
|
||||||
# # 检查制造订单的质检单
|
|
||||||
# quality_checks = self.env['quality.check'].search([
|
|
||||||
# ('production_id', '=', mo.id)
|
|
||||||
# ])
|
|
||||||
# if quality_checks:
|
|
||||||
# i = 0
|
|
||||||
# for check in quality_checks:
|
|
||||||
# i += 1
|
|
||||||
# vals = {
|
|
||||||
# 'wizard_id': wizard_id,
|
|
||||||
# 'sequence': sequence,
|
|
||||||
# 'category': '制造',
|
|
||||||
# 'doc_name': '质检单',
|
|
||||||
# 'operation_type': '',
|
|
||||||
# 'doc_number': check.name,
|
|
||||||
# 'line_number': i,
|
|
||||||
# 'product_name': f'[{check.product_id.default_code}] {check.product_id.name}',
|
|
||||||
# 'quantity': 1,
|
|
||||||
# 'doc_state': map_dict.get(check.quality_state, check.quality_state),
|
|
||||||
# 'cancel_reason': '已有异动' if check.quality_state not in ['none', 'cancel', 'waiting'] else ''
|
|
||||||
# }
|
|
||||||
# lines.append(self.create(vals))
|
|
||||||
# sequence += 1
|
|
||||||
|
|
||||||
# 检查制造订单的编程单
|
|
||||||
cloud_programming = mo._cron_get_programming_state()
|
|
||||||
if cloud_programming:
|
|
||||||
programming_no = cloud_programming['programming_no']
|
|
||||||
|
|
||||||
# 检查当前lines中是否已存在相同doc_number的记录
|
|
||||||
if not any(line.doc_number == programming_no for line in lines):
|
|
||||||
vals = {
|
|
||||||
'wizard_id': wizard_id,
|
|
||||||
'sequence': sequence,
|
|
||||||
'category': '编程',
|
|
||||||
'doc_name': '编程单',
|
|
||||||
'operation_type': '',
|
|
||||||
'doc_number': programming_no, # 直接使用变量
|
|
||||||
'line_number': 1,
|
|
||||||
'product_name': '',
|
|
||||||
'quantity': 0,
|
|
||||||
'doc_state': cloud_programming['programming_state'],
|
|
||||||
'cancel_reason': ''
|
|
||||||
}
|
|
||||||
lines.append(self.create(vals))
|
|
||||||
|
|
||||||
return lines
|
|
||||||
|
|
||||||
# unique_lines = {}
|
|
||||||
# for line in lines:
|
|
||||||
# doc_number = line.doc_number
|
|
||||||
# if doc_number not in unique_lines:
|
|
||||||
# unique_lines[doc_number] = line
|
|
||||||
#
|
|
||||||
# # 返回去重后的记录列表
|
|
||||||
# return list(unique_lines.values())
|
|
||||||
@@ -1,69 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="utf-8"?>
|
|
||||||
<odoo>
|
|
||||||
<record id="view_sf_sale_order_cancel_wizard" model="ir.ui.view">
|
|
||||||
<field name="name">sf.sale.order.cancel.wizard.form</field>
|
|
||||||
<field name="model">sf.sale.order.cancel.wizard</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="下游单据清单">
|
|
||||||
<group>
|
|
||||||
<field name="order_id" invisible="1"/>
|
|
||||||
<field name="has_movement" invisible="1"/>
|
|
||||||
</group>
|
|
||||||
<div class="alert alert-warning" role="alert">
|
|
||||||
<field name="display_message" readonly="1" nolabel="1"/>
|
|
||||||
</div>
|
|
||||||
<field name="related_docs">
|
|
||||||
<tree string="下游单据" create="false" edit="false" delete="false">
|
|
||||||
<!-- <field name="sequence" string="序号"/> -->
|
|
||||||
<field name="category" string="大类"/>
|
|
||||||
<field name="doc_name" string="单据名称"/>
|
|
||||||
<field name="operation_type" string="作业类型"/>
|
|
||||||
<field name="doc_number" string="单据编号"/>
|
|
||||||
<field name="line_number" string="行号"/>
|
|
||||||
<field name="product_name" string="产品名称"/>
|
|
||||||
<field name="quantity_str" string="数量"/>
|
|
||||||
<field name="doc_state" string="单据状态"/>
|
|
||||||
<field name="cancel_reason" string="禁止取消原因"/>
|
|
||||||
</tree>
|
|
||||||
</field>
|
|
||||||
<footer>
|
|
||||||
<button name="action_confirm_cancel"
|
|
||||||
string="确认取消"
|
|
||||||
type="object"
|
|
||||||
class="btn-primary"
|
|
||||||
attrs="{'invisible': [('has_movement', '=', True)]}"/>
|
|
||||||
<button string="关闭"
|
|
||||||
class="btn-secondary"
|
|
||||||
special="cancel"/>
|
|
||||||
</footer>
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="view_sf_sale_order_cancel_line" model="ir.ui.view">
|
|
||||||
<field name="name">sf.sale.order.cancel.line.form</field>
|
|
||||||
<field name="model">sf.sale.order.cancel.line</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<form string="下游单据明细">
|
|
||||||
<group>
|
|
||||||
<group>
|
|
||||||
<field name="category"/>
|
|
||||||
<field name="doc_name"/>
|
|
||||||
<field name="operation_type"/>
|
|
||||||
<field name="quantity_str"/>
|
|
||||||
<field name="cancel_reason"/>
|
|
||||||
|
|
||||||
</group>
|
|
||||||
<group>
|
|
||||||
<field name="line_number"/>
|
|
||||||
<field name="doc_number"/>
|
|
||||||
<field name="product_name"/>
|
|
||||||
<field name="doc_state"/>
|
|
||||||
</group>
|
|
||||||
</group>
|
|
||||||
|
|
||||||
</form>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
</odoo>
|
|
||||||
@@ -56,6 +56,7 @@ class WorkpieceDeliveryWizard(models.TransientModel):
|
|||||||
|
|
||||||
def _get_agv_route_type_selection(self):
|
def _get_agv_route_type_selection(self):
|
||||||
return self.env['sf.agv.task.route'].fields_get(['route_type'])['route_type']['selection']
|
return self.env['sf.agv.task.route'].fields_get(['route_type'])['route_type']['selection']
|
||||||
|
|
||||||
delivery_type = fields.Selection(selection=_get_agv_route_type_selection, string='类型')
|
delivery_type = fields.Selection(selection=_get_agv_route_type_selection, string='类型')
|
||||||
|
|
||||||
def dispatch_confirm(self):
|
def dispatch_confirm(self):
|
||||||
|
|||||||
@@ -68,11 +68,6 @@
|
|||||||
<field name="model">stock.picking</field>
|
<field name="model">stock.picking</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="order_quality_done" model="jikimo.message.bussiness.node">
|
|
||||||
<field name="name">调拨单质检完成提醒</field>
|
|
||||||
<field name="model">stock.picking</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="bussiness_mrp_workorder_pre_overdue_warning" model="jikimo.message.bussiness.node">
|
<record id="bussiness_mrp_workorder_pre_overdue_warning" model="jikimo.message.bussiness.node">
|
||||||
<field name="name">装夹预调工单逾期预警</field>
|
<field name="name">装夹预调工单逾期预警</field>
|
||||||
<field name="model">mrp.workorder</field>
|
<field name="model">mrp.workorder</field>
|
||||||
@@ -161,12 +156,4 @@
|
|||||||
<field name="model">product.product</field>
|
<field name="model">product.product</field>
|
||||||
</record>
|
</record>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<data noupdate="1">
|
|
||||||
<record id="bussiness_plan_data_tracking" model="jikimo.message.bussiness.node">
|
|
||||||
<field name="name">计划数据异常跟踪</field>
|
|
||||||
<field name="model">mrp.workorder</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
|
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -252,18 +252,6 @@
|
|||||||
<field name="content">### 订单发货提醒:
|
<field name="content">### 订单发货提醒:
|
||||||
单号:发料出库单[{{name}}]({{request_url}})
|
单号:发料出库单[{{name}}]({{request_url}})
|
||||||
事项:销售订单{{sale_order_name}}已全部产出并入库,请及时发货</field>
|
事项:销售订单{{sale_order_name}}已全部产出并入库,请及时发货</field>
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="template_order_quality_done" model="jikimo.message.template">
|
|
||||||
<field name="name">调拨单质检完成提醒</field>
|
|
||||||
<field name="model_id" ref="stock.model_stock_picking"/>
|
|
||||||
<field name="model">stock.picking</field>
|
|
||||||
<field name="bussiness_node_id" ref="order_quality_done"/>
|
|
||||||
<field name="msgtype">markdown</field>
|
|
||||||
<field name="urgency">normal</field>
|
|
||||||
<field name="content">### {{picking_type_name}}待处理提醒:
|
|
||||||
单号:[{{name}}]({{request_url}})
|
|
||||||
事项:质量检查已完成</field>
|
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="template_quality_cnc_test" model="jikimo.message.template">
|
<record id="template_quality_cnc_test" model="jikimo.message.template">
|
||||||
@@ -414,19 +402,4 @@
|
|||||||
事项:有{{num}}个质检单需要处理。</field>
|
事项:有{{num}}个质检单需要处理。</field>
|
||||||
</record>
|
</record>
|
||||||
</data>
|
</data>
|
||||||
|
|
||||||
<data noupdate="1">
|
|
||||||
<record id="template_plan_data_tracking" model="jikimo.message.template">
|
|
||||||
<field name="name">计划数据异常跟踪</field>
|
|
||||||
<field name="model_id" ref="mrp.model_mrp_workorder"/>
|
|
||||||
<field name="model">mrp.workorder</field>
|
|
||||||
<field name="bussiness_node_id" ref="bussiness_plan_data_tracking"/>
|
|
||||||
<field name="msgtype">markdown</field>
|
|
||||||
<field name="urgency">normal</field>
|
|
||||||
<field name="content">### 工单计划数据异常删除:
|
|
||||||
工单号:{{name}}
|
|
||||||
异动时间:{{write_date}}
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -16,7 +16,6 @@ class SFMessageProduct(models.Model):
|
|||||||
mrp_production_list = self.env['mrp.production'].sudo().search(
|
mrp_production_list = self.env['mrp.production'].sudo().search(
|
||||||
[('product_id', '=', product_product.id)])
|
[('product_id', '=', product_product.id)])
|
||||||
production_num = 0
|
production_num = 0
|
||||||
routing_type = None
|
|
||||||
for mrp_production_info in mrp_production_list:
|
for mrp_production_info in mrp_production_list:
|
||||||
routing_type = '人工线下加工' if mrp_production_info.production_type == '人工线下加工' else '装夹预调'
|
routing_type = '人工线下加工' if mrp_production_info.production_type == '人工线下加工' else '装夹预调'
|
||||||
mrp_production_ready = mrp_production_info.workorder_ids.filtered(
|
mrp_production_ready = mrp_production_info.workorder_ids.filtered(
|
||||||
@@ -24,7 +23,7 @@ class SFMessageProduct(models.Model):
|
|||||||
if mrp_production_ready:
|
if mrp_production_ready:
|
||||||
production_num += 1
|
production_num += 1
|
||||||
if production_num >= 1:
|
if production_num >= 1:
|
||||||
url = self.get_request_url(routing_type)
|
url = self.get_request_url()
|
||||||
content = content.replace('{{product_id}}', product_product.name).replace(
|
content = content.replace('{{product_id}}', product_product.name).replace(
|
||||||
'{{number}}', str(production_num)).replace(
|
'{{number}}', str(production_num)).replace(
|
||||||
'{{request_url}}', url)
|
'{{request_url}}', url)
|
||||||
@@ -43,15 +42,11 @@ class SFMessageProduct(models.Model):
|
|||||||
contents.append(content)
|
contents.append(content)
|
||||||
return contents, message_queue_ids
|
return contents, message_queue_ids
|
||||||
|
|
||||||
def get_request_url(self, routing_type):
|
def get_request_url(self):
|
||||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
||||||
action_id = self.env.ref('sf_message.mrp_workorder_issued_action').id
|
action_id = self.env.ref('sf_message.mrp_workorder_issued_action').id
|
||||||
menu_id = self.env.ref('mrp.menu_mrp_root').id
|
menu_id = self.env.ref('mrp.menu_mrp_root').id
|
||||||
if routing_type == '人工线下加工':
|
active_id = self.env['mrp.workcenter'].sudo().search([('name', '=', '工件装夹中心')]).id
|
||||||
routing_name = '线下工作中心'
|
|
||||||
else:
|
|
||||||
routing_name = '工件装夹中心'
|
|
||||||
active_id = self.env['mrp.workcenter'].sudo().search([('name', '=', routing_name)]).id
|
|
||||||
# 查询参数
|
# 查询参数
|
||||||
params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder',
|
params = {'menu_id': menu_id, 'action': action_id, 'model': 'mrp.workorder',
|
||||||
'view_type': 'list', 'active_id': active_id}
|
'view_type': 'list', 'active_id': active_id}
|
||||||
|
|||||||
@@ -9,8 +9,6 @@ class SFMessageStockPicking(models.Model):
|
|||||||
_description = "库存调拨"
|
_description = "库存调拨"
|
||||||
_inherit = ['stock.picking', 'jikimo.message.dispatch']
|
_inherit = ['stock.picking', 'jikimo.message.dispatch']
|
||||||
|
|
||||||
quality_check_ids = fields.One2many('quality.check', 'picking_id', '质量检测单')
|
|
||||||
|
|
||||||
@api.model_create_multi
|
@api.model_create_multi
|
||||||
def create(self, vals):
|
def create(self, vals):
|
||||||
result = super(SFMessageStockPicking, self).create(vals)
|
result = super(SFMessageStockPicking, self).create(vals)
|
||||||
@@ -22,16 +20,13 @@ class SFMessageStockPicking(models.Model):
|
|||||||
logging.info('add_queue调拨入库 error:%s' % e)
|
logging.info('add_queue调拨入库 error:%s' % e)
|
||||||
return result
|
return result
|
||||||
|
|
||||||
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id',
|
@api.depends('move_type', 'immediate_transfer', 'move_ids.state', 'move_ids.picking_id')
|
||||||
'quality_check_ids.quality_state')
|
|
||||||
def _compute_state(self):
|
def _compute_state(self):
|
||||||
super(SFMessageStockPicking, self)._compute_state()
|
super(SFMessageStockPicking, self)._compute_state()
|
||||||
try:
|
try:
|
||||||
for record in self:
|
for record in self:
|
||||||
if (record.state == 'assigned' and record.picking_type_id.sequence_code == 'PC'
|
if (record.state == 'assigned' and record.picking_type_id.sequence_code == 'PC'
|
||||||
and record.product_id.categ_id.type == '坯料'):
|
and record.product_id.categ_id.type == '坯料'):
|
||||||
jikimo_message_queue = record.get_message_queue(record.id)
|
|
||||||
if not jikimo_message_queue:
|
|
||||||
record.add_queue('坯料发料提醒')
|
record.add_queue('坯料发料提醒')
|
||||||
|
|
||||||
if record.picking_type_id.sequence_code == 'SFP' and record.state == 'done':
|
if record.picking_type_id.sequence_code == 'SFP' and record.state == 'done':
|
||||||
@@ -53,14 +48,6 @@ class SFMessageStockPicking(models.Model):
|
|||||||
all_ready_or_done = all(picking.state in ['assigned', 'done'] for picking in stock_picking_list)
|
all_ready_or_done = all(picking.state in ['assigned', 'done'] for picking in stock_picking_list)
|
||||||
if all_ready_or_done:
|
if all_ready_or_done:
|
||||||
mrp_production.add_queue('工序外协发料通知')
|
mrp_production.add_queue('工序外协发料通知')
|
||||||
if record.quality_check_ids and all(
|
|
||||||
qc.quality_state in ['pass', 'fail'] for qc in record.quality_check_ids):
|
|
||||||
message_template_id = self.env["jikimo.message.template"].sudo().search(
|
|
||||||
[('name', '=', '调拨单质检完成提醒')])
|
|
||||||
stock_picking_send = self.env["jikimo.message.queue"].sudo().search(
|
|
||||||
[('res_id', '=', record.id), ('message_template_id', '=', message_template_id.id)])
|
|
||||||
if not stock_picking_send:
|
|
||||||
record.add_queue('调拨单质检完成提醒')
|
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
logging.info('add_queue_compute_state error:%s' % e)
|
logging.info('add_queue_compute_state error:%s' % e)
|
||||||
|
|
||||||
@@ -96,17 +83,6 @@ class SFMessageStockPicking(models.Model):
|
|||||||
content = self.deal_stock_picking_sfp(message_queue_id)
|
content = self.deal_stock_picking_sfp(message_queue_id)
|
||||||
if content:
|
if content:
|
||||||
contents.append(content)
|
contents.append(content)
|
||||||
elif message_queue_id.message_template_id.name == '调拨单质检完成提醒':
|
|
||||||
content = message_queue_id.message_template_id.content
|
|
||||||
stock_picking_line = self.env['stock.picking'].sudo().search(
|
|
||||||
[('id', '=', int(message_queue_id.res_id))])
|
|
||||||
url = self.env['ir.config_parameter'].sudo().get_param('web.base.url')
|
|
||||||
action_id = self.env.ref('stock.action_picking_tree_ready').id
|
|
||||||
menu_id = self.env.ref('stock.menu_stock_root').id
|
|
||||||
url_with_id = f"{url}/web#view_type=form&action={action_id}&menu_id={menu_id}&id={stock_picking_line.id}"
|
|
||||||
content = content.replace('{{picking_type_name}}', stock_picking_line.picking_type_id.name).replace(
|
|
||||||
'{{name}}', stock_picking_line.name).replace('{{request_url}}', url_with_id)
|
|
||||||
contents.append(content)
|
|
||||||
return contents, message_queue_ids
|
return contents, message_queue_ids
|
||||||
|
|
||||||
def get_special_url(self, id, tmplate_name, special_name, model_id):
|
def get_special_url(self, id, tmplate_name, special_name, model_id):
|
||||||
@@ -131,14 +107,3 @@ class SFMessageStockPicking(models.Model):
|
|||||||
# 拼接URL
|
# 拼接URL
|
||||||
full_url = url + "/web#" + query_string
|
full_url = url + "/web#" + query_string
|
||||||
return full_url
|
return full_url
|
||||||
|
|
||||||
def get_message_queue(self, res_id):
|
|
||||||
business_node_id = self.env.ref('sf_message.bussiness_material_picking_remind').id
|
|
||||||
message_template = self.env["jikimo.message.template"].sudo().search([
|
|
||||||
("model", "=", self._name),
|
|
||||||
("bussiness_node_id", "=", business_node_id)
|
|
||||||
], limit=1)
|
|
||||||
jikimo_message_queue = self.env['jikimo.message.queue'].sudo().search(
|
|
||||||
[('res_id', '=', res_id), ("message_status", "in", ("pending", "sent")),
|
|
||||||
('message_template_id', '=', message_template.id)])
|
|
||||||
return jikimo_message_queue
|
|
||||||
|
|||||||
@@ -188,10 +188,3 @@ class SFMessageWork(models.Model):
|
|||||||
])
|
])
|
||||||
if message_queue_ids:
|
if message_queue_ids:
|
||||||
message_queue_ids.write({'message_status': 'cancel'})
|
message_queue_ids.write({'message_status': 'cancel'})
|
||||||
|
|
||||||
def write(self, vals):
|
|
||||||
res = super(SFMessageWork, self).write(vals)
|
|
||||||
if ('leave_id' in vals and vals['leave_id'] is False or 'date_planned_start' in vals and vals['date_planned_start'] is False) \
|
|
||||||
and self.schedule_state != '未排':
|
|
||||||
self.add_queue('计划数据异常跟踪')
|
|
||||||
return res
|
|
||||||
|
|||||||
@@ -61,7 +61,7 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
|
|||||||
for panel in ret['processing_panel'].split(','):
|
for panel in ret['processing_panel'].split(','):
|
||||||
# 查询状态为进行中且工序类型为CNC加工的工单
|
# 查询状态为进行中且工序类型为CNC加工的工单
|
||||||
cnc_workorder_has = production.workorder_ids.filtered(
|
cnc_workorder_has = production.workorder_ids.filtered(
|
||||||
lambda ach: ach.routing_type in ['CNC加工', '人工线下加工'] and ach.state not in ['progress', 'done',
|
lambda ach: ach.routing_type == 'CNC加工' and ach.state not in ['progress', 'done',
|
||||||
'rework',
|
'rework',
|
||||||
'cancel'] and ach.processing_panel == panel)
|
'cancel'] and ach.processing_panel == panel)
|
||||||
if cnc_workorder_has:
|
if cnc_workorder_has:
|
||||||
@@ -76,7 +76,7 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
|
|||||||
for panel in ret['processing_panel'].split(','):
|
for panel in ret['processing_panel'].split(','):
|
||||||
# 查询状态为进行中且工序类型为CNC加工的工单
|
# 查询状态为进行中且工序类型为CNC加工的工单
|
||||||
cnc_workorder = productions.workorder_ids.filtered(
|
cnc_workorder = productions.workorder_ids.filtered(
|
||||||
lambda ac: ac.routing_type in ['CNC加工', '人工线下加工'] and ac.state not in ['progress', 'done', 'rework'
|
lambda ac: ac.routing_type == 'CNC加工' and ac.state not in ['progress', 'done', 'rework'
|
||||||
'cancel'] and ac.processing_panel == panel)
|
'cancel'] and ac.processing_panel == panel)
|
||||||
if cnc_workorder:
|
if cnc_workorder:
|
||||||
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
|
# program_path_tmp_panel = os.path.join('C://Users//43484//Desktop//fsdownload//test',
|
||||||
@@ -91,21 +91,19 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
|
|||||||
logging.info('panel_file_path:%s' % panel_file_path)
|
logging.info('panel_file_path:%s' % panel_file_path)
|
||||||
cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
|
cnc_workorder.write({'cnc_worksheet': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||||
pre_workorder = productions.workorder_ids.filtered(
|
pre_workorder = productions.workorder_ids.filtered(
|
||||||
lambda ap: ap.routing_type in ['装夹预调', '人工线下加工'] and ap.state not in ['done', 'rework'
|
lambda ap: ap.routing_type == '装夹预调' and ap.state not in ['done', 'rework'
|
||||||
'cancel'] and ap.processing_panel == panel)
|
'cancel'] and ap.processing_panel == panel)
|
||||||
if pre_workorder:
|
if pre_workorder:
|
||||||
pre_workorder.write(
|
pre_workorder.write(
|
||||||
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
|
{'processing_drawing': base64.b64encode(open(panel_file_path, 'rb').read())})
|
||||||
productions.write({'programming_state': '已编程', 'work_state': '已编程'})
|
productions.write({'programming_state': '已编程', 'work_state': '已编程'})
|
||||||
productions.filtered(lambda p: p.production_type == '人工线下加工').write({'manual_quotation': True})
|
|
||||||
logging.info('已更新制造订单编程状态:%s' % productions.ids)
|
logging.info('已更新制造订单编程状态:%s' % productions.ids)
|
||||||
|
|
||||||
# 对制造订单所有面的cnc工单的程序用刀进行校验
|
# 对制造订单所有面的cnc工单的程序用刀进行校验
|
||||||
try:
|
try:
|
||||||
logging.info(f'已更新制造订单:{productions}')
|
logging.info(f'已更新制造订单:{productions}')
|
||||||
re_tool_chekout = False
|
re_tool_chekout = False
|
||||||
productions_temp = productions.filtered(lambda p: p.production_type == '自动化产线加工')
|
re_tool_chekout = productions.production_cnc_tool_checkout()
|
||||||
re_tool_chekout = productions_temp.production_cnc_tool_checkout()
|
|
||||||
if re_tool_chekout:
|
if re_tool_chekout:
|
||||||
return json.JSONEncoder().encode({'status': -3, 'message': '对cnc工单的程序用刀进行校验失败'})
|
return json.JSONEncoder().encode({'status': -3, 'message': '对cnc工单的程序用刀进行校验失败'})
|
||||||
except Exception as e:
|
except Exception as e:
|
||||||
@@ -202,17 +200,6 @@ class Sf_Mrs_Connect(http.Controller, MultiInheritController):
|
|||||||
'send_time': ret['send_time'],
|
'send_time': ret['send_time'],
|
||||||
})
|
})
|
||||||
logging.info('已创建无效功能刀具的编程记录:%s' % production.name)
|
logging.info('已创建无效功能刀具的编程记录:%s' % production.name)
|
||||||
elif ret['reprogramming_reason']:
|
|
||||||
production.programming_record_ids.create({
|
|
||||||
'number': len(production.programming_record_ids) + 1,
|
|
||||||
'production_id': production.id,
|
|
||||||
'reason': ret['reprogramming_reason'],
|
|
||||||
'programming_method': ret['programme_way'],
|
|
||||||
'current_programming_count': ret['reprogramming_num'],
|
|
||||||
'target_production_id': productions_reprogram,
|
|
||||||
'apply_time': ret['trigger_time'],
|
|
||||||
'send_time': ret['send_time'],
|
|
||||||
})
|
|
||||||
else:
|
else:
|
||||||
logging.info('无对应状态,不需更新编程记录')
|
logging.info('无对应状态,不需更新编程记录')
|
||||||
|
|
||||||
|
|||||||
@@ -1968,7 +1968,8 @@ class CuttingSpeed(models.Model):
|
|||||||
self.create({
|
self.create({
|
||||||
'name': item['name'],
|
'name': item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', item['standard_library_code'])]).id,
|
[('code', '=', item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'execution_standard_id': self.env['sf.international.standards'].search(
|
'execution_standard_id': self.env['sf.international.standards'].search(
|
||||||
[('code', '=', item['execution_standard_code'])]).id,
|
[('code', '=', item['execution_standard_code'])]).id,
|
||||||
'material_name_id': self.env['sf.materials.model'].search(
|
'material_name_id': self.env['sf.materials.model'].search(
|
||||||
@@ -1987,8 +1988,6 @@ class CuttingSpeed(models.Model):
|
|||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
cutting_speed.write({
|
cutting_speed.write({
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', item['standard_library_code'])]).id,
|
|
||||||
'execution_standard_id': self.env['sf.international.standards'].search(
|
'execution_standard_id': self.env['sf.international.standards'].search(
|
||||||
[('code', '=', item['execution_standard_code'])]).id,
|
[('code', '=', item['execution_standard_code'])]).id,
|
||||||
'material_name_id': self.env['sf.materials.model'].search(
|
'material_name_id': self.env['sf.materials.model'].search(
|
||||||
@@ -2021,7 +2020,8 @@ class CuttingSpeed(models.Model):
|
|||||||
self.create({
|
self.create({
|
||||||
'name': item['name'],
|
'name': item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', item['standard_library_code'])]).id,
|
[('code', '=', item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'execution_standard_id': self.env['sf.international.standards'].search(
|
'execution_standard_id': self.env['sf.international.standards'].search(
|
||||||
[('code', '=', item['execution_standard_code'])]).id,
|
[('code', '=', item['execution_standard_code'])]).id,
|
||||||
'material_name_id': self.env['sf.materials.model'].search(
|
'material_name_id': self.env['sf.materials.model'].search(
|
||||||
@@ -2040,8 +2040,6 @@ class CuttingSpeed(models.Model):
|
|||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
cutting_speed.write({
|
cutting_speed.write({
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', item['standard_library_code'])]).id,
|
|
||||||
'execution_standard_id': self.env['sf.international.standards'].search(
|
'execution_standard_id': self.env['sf.international.standards'].search(
|
||||||
[('code', '=', item['execution_standard_code'])]).id,
|
[('code', '=', item['execution_standard_code'])]).id,
|
||||||
'material_name_id': self.env['sf.materials.model'].search(
|
'material_name_id': self.env['sf.materials.model'].search(
|
||||||
@@ -2120,7 +2118,8 @@ class CuttingSpeed(models.Model):
|
|||||||
self.create({
|
self.create({
|
||||||
'name': item['name'],
|
'name': item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', item['standard_library_code'])]).id,
|
[('code', '=', item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'materials_type_id': self.env['sf.materials.model'].search(
|
'materials_type_id': self.env['sf.materials.model'].search(
|
||||||
[('materials_no', '=', item['materials_type_code'])]).id,
|
[('materials_no', '=', item['materials_type_code'])]).id,
|
||||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||||
@@ -2131,8 +2130,6 @@ class CuttingSpeed(models.Model):
|
|||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
feed_per_tooth.write({
|
feed_per_tooth.write({
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', item['standard_library_code'])]).id,
|
|
||||||
'materials_type_id': self.env['sf.materials.model'].search(
|
'materials_type_id': self.env['sf.materials.model'].search(
|
||||||
[('materials_no', '=', item['materials_type_code'])]).id,
|
[('materials_no', '=', item['materials_type_code'])]).id,
|
||||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||||
@@ -2159,7 +2156,8 @@ class CuttingSpeed(models.Model):
|
|||||||
self.create({
|
self.create({
|
||||||
'name': item['name'],
|
'name': item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', item['standard_library_code'])]).id,
|
[('code', '=', item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'materials_type_id': self.env['sf.materials.model'].search(
|
'materials_type_id': self.env['sf.materials.model'].search(
|
||||||
[('materials_no', '=', item['materials_type_code'])]).id,
|
[('materials_no', '=', item['materials_type_code'])]).id,
|
||||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||||
@@ -2170,8 +2168,6 @@ class CuttingSpeed(models.Model):
|
|||||||
})
|
})
|
||||||
else:
|
else:
|
||||||
feed_per_tooth.write({
|
feed_per_tooth.write({
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', item['standard_library_code'])]).id,
|
|
||||||
'materials_type_id': self.env['sf.materials.model'].search(
|
'materials_type_id': self.env['sf.materials.model'].search(
|
||||||
[('materials_no', '=', item['materials_type_code'])]).id,
|
[('materials_no', '=', item['materials_type_code'])]).id,
|
||||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||||
@@ -2199,7 +2195,7 @@ class Cutting_tool_standard_library(models.Model):
|
|||||||
if result['status'] == 1:
|
if result['status'] == 1:
|
||||||
for item in result['cutting_tool_standard_library_yesterday_list']:
|
for item in result['cutting_tool_standard_library_yesterday_list']:
|
||||||
cutting_tool_standard_library = self.search(
|
cutting_tool_standard_library = self.search(
|
||||||
[("code", '=', item['code']),
|
[("code", '=', item['code'].replace("JKM", result['factory_short_name'])),
|
||||||
('active', 'in', [True, False])])
|
('active', 'in', [True, False])])
|
||||||
cutting_tool_type = self.env['sf.cutting.tool.type'].search(
|
cutting_tool_type = self.env['sf.cutting.tool.type'].search(
|
||||||
[("code", '=', item['cutting_tool_type_code'])])
|
[("code", '=', item['cutting_tool_type_code'])])
|
||||||
@@ -2210,7 +2206,7 @@ class Cutting_tool_standard_library(models.Model):
|
|||||||
brand = self.env['sf.machine.brand'].search([("code", '=', item['brand_code'])])
|
brand = self.env['sf.machine.brand'].search([("code", '=', item['brand_code'])])
|
||||||
if not cutting_tool_standard_library:
|
if not cutting_tool_standard_library:
|
||||||
self.create({
|
self.create({
|
||||||
"code": item['code'],
|
"code": item['code'].replace("JKM", result['factory_short_name']),
|
||||||
"name": item['name'],
|
"name": item['name'],
|
||||||
"cutting_tool_material_id": cutting_tool_material.id,
|
"cutting_tool_material_id": cutting_tool_material.id,
|
||||||
"cutting_tool_type_id": cutting_tool_type.id,
|
"cutting_tool_type_id": cutting_tool_type.id,
|
||||||
@@ -2232,9 +2228,9 @@ class Cutting_tool_standard_library(models.Model):
|
|||||||
'maintenance.equipment.image'].search(
|
'maintenance.equipment.image'].search(
|
||||||
[('name', '=', item['fit_blade_shape'])]).id,
|
[('name', '=', item['fit_blade_shape'])]).id,
|
||||||
"chuck_id": False if not item['chuck_code'] else self.search(
|
"chuck_id": False if not item['chuck_code'] else self.search(
|
||||||
[('code', '=', item['chuck_code'])]).id,
|
[('code', '=', item['chuck_code'].replace("JKM", result['factory_short_name']))]).id,
|
||||||
"handle_id": False if not item['handle_code'] else self.search(
|
"handle_id": False if not item['handle_code'] else self.search(
|
||||||
[('code', '=', item['handle_code'])]).id,
|
[('code', '=', item['handle_code'].replace("JKM", result['factory_short_name']))]).id,
|
||||||
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
|
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
|
||||||
'suitable_machining_methods') else self.env['maintenance.equipment.image']._get_ids(
|
'suitable_machining_methods') else self.env['maintenance.equipment.image']._get_ids(
|
||||||
item['suitable_machining_methods']),
|
item['suitable_machining_methods']),
|
||||||
@@ -2274,9 +2270,9 @@ class Cutting_tool_standard_library(models.Model):
|
|||||||
'maintenance.equipment.image'].search(
|
'maintenance.equipment.image'].search(
|
||||||
[('name', '=', item['fit_blade_shape'])]).id,
|
[('name', '=', item['fit_blade_shape'])]).id,
|
||||||
"chuck_id": False if not item['chuck_code'] else self.search(
|
"chuck_id": False if not item['chuck_code'] else self.search(
|
||||||
[('code', '=', item['chuck_code'])]).id,
|
[('code', '=', item['chuck_code'].replace("JKM", result['factory_short_name']))]).id,
|
||||||
"handle_id": False if not item['handle_code'] else self.search(
|
"handle_id": False if not item['handle_code'] else self.search(
|
||||||
[('code', '=', item['handle_code'])]).id,
|
[('code', '=', item['handle_code'].replace("JKM", result['factory_short_name']))]).id,
|
||||||
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
|
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
|
||||||
'suitable_machining_methods') else self.env['maintenance.equipment.image']._get_ids(
|
'suitable_machining_methods') else self.env['maintenance.equipment.image']._get_ids(
|
||||||
item['suitable_machining_methods']),
|
item['suitable_machining_methods']),
|
||||||
@@ -2306,7 +2302,7 @@ class Cutting_tool_standard_library(models.Model):
|
|||||||
if result['status'] == 1:
|
if result['status'] == 1:
|
||||||
for item in result['cutting_tool_standard_library_all_list']:
|
for item in result['cutting_tool_standard_library_all_list']:
|
||||||
cutting_tool_standard_library = self.search(
|
cutting_tool_standard_library = self.search(
|
||||||
[("code", '=', item['code']),
|
[("code", '=', item['code'].replace("JKM", result['factory_short_name'])),
|
||||||
("active", 'in', [True, False])])
|
("active", 'in', [True, False])])
|
||||||
cutting_tool_type = self.env['sf.cutting.tool.type'].search(
|
cutting_tool_type = self.env['sf.cutting.tool.type'].search(
|
||||||
[("code", '=', item['cutting_tool_type_code'])])
|
[("code", '=', item['cutting_tool_type_code'])])
|
||||||
@@ -2317,7 +2313,7 @@ class Cutting_tool_standard_library(models.Model):
|
|||||||
brand = self.env['sf.machine.brand'].search([("code", '=', item['brand_code'])])
|
brand = self.env['sf.machine.brand'].search([("code", '=', item['brand_code'])])
|
||||||
if not cutting_tool_standard_library:
|
if not cutting_tool_standard_library:
|
||||||
self.create({
|
self.create({
|
||||||
"code": item['code'],
|
"code": item['code'].replace("JKM", result['factory_short_name']),
|
||||||
"name": item['name'],
|
"name": item['name'],
|
||||||
"cutting_tool_material_id": cutting_tool_material.id,
|
"cutting_tool_material_id": cutting_tool_material.id,
|
||||||
"cutting_tool_type_id": cutting_tool_type.id,
|
"cutting_tool_type_id": cutting_tool_type.id,
|
||||||
@@ -2339,9 +2335,9 @@ class Cutting_tool_standard_library(models.Model):
|
|||||||
'maintenance.equipment.image'].search(
|
'maintenance.equipment.image'].search(
|
||||||
[('name', '=', item['fit_blade_shape'])]).id,
|
[('name', '=', item['fit_blade_shape'])]).id,
|
||||||
"chuck_id": False if not item['chuck_code'] else self.search(
|
"chuck_id": False if not item['chuck_code'] else self.search(
|
||||||
[('code', '=', item['chuck_code'])]).id,
|
[('code', '=', item['chuck_code'].replace("JKM", result['factory_short_name']))]).id,
|
||||||
"handle_id": False if not item['handle_code'] else self.search(
|
"handle_id": False if not item['handle_code'] else self.search(
|
||||||
[('code', '=', item['handle_code'])]).id,
|
[('code', '=', item['handle_code'].replace("JKM", result['factory_short_name']))]).id,
|
||||||
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
|
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
|
||||||
'suitable_machining_method') else self.env['maintenance.equipment.image']._get_ids(
|
'suitable_machining_method') else self.env['maintenance.equipment.image']._get_ids(
|
||||||
item['suitable_machining_method']),
|
item['suitable_machining_method']),
|
||||||
@@ -2381,12 +2377,12 @@ class Cutting_tool_standard_library(models.Model):
|
|||||||
'maintenance.equipment.image'].search(
|
'maintenance.equipment.image'].search(
|
||||||
[('name', '=', item['fit_blade_shape'])]).id,
|
[('name', '=', item['fit_blade_shape'])]).id,
|
||||||
"chuck_id": False if not item['chuck_code'] else self.search(
|
"chuck_id": False if not item['chuck_code'] else self.search(
|
||||||
[('code', '=', item['chuck_code'])]).id,
|
[('code', '=', item['chuck_code'].replace("JKM", result['factory_short_name']))]).id,
|
||||||
"handle_id": False if not item['handle_code'] else self.search(
|
"handle_id": False if not item['handle_code'] else self.search(
|
||||||
[('code', '=', item['handle_code'])]).id,
|
[('code', '=', item['handle_code'].replace("JKM", result['factory_short_name']))]).id,
|
||||||
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
|
"suitable_machining_method_ids": [(6, 0, [])] if not item.get(
|
||||||
'suitable_machining_method') else self.env['maintenance.equipment.image']._get_ids(
|
'suitable_machining_methods') else self.env['maintenance.equipment.image']._get_ids(
|
||||||
item['suitable_machining_method']),
|
item['suitable_machining_methods']),
|
||||||
"blade_tip_characteristics_id": self.env['maintenance.equipment.image'].search(
|
"blade_tip_characteristics_id": self.env['maintenance.equipment.image'].search(
|
||||||
[('name', '=', item['blade_tip_characteristics'])]).id,
|
[('name', '=', item['blade_tip_characteristics'])]).id,
|
||||||
"handle_type_id": self.env['maintenance.equipment.image'].search(
|
"handle_type_id": self.env['maintenance.equipment.image'].search(
|
||||||
@@ -2434,7 +2430,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[(
|
[(
|
||||||
'code', '=',
|
'code', '=',
|
||||||
integral_tool_item['standard_library_code'])]).id,
|
integral_tool_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'total_length': integral_tool_item['total_length'],
|
'total_length': integral_tool_item['total_length'],
|
||||||
'blade_diameter': integral_tool_item['blade_diameter'],
|
'blade_diameter': integral_tool_item['blade_diameter'],
|
||||||
'blade_length': integral_tool_item['blade_length'],
|
'blade_length': integral_tool_item['blade_length'],
|
||||||
@@ -2457,10 +2454,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
self.search([('code', '=', integral_tool_item['code'])]).write({
|
self.search([('code', '=', integral_tool_item['code'])]).write({
|
||||||
'name': integral_tool_item['name'],
|
'name': integral_tool_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[(
|
|
||||||
'code', '=',
|
|
||||||
integral_tool_item['standard_library_code'])]).id,
|
|
||||||
'total_length': integral_tool_item['total_length'],
|
'total_length': integral_tool_item['total_length'],
|
||||||
'blade_diameter': integral_tool_item['blade_diameter'],
|
'blade_diameter': integral_tool_item['blade_diameter'],
|
||||||
'blade_length': integral_tool_item['blade_length'],
|
'blade_length': integral_tool_item['blade_length'],
|
||||||
@@ -2493,7 +2486,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'code': blade_item['code'],
|
'code': blade_item['code'],
|
||||||
'cutting_tool_type': '刀片',
|
'cutting_tool_type': '刀片',
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', blade_item['standard_library_code'])]).id,
|
[('code', '=', blade_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'length': blade_item['length'],
|
'length': blade_item['length'],
|
||||||
'thickness': blade_item['thickness'],
|
'thickness': blade_item['thickness'],
|
||||||
'cutting_blade_length': blade_item['cutting_blade_length'],
|
'cutting_blade_length': blade_item['cutting_blade_length'],
|
||||||
@@ -2522,8 +2516,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
self.search([('code', '=', blade_item['code'])]).write({
|
self.search([('code', '=', blade_item['code'])]).write({
|
||||||
'name': blade_item['name'],
|
'name': blade_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', blade_item['standard_library_code'])]).id,
|
|
||||||
'length': blade_item['length'],
|
'length': blade_item['length'],
|
||||||
'thickness': blade_item['thickness'],
|
'thickness': blade_item['thickness'],
|
||||||
'cutting_blade_length': blade_item['cutting_blade_length'],
|
'cutting_blade_length': blade_item['cutting_blade_length'],
|
||||||
@@ -2562,7 +2554,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'code': chuck_item['code'],
|
'code': chuck_item['code'],
|
||||||
'cutting_tool_type': '夹头',
|
'cutting_tool_type': '夹头',
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', chuck_item['standard_library_code'])]).id,
|
[('code', '=', chuck_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'er_size_model': chuck_item['size_model'],
|
'er_size_model': chuck_item['size_model'],
|
||||||
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
||||||
'max_clamping_diameter': chuck_item['clamping_diameter_max'],
|
'max_clamping_diameter': chuck_item['clamping_diameter_max'],
|
||||||
@@ -2580,8 +2573,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
self.search([('code', '=', chuck_item['code'])]).write({
|
self.search([('code', '=', chuck_item['code'])]).write({
|
||||||
'name': chuck_item['name'],
|
'name': chuck_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', chuck_item['standard_library_code'])]).id,
|
|
||||||
'er_size_model': chuck_item['size_model'],
|
'er_size_model': chuck_item['size_model'],
|
||||||
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
||||||
'max_clamping_diameter': chuck_item['clamping_diameter_max'],
|
'max_clamping_diameter': chuck_item['clamping_diameter_max'],
|
||||||
@@ -2610,7 +2601,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'code': cutter_arbor_item['code'],
|
'code': cutter_arbor_item['code'],
|
||||||
'cutting_tool_type': '刀杆',
|
'cutting_tool_type': '刀杆',
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', cutter_arbor_item['standard_library_code'])]).id,
|
[('code', '=', cutter_arbor_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'height': cutter_arbor_item['height'],
|
'height': cutter_arbor_item['height'],
|
||||||
'width': cutter_arbor_item['width'],
|
'width': cutter_arbor_item['width'],
|
||||||
'total_length': cutter_arbor_item['total_length'],
|
'total_length': cutter_arbor_item['total_length'],
|
||||||
@@ -2628,7 +2620,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'installing_structure': cutter_arbor_item['mounting_structure'],
|
'installing_structure': cutter_arbor_item['mounting_structure'],
|
||||||
'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else self.env[
|
'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else self.env[
|
||||||
'sf.cutting_tool.standard.library'].search(
|
'sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', cutter_arbor_item['fit_blade_model_code'])]).id,
|
[('code', '=', cutter_arbor_item['fit_blade_model_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
|
'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
|
||||||
'cotter_pin': cutter_arbor_item['fit_pin_model'],
|
'cotter_pin': cutter_arbor_item['fit_pin_model'],
|
||||||
'pressing_plate': cutter_arbor_item['fit_plate_model'],
|
'pressing_plate': cutter_arbor_item['fit_plate_model'],
|
||||||
@@ -2639,8 +2632,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
self.search([('code', '=', cutter_arbor_item['code'])]).write({
|
self.search([('code', '=', cutter_arbor_item['code'])]).write({
|
||||||
'name': cutter_arbor_item['name'],
|
'name': cutter_arbor_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', cutter_arbor_item['standard_library_code'])]).id,
|
|
||||||
'height': cutter_arbor_item['height'],
|
'height': cutter_arbor_item['height'],
|
||||||
'width': cutter_arbor_item['width'],
|
'width': cutter_arbor_item['width'],
|
||||||
'total_length': cutter_arbor_item['total_length'],
|
'total_length': cutter_arbor_item['total_length'],
|
||||||
@@ -2658,7 +2649,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'installing_structure': cutter_arbor_item['mounting_structure'],
|
'installing_structure': cutter_arbor_item['mounting_structure'],
|
||||||
'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else self.env[
|
'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else self.env[
|
||||||
'sf.cutting_tool.standard.library'].search(
|
'sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', cutter_arbor_item['fit_blade_model_code'])]).id,
|
[('code', '=', cutter_arbor_item['fit_blade_model_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
|
'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
|
||||||
'cotter_pin': cutter_arbor_item['fit_pin_model'],
|
'cotter_pin': cutter_arbor_item['fit_pin_model'],
|
||||||
'pressing_plate': cutter_arbor_item['fit_plate_model'],
|
'pressing_plate': cutter_arbor_item['fit_plate_model'],
|
||||||
@@ -2680,7 +2672,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'code': cutter_head_item['code'],
|
'code': cutter_head_item['code'],
|
||||||
'cutting_tool_type': '刀盘',
|
'cutting_tool_type': '刀盘',
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', cutter_head_item['standard_library_code'])]).id,
|
[('code', '=', cutter_head_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
||||||
'blade_diameter': cutter_head_item['blade_diameter'],
|
'blade_diameter': cutter_head_item['blade_diameter'],
|
||||||
'cutter_head_diameter': cutter_head_item['cutter_diameter'],
|
'cutter_head_diameter': cutter_head_item['cutter_diameter'],
|
||||||
@@ -2693,7 +2686,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'installing_structure': cutter_head_item['mounting_structure'],
|
'installing_structure': cutter_head_item['mounting_structure'],
|
||||||
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
|
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
|
||||||
'sf.cutting_tool.standard.library'].search(
|
'sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', cutter_head_item['fit_blade_model_code'])]).id,
|
[('code', '=', cutter_head_item['fit_blade_model_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'screw': cutter_head_item['fit_screw_model'],
|
'screw': cutter_head_item['fit_screw_model'],
|
||||||
'spanner': cutter_head_item['fit_wrench_model'],
|
'spanner': cutter_head_item['fit_wrench_model'],
|
||||||
'is_cooling_hole': cutter_head_item['is_cooling_hole'],
|
'is_cooling_hole': cutter_head_item['is_cooling_hole'],
|
||||||
@@ -2703,8 +2697,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
self.search([('code', '=', cutter_head_item['code'])]).write({
|
self.search([('code', '=', cutter_head_item['code'])]).write({
|
||||||
'name': cutter_head_item['name'],
|
'name': cutter_head_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', cutter_head_item['standard_library_code'])]).id,
|
|
||||||
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
||||||
'blade_diameter': cutter_head_item['blade_diameter'],
|
'blade_diameter': cutter_head_item['blade_diameter'],
|
||||||
'cutter_head_diameter': cutter_head_item['cutter_diameter'],
|
'cutter_head_diameter': cutter_head_item['cutter_diameter'],
|
||||||
@@ -2717,7 +2709,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'installing_structure': cutter_head_item['mounting_structure'],
|
'installing_structure': cutter_head_item['mounting_structure'],
|
||||||
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
|
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
|
||||||
'sf.cutting_tool.standard.library'].search(
|
'sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', cutter_head_item['fit_blade_model_code'])]).id,
|
[('code', '=', cutter_head_item['fit_blade_model_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'screw': cutter_head_item['fit_screw_model'],
|
'screw': cutter_head_item['fit_screw_model'],
|
||||||
'spanner': cutter_head_item['fit_wrench_model'],
|
'spanner': cutter_head_item['fit_wrench_model'],
|
||||||
'is_cooling_hole': cutter_head_item['is_cooling_hole'],
|
'is_cooling_hole': cutter_head_item['is_cooling_hole'],
|
||||||
@@ -2734,8 +2727,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
[('code', '=', knife_handle_item['code']), ('active', 'in', [True, False])])
|
[('code', '=', knife_handle_item['code']), ('active', 'in', [True, False])])
|
||||||
val = {
|
val = {
|
||||||
'name': knife_handle_item['name'],
|
'name': knife_handle_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', knife_handle_item['standard_library_code'])]).id,
|
|
||||||
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
||||||
'total_length': knife_handle_item['total_length'],
|
'total_length': knife_handle_item['total_length'],
|
||||||
'flange_shank_length': knife_handle_item['flange_length'],
|
'flange_shank_length': knife_handle_item['flange_length'],
|
||||||
@@ -2760,6 +2751,9 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
if not knife_handle:
|
if not knife_handle:
|
||||||
val['code'] = knife_handle_item['code']
|
val['code'] = knife_handle_item['code']
|
||||||
val['cutting_tool_type'] = '刀柄'
|
val['cutting_tool_type'] = '刀柄'
|
||||||
|
val['standard_library_id'] = self.env['sf.cutting_tool.standard.library'].search(
|
||||||
|
[('code', '=', knife_handle_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id
|
||||||
self.create(val)
|
self.create(val)
|
||||||
else:
|
else:
|
||||||
self.search([('code', '=', knife_handle_item['code'])]).write(val)
|
self.search([('code', '=', knife_handle_item['code'])]).write(val)
|
||||||
@@ -2791,7 +2785,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[(
|
[(
|
||||||
'code', '=',
|
'code', '=',
|
||||||
integral_tool_item['standard_library_code'])]).id,
|
integral_tool_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'total_length': integral_tool_item['total_length'],
|
'total_length': integral_tool_item['total_length'],
|
||||||
'blade_diameter': integral_tool_item['blade_diameter'],
|
'blade_diameter': integral_tool_item['blade_diameter'],
|
||||||
'blade_length': integral_tool_item['blade_length'],
|
'blade_length': integral_tool_item['blade_length'],
|
||||||
@@ -2814,10 +2809,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
integral_tool.write({
|
integral_tool.write({
|
||||||
'name': integral_tool_item['name'],
|
'name': integral_tool_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[(
|
|
||||||
'code', '=',
|
|
||||||
integral_tool_item['standard_library_code'])]).id,
|
|
||||||
'total_length': integral_tool_item['total_length'],
|
'total_length': integral_tool_item['total_length'],
|
||||||
'blade_diameter': integral_tool_item['blade_diameter'],
|
'blade_diameter': integral_tool_item['blade_diameter'],
|
||||||
'blade_length': integral_tool_item['blade_length'],
|
'blade_length': integral_tool_item['blade_length'],
|
||||||
@@ -2850,7 +2841,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'code': blade_item['code'],
|
'code': blade_item['code'],
|
||||||
'cutting_tool_type': '刀片',
|
'cutting_tool_type': '刀片',
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', blade_item['standard_library_code'])]).id,
|
[('code', '=', blade_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'length': blade_item['length'],
|
'length': blade_item['length'],
|
||||||
'thickness': blade_item['thickness'],
|
'thickness': blade_item['thickness'],
|
||||||
'cutting_blade_length': blade_item['cutting_blade_length'],
|
'cutting_blade_length': blade_item['cutting_blade_length'],
|
||||||
@@ -2879,8 +2871,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
blade.write({
|
blade.write({
|
||||||
'name': blade_item['name'],
|
'name': blade_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', blade_item['standard_library_code'])]).id,
|
|
||||||
'length': blade_item['length'],
|
'length': blade_item['length'],
|
||||||
'thickness': blade_item['thickness'],
|
'thickness': blade_item['thickness'],
|
||||||
'cutting_blade_length': blade_item['cutting_blade_length'],
|
'cutting_blade_length': blade_item['cutting_blade_length'],
|
||||||
@@ -2919,7 +2909,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'code': chuck_item['code'],
|
'code': chuck_item['code'],
|
||||||
'cutting_tool_type': '夹头',
|
'cutting_tool_type': '夹头',
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', chuck_item['standard_library_code'])]).id,
|
[('code', '=', chuck_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'er_size_model': chuck_item['size_model'],
|
'er_size_model': chuck_item['size_model'],
|
||||||
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
||||||
'max_clamping_diameter': chuck_item['clamping_diameter_max'],
|
'max_clamping_diameter': chuck_item['clamping_diameter_max'],
|
||||||
@@ -2937,8 +2928,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
chuck.write({
|
chuck.write({
|
||||||
'name': chuck_item['name'],
|
'name': chuck_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', chuck_item['standard_library_code'])]).id,
|
|
||||||
'er_size_model': chuck_item['size_model'],
|
'er_size_model': chuck_item['size_model'],
|
||||||
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
||||||
'max_clamping_diameter': chuck_item['clamping_diameter_max'],
|
'max_clamping_diameter': chuck_item['clamping_diameter_max'],
|
||||||
@@ -2967,7 +2956,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'code': cutter_arbor_item['code'],
|
'code': cutter_arbor_item['code'],
|
||||||
'cutting_tool_type': '刀杆',
|
'cutting_tool_type': '刀杆',
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', cutter_arbor_item['standard_library_code'])]).id,
|
[('code', '=', cutter_arbor_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'height': cutter_arbor_item['height'],
|
'height': cutter_arbor_item['height'],
|
||||||
'width': cutter_arbor_item['width'],
|
'width': cutter_arbor_item['width'],
|
||||||
'total_length': cutter_arbor_item['total_length'],
|
'total_length': cutter_arbor_item['total_length'],
|
||||||
@@ -2985,7 +2975,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'installing_structure': cutter_arbor_item['mounting_structure'],
|
'installing_structure': cutter_arbor_item['mounting_structure'],
|
||||||
'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else self.env[
|
'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else self.env[
|
||||||
'sf.cutting_tool.standard.library'].search(
|
'sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', cutter_arbor_item['fit_blade_model_code'])]).id,
|
[('code', '=', cutter_arbor_item['fit_blade_model_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
|
'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
|
||||||
'cotter_pin': cutter_arbor_item['fit_pin_model'],
|
'cotter_pin': cutter_arbor_item['fit_pin_model'],
|
||||||
'pressing_plate': cutter_arbor_item['fit_plate_model'],
|
'pressing_plate': cutter_arbor_item['fit_plate_model'],
|
||||||
@@ -2996,8 +2987,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
cutter_arbor.write({
|
cutter_arbor.write({
|
||||||
'name': cutter_arbor_item['name'],
|
'name': cutter_arbor_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', cutter_arbor_item['standard_library_code'])]).id,
|
|
||||||
'height': cutter_arbor_item['height'],
|
'height': cutter_arbor_item['height'],
|
||||||
'width': cutter_arbor_item['width'],
|
'width': cutter_arbor_item['width'],
|
||||||
'total_length': cutter_arbor_item['total_length'],
|
'total_length': cutter_arbor_item['total_length'],
|
||||||
@@ -3017,7 +3006,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
self.env[
|
self.env[
|
||||||
'sf.cutting_tool.standard.library'].search(
|
'sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=',
|
[('code', '=',
|
||||||
cutter_arbor_item['fit_blade_model_code'])]).id,
|
cutter_arbor_item['fit_blade_model_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
|
'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
|
||||||
'cotter_pin': cutter_arbor_item['fit_pin_model'],
|
'cotter_pin': cutter_arbor_item['fit_pin_model'],
|
||||||
'pressing_plate': cutter_arbor_item['fit_plate_model'],
|
'pressing_plate': cutter_arbor_item['fit_plate_model'],
|
||||||
@@ -3038,7 +3028,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'code': cutter_head_item['code'],
|
'code': cutter_head_item['code'],
|
||||||
'cutting_tool_type': '刀盘',
|
'cutting_tool_type': '刀盘',
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', cutter_head_item['standard_library_code'])]).id,
|
[('code', '=', cutter_head_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
||||||
'blade_diameter': cutter_head_item['blade_diameter'],
|
'blade_diameter': cutter_head_item['blade_diameter'],
|
||||||
'cutter_head_diameter': cutter_head_item['cutter_diameter'],
|
'cutter_head_diameter': cutter_head_item['cutter_diameter'],
|
||||||
@@ -3051,7 +3042,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'installing_structure': cutter_head_item['mounting_structure'],
|
'installing_structure': cutter_head_item['mounting_structure'],
|
||||||
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
|
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
|
||||||
'sf.cutting_tool.standard.library'].search(
|
'sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', cutter_head_item['fit_blade_model_code'])]).id,
|
[('code', '=', cutter_head_item['fit_blade_model_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'screw': cutter_head_item['fit_screw_model'],
|
'screw': cutter_head_item['fit_screw_model'],
|
||||||
'spanner': cutter_head_item['fit_wrench_model'],
|
'spanner': cutter_head_item['fit_wrench_model'],
|
||||||
'is_cooling_hole': cutter_head_item['is_cooling_hole'],
|
'is_cooling_hole': cutter_head_item['is_cooling_hole'],
|
||||||
@@ -3061,8 +3053,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
cutter_head.write({
|
cutter_head.write({
|
||||||
'name': cutter_head_item['name'],
|
'name': cutter_head_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', cutter_head_item['standard_library_code'])]).id,
|
|
||||||
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
||||||
'blade_diameter': cutter_head_item['blade_diameter'],
|
'blade_diameter': cutter_head_item['blade_diameter'],
|
||||||
'cutter_head_diameter': cutter_head_item['cutter_diameter'],
|
'cutter_head_diameter': cutter_head_item['cutter_diameter'],
|
||||||
@@ -3076,7 +3066,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
|
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
|
||||||
'sf.cutting_tool.standard.library'].search(
|
'sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=',
|
[('code', '=',
|
||||||
cutter_head_item['fit_blade_model_code'])]).id,
|
cutter_head_item['fit_blade_model_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'screw': cutter_head_item['fit_screw_model'],
|
'screw': cutter_head_item['fit_screw_model'],
|
||||||
'spanner': cutter_head_item['fit_wrench_model'],
|
'spanner': cutter_head_item['fit_wrench_model'],
|
||||||
'is_cooling_hole': cutter_head_item['is_cooling_hole'],
|
'is_cooling_hole': cutter_head_item['is_cooling_hole'],
|
||||||
@@ -3097,7 +3088,8 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
'code': knife_handle_item['code'],
|
'code': knife_handle_item['code'],
|
||||||
'cutting_tool_type': '刀柄',
|
'cutting_tool_type': '刀柄',
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
||||||
[('code', '=', knife_handle_item['standard_library_code'])]).id,
|
[('code', '=', knife_handle_item['standard_library_code'].replace("JKM", result[
|
||||||
|
'factory_short_name']))]).id,
|
||||||
'total_length': knife_handle_item['total_length'],
|
'total_length': knife_handle_item['total_length'],
|
||||||
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
||||||
'flange_shank_length': knife_handle_item['flange_length'],
|
'flange_shank_length': knife_handle_item['flange_length'],
|
||||||
@@ -3122,8 +3114,6 @@ class CuttingToolBasicParameters(models.Model):
|
|||||||
else:
|
else:
|
||||||
knife_handle.write({
|
knife_handle.write({
|
||||||
'name': knife_handle_item['name'],
|
'name': knife_handle_item['name'],
|
||||||
'standard_library_id': self.env['sf.cutting_tool.standard.library'].search(
|
|
||||||
[('code', '=', knife_handle_item['standard_library_code'])]).id,
|
|
||||||
'total_length': knife_handle_item['total_length'],
|
'total_length': knife_handle_item['total_length'],
|
||||||
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
||||||
'flange_shank_length': knife_handle_item['flange_length'],
|
'flange_shank_length': knife_handle_item['flange_length'],
|
||||||
|
|||||||
@@ -14,11 +14,10 @@ class QualityCheck(models.Model):
|
|||||||
('waiting', '等待'),
|
('waiting', '等待'),
|
||||||
('none', '待处理'),
|
('none', '待处理'),
|
||||||
('pass', '通过的'),
|
('pass', '通过的'),
|
||||||
('fail', '失败的'),
|
('fail', '失败的')], string='状态', tracking=True, store=True,
|
||||||
('cancel', '已取消'), ], string='状态', tracking=True, store=True,
|
|
||||||
default='none', copy=False, compute='_compute_quality_state')
|
default='none', copy=False, compute='_compute_quality_state')
|
||||||
|
|
||||||
individuation_page_list = fields.Char('个性化记录', related='workorder_id.individuation_page_list')
|
individuation_page_PTD = fields.Boolean('个性化记录(是否显示后置三元检测[PTD]页签)', related='workorder_id.individuation_page_PTD')
|
||||||
work_state = fields.Selection(related='workorder_id.state', string='工单状态')
|
work_state = fields.Selection(related='workorder_id.state', string='工单状态')
|
||||||
processing_panel = fields.Char(related='workorder_id.processing_panel', string='加工面')
|
processing_panel = fields.Char(related='workorder_id.processing_panel', string='加工面')
|
||||||
|
|
||||||
@@ -40,14 +39,6 @@ class QualityCheck(models.Model):
|
|||||||
operation_id = fields.Many2one('mrp.routing.workcenter', '作业', store=True, compute='_compute_operation_id')
|
operation_id = fields.Many2one('mrp.routing.workcenter', '作业', store=True, compute='_compute_operation_id')
|
||||||
is_inspect = fields.Boolean('需送检', related='point_id.is_inspect')
|
is_inspect = fields.Boolean('需送检', related='point_id.is_inspect')
|
||||||
|
|
||||||
lot_name = fields.Char('批次/序列号 名称', compute='_compute_lot_name', store=True)
|
|
||||||
|
|
||||||
@api.depends('move_line_id', 'move_line_id.lot_name')
|
|
||||||
def _compute_lot_name(self):
|
|
||||||
for qc in self:
|
|
||||||
if qc.move_line_id:
|
|
||||||
qc.lot_name = qc.move_line_id.lot_name
|
|
||||||
|
|
||||||
@api.depends('point_id.operation_id')
|
@api.depends('point_id.operation_id')
|
||||||
def _compute_operation_id(self):
|
def _compute_operation_id(self):
|
||||||
for qc in self:
|
for qc in self:
|
||||||
@@ -57,7 +48,7 @@ class QualityCheck(models.Model):
|
|||||||
@api.depends('point_id.is_inspect')
|
@api.depends('point_id.is_inspect')
|
||||||
def _compute_quality_state(self):
|
def _compute_quality_state(self):
|
||||||
for qc in self:
|
for qc in self:
|
||||||
if qc.point_id.is_inspect and qc.quality_state == 'none' and qc.workorder_id.state != 'to be detected':
|
if qc.point_id.is_inspect and qc.quality_state == 'none':
|
||||||
qc.quality_state = 'waiting'
|
qc.quality_state = 'waiting'
|
||||||
elif not qc.point_id.is_inspect and qc.quality_state == 'waiting':
|
elif not qc.point_id.is_inspect and qc.quality_state == 'waiting':
|
||||||
qc.quality_state = 'none'
|
qc.quality_state = 'none'
|
||||||
@@ -71,9 +62,7 @@ class QualityCheck(models.Model):
|
|||||||
def do_pass(self):
|
def do_pass(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
super().do_pass()
|
super().do_pass()
|
||||||
if self.workorder_id:
|
if self.workorder_id and self.individuation_page_PTD is True:
|
||||||
if self.workorder_id.state in ('pending', 'waiting'):
|
|
||||||
raise ValidationError('工单未就绪!')
|
|
||||||
# 1)将页签“判定结果”的检测结果值同步到【工单_后置三元检测_检测结果】
|
# 1)将页签“判定结果”的检测结果值同步到【工单_后置三元检测_检测结果】
|
||||||
if self.test_results in ['返工', '报废']:
|
if self.test_results in ['返工', '报废']:
|
||||||
raise ValidationError('请重新选择【判定结果】-【检测结果】')
|
raise ValidationError('请重新选择【判定结果】-【检测结果】')
|
||||||
@@ -85,25 +74,12 @@ class QualityCheck(models.Model):
|
|||||||
def do_fail(self):
|
def do_fail(self):
|
||||||
self.ensure_one()
|
self.ensure_one()
|
||||||
super().do_fail()
|
super().do_fail()
|
||||||
if self.workorder_id:
|
if self.workorder_id and self.individuation_page_PTD is True:
|
||||||
if self.workorder_id.state in ('pending', 'waiting'):
|
|
||||||
raise ValidationError('工单未就绪!')
|
|
||||||
# 1)将页签“判定结果”的检测结果值同步到【工单_后置三元检测_检测结果】
|
# 1)将页签“判定结果”的检测结果值同步到【工单_后置三元检测_检测结果】
|
||||||
if not self.test_results:
|
if not self.test_results:
|
||||||
raise ValidationError('请填写【判定结果】里的信息')
|
raise ValidationError('请填写【判定结果】里的信息')
|
||||||
if self.test_results == '合格':
|
if self.test_results == '合格':
|
||||||
raise ValidationError('请重新选择【判定结果】-【检测结果】')
|
raise ValidationError('请重新选择【判定结果】-【检测结果】')
|
||||||
if self.workorder_id.routing_type != 'CNC加工' and 'PTD' not in self.workorder_id.individuation_page_list:
|
|
||||||
self.workorder_id.production_id.write({'detection_result_ids': [(0, 0, {
|
|
||||||
'rework_reason': self.reason,
|
|
||||||
'detailed_reason': self.detailed_reason,
|
|
||||||
'processing_panel': self.workorder_id.processing_panel,
|
|
||||||
'routing_type': self.workorder_id.routing_type,
|
|
||||||
'handle_result': '待处理',
|
|
||||||
'test_results': self.test_results,
|
|
||||||
'test_report': self.workorder_id.detection_report})],
|
|
||||||
'is_scrap': True if self.test_results == '报废' else False
|
|
||||||
})
|
|
||||||
if self.workorder_id.state not in ['done']:
|
if self.workorder_id.state not in ['done']:
|
||||||
self.workorder_id.write(
|
self.workorder_id.write(
|
||||||
{'test_results': self.test_results, 'reason': self.reason, 'detailed_reason': self.detailed_reason})
|
{'test_results': self.test_results, 'reason': self.reason, 'detailed_reason': self.detailed_reason})
|
||||||
@@ -130,3 +106,4 @@ class QualityCheck(models.Model):
|
|||||||
return "零件特采发送成功"
|
return "零件特采发送成功"
|
||||||
else:
|
else:
|
||||||
raise ValidationError("零件特采发送失败")
|
raise ValidationError("零件特采发送失败")
|
||||||
|
|
||||||
|
|||||||
@@ -8,25 +8,23 @@
|
|||||||
<xpath expr="//field[@name='alert_ids']" position="after">
|
<xpath expr="//field[@name='alert_ids']" position="after">
|
||||||
<field name="production_id" invisible="1"/>
|
<field name="production_id" invisible="1"/>
|
||||||
<field name="work_state" invisible="1"/>
|
<field name="work_state" invisible="1"/>
|
||||||
<field name="individuation_page_list" invisible="1"/>
|
<field name="individuation_page_PTD" invisible="1"/>
|
||||||
<field name="production_line_id" attrs="{'invisible': [('production_id', '=', False)]}"/>
|
<field name="production_line_id" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
|
||||||
<field name="equipment_id" attrs="{'invisible': [('production_id', '=', False)]}"/>
|
<field name="equipment_id" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
|
||||||
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
|
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
|
||||||
attrs="{'invisible': ['|',('model_file', '=', False), ('production_id', '=', False)]}"/>
|
attrs="{'invisible': ['|', '|',('model_file', '=', False), ('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='partner_id']" position="after">
|
<xpath expr="//field[@name='partner_id']" position="after">
|
||||||
<field name="processing_panel" attrs="{'invisible': [('production_id', '=', False)]}"/>
|
<field name="processing_panel" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
|
||||||
<!-- <field name="production_id" string="制造订单" readonly="1"-->
|
|
||||||
<!-- attrs="{'invisible': [('production_id', '=', False)]}"/>-->
|
|
||||||
<field name="workorder_id" string="工单号" readonly="1"
|
<field name="workorder_id" string="工单号" readonly="1"
|
||||||
attrs="{'invisible': [('production_id', '=', False)]}"/>
|
attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
|
||||||
<field name="is_inspect" attrs="{'invisible': [('production_id', '=', False)]}"/>
|
<field name="is_inspect" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//page[@name='notes']" position="before">
|
<xpath expr="//page[@name='notes']" position="before">
|
||||||
<page string="检测报告" attrs="{'invisible': [('production_id', '=', False)]}">
|
<page string="检测报告" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}">
|
||||||
<field name="detection_report" string="" widget="pdf_viewer"/>
|
<field name="detection_report" string="" widget="pdf_viewer"/>
|
||||||
</page>
|
</page>
|
||||||
<page string="判定结果" attrs="{'invisible': [('production_id', '=', False)]}">
|
<page string="判定结果" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}">
|
||||||
<group>
|
<group>
|
||||||
<group>
|
<group>
|
||||||
<field name="test_results" attrs="{'readonly': [('quality_state','in', ['pass', 'fail'])]}"/>
|
<field name="test_results" attrs="{'readonly': [('quality_state','in', ['pass', 'fail'])]}"/>
|
||||||
@@ -37,33 +35,25 @@
|
|||||||
</group>
|
</group>
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
<page string="2D图纸" attrs="{'invisible': [('production_id', '=', False)]}">
|
<page string="2D图纸" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}">
|
||||||
<field name="machining_drawings" string="" widget="adaptive_viewer"/>
|
<field name="machining_drawings" string="" widget="adaptive_viewer"/>
|
||||||
</page>
|
</page>
|
||||||
<page string="客户质量标准" attrs="{'invisible': [('production_id', '=', False)]}">
|
<page string="客户质量标准" attrs="{'invisible': ['|',('production_id', '=', False), ('individuation_page_PTD', '=', False)]}">
|
||||||
<field name="quality_standard" string="" widget="adaptive_viewer"/>
|
<field name="quality_standard" string="" widget="adaptive_viewer"/>
|
||||||
</page>
|
</page>
|
||||||
<page string="其他"
|
<page string="其他"
|
||||||
attrs="{'invisible': ['|',('quality_state', 'not in', ['pass', 'fail']), ('production_id', '=', False)]}">
|
attrs="{'invisible': ['|','|', ('quality_state', 'not in', ['pass', 'fail']), ('production_id', '=', False),('individuation_page_PTD', '=', False)]}">
|
||||||
<group>
|
<group>
|
||||||
<field name="write_uid" widget='many2one_avatar_user' string="判定人" readonly="1"/>
|
<field name="write_uid" widget='many2one_avatar_user' string="判定人" readonly="1"/>
|
||||||
<field name="write_date" string="判定时间" readonly="1"/>
|
<field name="write_date" string="判定时间" readonly="1"/>
|
||||||
</group>
|
</group>
|
||||||
</page>
|
</page>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//header//button[@name='do_pass'][1]" position="attributes">
|
|
||||||
<attribute name="string">合格</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//header//button[@name='do_pass'][2]" position="attributes">
|
<xpath expr="//header//button[@name='do_pass'][2]" position="attributes">
|
||||||
<attribute name="attrs">{'invisible': ['|',('quality_state', '!=', 'fail'),('work_state','in', ('done', 'rework'))]}</attribute>
|
<attribute name="attrs">{'invisible': ['|',('quality_state', '!=', 'fail'),('work_state','in', ('done', 'rework'))]}</attribute>
|
||||||
<attribute name="string">合格</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//header//button[@name='do_fail'][1]" position="attributes">
|
|
||||||
<attribute name="string">不合格</attribute>
|
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//header//button[@name='do_fail'][2]" position="attributes">
|
<xpath expr="//header//button[@name='do_fail'][2]" position="attributes">
|
||||||
<attribute name="attrs">{'invisible': ['|',('quality_state', '!=', 'pass'),('work_state','in', ('done', 'rework'))]}</attribute>
|
<attribute name="attrs">{'invisible': ['|',('quality_state', '!=', 'pass'),('work_state','in', ('done', 'rework'))]}</attribute>
|
||||||
<attribute name="string">不合格</attribute>
|
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
@@ -74,7 +64,6 @@
|
|||||||
<field name="inherit_id" ref="quality_control.quality_check_view_tree"/>
|
<field name="inherit_id" ref="quality_control.quality_check_view_tree"/>
|
||||||
<field name="arch" type="xml">
|
<field name="arch" type="xml">
|
||||||
<xpath expr="//tree//field[@name='name']" position="after">
|
<xpath expr="//tree//field[@name='name']" position="after">
|
||||||
<field name="title" string="标准名"/>
|
|
||||||
<field name="operation_id" invisible="1"/>
|
<field name="operation_id" invisible="1"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
@@ -90,15 +79,8 @@
|
|||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='product_id']" position="after">
|
<xpath expr="//field[@name='product_id']" position="after">
|
||||||
<field name="production_id"/>
|
<field name="production_id"/>
|
||||||
|
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
<record id="quality_control.quality_check_action_main" model="ir.actions.act_window">
|
|
||||||
<field name="context">{
|
|
||||||
'is_web_request': True,
|
|
||||||
'search_default_progress': 1,
|
|
||||||
'search_default_passed': 1,
|
|
||||||
'search_default_failed': 1,
|
|
||||||
}</field>
|
|
||||||
</record>
|
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -28,7 +28,6 @@
|
|||||||
'web.assets_backend': [
|
'web.assets_backend': [
|
||||||
'sf_sale/static/js/setTableWidth.js',
|
'sf_sale/static/js/setTableWidth.js',
|
||||||
'sf_sale/static/src/css/purchase_list.css',
|
'sf_sale/static/src/css/purchase_list.css',
|
||||||
'sf_sale/static/lib/*',
|
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
'demo': [
|
'demo': [
|
||||||
|
|||||||
@@ -130,10 +130,7 @@ class ReSaleOrder(models.Model):
|
|||||||
'order_id': self.id,
|
'order_id': self.id,
|
||||||
'product_id': product.id,
|
'product_id': product.id,
|
||||||
'name': '%s/%s/%s/%s/%s/%s' % (
|
'name': '%s/%s/%s/%s/%s/%s' % (
|
||||||
self.format_float(product.model_long),
|
product.model_long, product.model_width, product.model_height, product.model_volume,
|
||||||
self.format_float(product.model_width),
|
|
||||||
self.format_float(product.model_height),
|
|
||||||
self.format_float(product.model_volume),
|
|
||||||
machining_accuracy_name,
|
machining_accuracy_name,
|
||||||
product.materials_id.name),
|
product.materials_id.name),
|
||||||
'price_unit': product.list_price,
|
'price_unit': product.list_price,
|
||||||
@@ -146,20 +143,6 @@ class ReSaleOrder(models.Model):
|
|||||||
}
|
}
|
||||||
return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals)
|
return self.env['sale.order.line'].with_context(skip_procurement=True).create(vals)
|
||||||
|
|
||||||
def format_float(self, value):
|
|
||||||
# 将浮点数转换为字符串
|
|
||||||
value_str = str(value)
|
|
||||||
# 检查小数点的位置
|
|
||||||
if '.' in value_str:
|
|
||||||
# 获取小数部分
|
|
||||||
decimal_part = value_str.split('.')[1]
|
|
||||||
# 判断小数位数是否超过2位
|
|
||||||
if len(decimal_part) > 2:
|
|
||||||
# 超过2位则保留2位小数
|
|
||||||
return "{:.2f}".format(value)
|
|
||||||
# 否则保持原来的位数
|
|
||||||
return float(value_str)
|
|
||||||
|
|
||||||
@api.constrains('order_line')
|
@api.constrains('order_line')
|
||||||
def check_order_line(self):
|
def check_order_line(self):
|
||||||
for item in self:
|
for item in self:
|
||||||
@@ -401,6 +384,12 @@ class RePurchaseOrder(models.Model):
|
|||||||
def button_confirm(self):
|
def button_confirm(self):
|
||||||
result = super(RePurchaseOrder, self).button_confirm()
|
result = super(RePurchaseOrder, self).button_confirm()
|
||||||
for item in self:
|
for item in self:
|
||||||
|
# 确认订单时,自动分配序列号
|
||||||
|
if item.picking_ids:
|
||||||
|
for picking_id in item.picking_ids:
|
||||||
|
if picking_id.move_ids:
|
||||||
|
for move_id in picking_id.move_ids:
|
||||||
|
move_id.put_move_line()
|
||||||
for line in item.order_line:
|
for line in item.order_line:
|
||||||
if line.product_id.categ_type == '表面工艺':
|
if line.product_id.categ_type == '表面工艺':
|
||||||
if item.origin:
|
if item.origin:
|
||||||
@@ -511,10 +500,9 @@ class ResUserToSale(models.Model):
|
|||||||
|
|
||||||
@api.model
|
@api.model
|
||||||
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
|
def _name_search(self, name, args=None, operator='ilike', limit=100, name_get_uid=None):
|
||||||
domain = []
|
|
||||||
if self._context.get('is_sale'):
|
if self._context.get('is_sale'):
|
||||||
if self.env.user.has_group('sf_base.group_sale_director'):
|
if self.env.user.has_group('sf_base.group_sale_director'):
|
||||||
pass
|
domain = []
|
||||||
elif self.env.user.has_group('sf_base.group_sale_salemanager'):
|
elif self.env.user.has_group('sf_base.group_sale_salemanager'):
|
||||||
if self.id != self.env.user.id:
|
if self.id != self.env.user.id:
|
||||||
domain = [('id', '=', self.id)]
|
domain = [('id', '=', self.id)]
|
||||||
@@ -523,7 +511,7 @@ class ResUserToSale(models.Model):
|
|||||||
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
|
return self._search(domain, limit=limit, access_rights_uid=name_get_uid)
|
||||||
elif self._context.get('supplier_rank'):
|
elif self._context.get('supplier_rank'):
|
||||||
if self.env.user.has_group('sf_base.group_purchase_director'):
|
if self.env.user.has_group('sf_base.group_purchase_director'):
|
||||||
pass
|
domain = []
|
||||||
elif self.env.user.has_group('sf_base.group_purchase'):
|
elif self.env.user.has_group('sf_base.group_purchase'):
|
||||||
if self.id != self.env.user.id:
|
if self.id != self.env.user.id:
|
||||||
domain = [('id', '=', self.id)]
|
domain = [('id', '=', self.id)]
|
||||||
|
|||||||
@@ -1,18 +0,0 @@
|
|||||||
/** @odoo-module */
|
|
||||||
|
|
||||||
import { Component } from "@odoo/owl";
|
|
||||||
import { registry } from "@web/core/registry";
|
|
||||||
|
|
||||||
|
|
||||||
export class MergeField extends Component {
|
|
||||||
get mergeValue() {
|
|
||||||
const data = this.props.record.data;
|
|
||||||
|
|
||||||
const v = data?.product_uom_qty
|
|
||||||
const unit = data?.product_uom[1]
|
|
||||||
return `${v} ${unit}`
|
|
||||||
}
|
|
||||||
}
|
|
||||||
MergeField.template = "jikimo_sf.MergeField";
|
|
||||||
|
|
||||||
registry.category("fields").add("merge_field", MergeField);
|
|
||||||
@@ -1,8 +0,0 @@
|
|||||||
<?xml version="1.0" encoding="UTF-8"?>
|
|
||||||
<templates xml:space="preserve">
|
|
||||||
|
|
||||||
<t t-name="jikimo_sf.MergeField" owl="1">
|
|
||||||
<span t-esc="mergeValue"/>
|
|
||||||
</t>
|
|
||||||
|
|
||||||
</templates>
|
|
||||||
@@ -1,11 +1,3 @@
|
|||||||
.purchase_order_list_name {
|
.purchase_order_list_name {
|
||||||
min-width: 62px !important;
|
min-width: 62px !important;
|
||||||
}
|
}
|
||||||
|
|
||||||
.o_list_renderer .o_list_table .o_data_row td.o_data_cell.o_field_cell.o_list_char.section_and_note_text, .section_and_note_text span{
|
|
||||||
white-space: wrap!important;
|
|
||||||
overflow: auto!important;
|
|
||||||
text-overflow: unset!important;
|
|
||||||
word-wrap: break-word;
|
|
||||||
word-break: break-all;
|
|
||||||
}
|
|
||||||
@@ -42,20 +42,20 @@
|
|||||||
<field name="currency_id" position="after">
|
<field name="currency_id" position="after">
|
||||||
<field name="remark" attrs="{'readonly': [('state', 'in', ['purchase'])]}" string="订单备注"/>
|
<field name="remark" attrs="{'readonly': [('state', 'in', ['purchase'])]}" string="订单备注"/>
|
||||||
</field>
|
</field>
|
||||||
<xpath expr="//form/header/button[@name='action_rfq_send'][1]" position="attributes">
|
<xpath expr="//form/header/button[@name='action_rfq_send'][1]" position="replace">
|
||||||
<attribute name="invisible">1</attribute>
|
<button name="action_rfq_send" states="draft" string="通过Email发送采购单" type="object"
|
||||||
|
context="{'send_rfq':True}" class="oe_highlight" data-hotkey="g"
|
||||||
|
groups="sf_base.group_purchase,sf_base.group_purchase_director"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//form/header/button[@name='action_rfq_send'][2]" position="attributes">
|
<xpath expr="//form/header/button[@name='action_rfq_send'][2]" position="replace">
|
||||||
<attribute name="invisible">1</attribute>
|
<button name="action_rfq_send" states="sent" string="通过Email重新发送采购单" type="object"
|
||||||
|
context="{'send_rfq':True}" data-hotkey="g"
|
||||||
|
groups="sf_base.group_purchase,sf_base.group_purchase_director"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//form/header/button[@name='action_rfq_send'][3]" position="attributes">
|
<xpath expr="//form/header/button[@name='action_rfq_send'][3]" position="replace">
|
||||||
<attribute name="invisible">1</attribute>
|
<button name="action_rfq_send" states="purchase" string="通过Email发送订单" type="object"
|
||||||
</xpath>
|
context="{'send_rfq':False}" data-hotkey="g"
|
||||||
<xpath expr="//form/header/button[@name='print_quotation'][1]" position="attributes">
|
groups="sf_base.group_purchase,sf_base.group_purchase_director"/>
|
||||||
<attribute name="invisible">1</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//form/header/button[@name='print_quotation'][2]" position="attributes">
|
|
||||||
<attribute name="invisible">1</attribute>
|
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<!-- <xpath expr="//form/header/button[@name='print_quotation[1]']" position="attributes">-->
|
<!-- <xpath expr="//form/header/button[@name='print_quotation[1]']" position="attributes">-->
|
||||||
@@ -139,7 +139,7 @@
|
|||||||
</field>
|
</field>
|
||||||
<xpath expr="//field[@name='date_order']" position="after">
|
<xpath expr="//field[@name='date_order']" position="after">
|
||||||
<field name="payment_term_id" attrs="{'readonly': ['|', ('invoice_status','=', 'invoiced'), ('state', '=', 'done')]}" options="{'no_create': True}"/>
|
<field name="payment_term_id" attrs="{'readonly': ['|', ('invoice_status','=', 'invoiced'), ('state', '=', 'done')]}" options="{'no_create': True}"/>
|
||||||
<!-- <field name="contract_summary"/>-->
|
<field name="contract_summary"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<field name="partner_ref" position="attributes">
|
<field name="partner_ref" position="attributes">
|
||||||
<attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
|
<attribute name="attrs">{'readonly': [('state', 'in', ['purchase'])]}
|
||||||
@@ -353,9 +353,5 @@
|
|||||||
</field>
|
</field>
|
||||||
<field name="view_mode">tree,kanban,form,activity</field>
|
<field name="view_mode">tree,kanban,form,activity</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="purchase.purchase_rfq" model="ir.actions.act_window">
|
|
||||||
<field name="context">{'quotation_only': True,"search_default_draft":1}</field>
|
|
||||||
</record>
|
|
||||||
</data>
|
</data>
|
||||||
</odoo>
|
</odoo>
|
||||||
@@ -102,7 +102,7 @@
|
|||||||
</field>
|
</field>
|
||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="before">
|
<xpath expr="//field[@name='order_line']/tree/field[@name='name']" position="before">
|
||||||
<field name="model_glb_file" widget="Viewer3D" optional="show"
|
<field name="model_glb_file" widget="Viewer3D" optional="show"
|
||||||
string="模型文件" attrs="{'readonly': [('state', 'in', ['draft'])], 'isInList': True}"/>
|
string="模型文件" attrs="{'readonly': [('state', 'in', ['draft'])]}"/>
|
||||||
<field name="part_name" optional="hide"/>
|
<field name="part_name" optional="hide"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='price_subtotal']" position="after">
|
<xpath expr="//field[@name='order_line']/tree/field[@name='price_subtotal']" position="after">
|
||||||
@@ -112,7 +112,6 @@
|
|||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='product_template_id']" position="attributes">
|
<xpath expr="//field[@name='order_line']/tree/field[@name='product_template_id']" position="attributes">
|
||||||
<attribute name="options">{'no_create': True}</attribute>
|
<attribute name="options">{'no_create': True}</attribute>
|
||||||
<attribute name="context">{'is_sale_order_line': True }</attribute>
|
<attribute name="context">{'is_sale_order_line': True }</attribute>
|
||||||
<attribute name="class">section_and_note_text</attribute>
|
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='order_line']" position="attributes">
|
<xpath expr="//field[@name='order_line']" position="attributes">
|
||||||
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
|
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
|
||||||
@@ -123,16 +122,6 @@
|
|||||||
<field name="manual_quotation" readonly="1"/>
|
<field name="manual_quotation" readonly="1"/>
|
||||||
<field name="is_incoming_material" readonly="1"/>
|
<field name="is_incoming_material" readonly="1"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
|
|
||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='product_uom_qty']" position="replace">
|
|
||||||
<field name="product_uom_qty" string="数量" widget="merge_field" optional="show" />
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='product_uom'][2]" position="attributes">
|
|
||||||
<attribute name="optional">hide</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//field[@name='order_line']/tree/field[@name='product_uom']" position="attributes">
|
|
||||||
<attribute name="optional">hide</attribute>
|
|
||||||
</xpath>
|
|
||||||
<field name="user_id" position="attributes">
|
<field name="user_id" position="attributes">
|
||||||
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
|
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
|
||||||
</field>
|
</field>
|
||||||
@@ -239,18 +228,6 @@
|
|||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|
||||||
<record id="view_order_form_inherit_sale_stock_qty_sf" model="ir.ui.view">
|
|
||||||
<field name="name">sale.order.line.tree.sale.stock.qty.sf</field>
|
|
||||||
<field name="inherit_id" ref="sale_stock.view_order_form_inherit_sale_stock_qty"/>
|
|
||||||
<field name="model">sale.order</field>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<xpath expr="//page/field[@name='order_line']/form/group/group/div[@name='ordered_qty']/widget[@name='qty_at_date_widget']" position="replace">
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//page/field[@name='order_line']/tree/widget[@name='qty_at_date_widget']" position="replace">
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="view_quotation_with_onboarding_tree_inherit_sf" model="ir.ui.view">
|
<record id="view_quotation_with_onboarding_tree_inherit_sf" model="ir.ui.view">
|
||||||
<field name="name">sale.order.quotation.tree.inherit.sf</field>
|
<field name="name">sale.order.quotation.tree.inherit.sf</field>
|
||||||
<field name="model">sale.order</field>
|
<field name="model">sale.order</field>
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ class StockPicking(models.Model):
|
|||||||
@api.depends('name')
|
@api.depends('name')
|
||||||
def _compute_pro_purchase_count(self):
|
def _compute_pro_purchase_count(self):
|
||||||
for sp in self:
|
for sp in self:
|
||||||
if sp.name and sp.name != '/':
|
if sp:
|
||||||
po_ids = self.env['purchase.order'].sudo().search([
|
po_ids = self.env['purchase.order'].sudo().search([
|
||||||
('origin', 'like', sp.name), ('purchase_type', '=', 'standard')])
|
('origin', 'like', sp.name), ('purchase_type', '=', 'standard')])
|
||||||
if po_ids:
|
if po_ids:
|
||||||
@@ -52,7 +52,7 @@ class StockPicking(models.Model):
|
|||||||
@api.depends('name')
|
@api.depends('name')
|
||||||
def _compute_pro_out_purchase_count(self):
|
def _compute_pro_out_purchase_count(self):
|
||||||
for sp in self:
|
for sp in self:
|
||||||
if sp.name and sp.name != '/':
|
if sp:
|
||||||
po_ids = self.env['purchase.order'].sudo().search([
|
po_ids = self.env['purchase.order'].sudo().search([
|
||||||
('origin', 'like', sp.name), ('purchase_type', '=', 'outsourcing')])
|
('origin', 'like', sp.name), ('purchase_type', '=', 'outsourcing')])
|
||||||
if po_ids:
|
if po_ids:
|
||||||
|
|||||||
@@ -935,28 +935,11 @@ class SfStockPicking(models.Model):
|
|||||||
_inherit = 'stock.picking'
|
_inherit = 'stock.picking'
|
||||||
|
|
||||||
check_in = fields.Char(string='查询是否为入库单', compute='_check_is_in')
|
check_in = fields.Char(string='查询是否为入库单', compute='_check_is_in')
|
||||||
product_uom_qty_sp = fields.Float('需求数量', compute='_compute_product_uom_qty_sp', store=True)
|
|
||||||
|
|
||||||
@api.depends('move_ids_without_package', 'move_ids_without_package.product_uom_qty')
|
|
||||||
def _compute_product_uom_qty_sp(self):
|
|
||||||
for sp in self:
|
|
||||||
if sp.move_ids_without_package:
|
|
||||||
sp.product_uom_qty_sp = 0
|
|
||||||
for move_id in sp.move_ids_without_package:
|
|
||||||
sp.product_uom_qty_sp += move_id.product_uom_qty
|
|
||||||
else:
|
|
||||||
sp.product_uom_qty_sp = 0
|
|
||||||
|
|
||||||
def batch_stock_move(self):
|
def batch_stock_move(self):
|
||||||
"""
|
"""
|
||||||
批量调拨,非就绪状态的会被忽略,完成后有通知提示
|
批量调拨,非就绪状态的会被忽略,完成后有通知提示
|
||||||
"""
|
"""
|
||||||
# 对所以调拨单的质检单进行是否完成校验
|
|
||||||
sp_ids = [sp.id for sp in self]
|
|
||||||
qc_ids = self.env['quality.check'].sudo().search(
|
|
||||||
[('picking_id', 'in', sp_ids), ('quality_state', 'in', ['waiting', 'none'])])
|
|
||||||
if qc_ids:
|
|
||||||
raise ValidationError(f'单据{list(set(qc.picking_id.name for qc in qc_ids))}未完成质量检查,完成后再试。')
|
|
||||||
for record in self:
|
for record in self:
|
||||||
if record.state != 'assigned':
|
if record.state != 'assigned':
|
||||||
continue
|
continue
|
||||||
@@ -1140,7 +1123,7 @@ class SfPickingType(models.Model):
|
|||||||
action = super(SfPickingType, self)._get_action(action_xmlid)
|
action = super(SfPickingType, self)._get_action(action_xmlid)
|
||||||
if not self.env.user.has_group('base.group_system'):
|
if not self.env.user.has_group('base.group_system'):
|
||||||
action['context']['create'] = False
|
action['context']['create'] = False
|
||||||
if self.sequence_code in ['INT', 'PC']:
|
if self.sequence_code in ['DL', 'INT', 'PC']:
|
||||||
action['context']['search_default_retrospect'] = 1
|
action['context']['search_default_retrospect'] = 1
|
||||||
return action
|
return action
|
||||||
|
|
||||||
|
|||||||
@@ -79,9 +79,6 @@
|
|||||||
<xpath expr="//field[@name='lot_name']" position="after">
|
<xpath expr="//field[@name='lot_name']" position="after">
|
||||||
<field name="rfid"/>
|
<field name="rfid"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//field[@name='lot_name']" position="attributes">
|
|
||||||
<attribute name="readonly">True</attribute>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//field[@name='product_uom_id']" position="after">
|
<xpath expr="//field[@name='product_uom_id']" position="after">
|
||||||
<field name="lot_qr_code" widget="image"/>
|
<field name="lot_qr_code" widget="image"/>
|
||||||
<button name="print_single_method" string="打印编码" type="object" class="oe_highlight"/>
|
<button name="print_single_method" string="打印编码" type="object" class="oe_highlight"/>
|
||||||
@@ -157,24 +154,7 @@
|
|||||||
groups="sf_base.group_sf_stock_user"/>
|
groups="sf_base.group_sf_stock_user"/>
|
||||||
</xpath>
|
</xpath>
|
||||||
<xpath expr="//header" position="inside">
|
<xpath expr="//header" position="inside">
|
||||||
<button name="batch_stock_move" type='object' string="批量调拨"
|
<button name="batch_stock_move" type='object' string="批量调拨"/>
|
||||||
invisible="context.get('stock_type','') in ('发料出库')"
|
|
||||||
/>
|
|
||||||
</xpath>
|
|
||||||
<xpath expr="//field[@name='location_dest_id']" position="after">
|
|
||||||
<field name="product_uom_qty_sp"/>
|
|
||||||
</xpath>
|
|
||||||
</field>
|
|
||||||
</record>
|
|
||||||
|
|
||||||
<record id="view_stock_picking_type_kanban_inherit" model="ir.ui.view">
|
|
||||||
<field name="name">stock.picking.type.kanban.view.inherit</field>
|
|
||||||
<field name="model">stock.picking.type</field>
|
|
||||||
<field name="inherit_id" ref="stock.stock_picking_type_kanban"/>
|
|
||||||
<field name="arch" type="xml">
|
|
||||||
<!-- 找到按钮所在位置并添加 context -->
|
|
||||||
<xpath expr="//button[@name='get_action_picking_tree_ready']" position="attributes">
|
|
||||||
<attribute name="context">{'stock_type': name}</attribute>
|
|
||||||
</xpath>
|
</xpath>
|
||||||
</field>
|
</field>
|
||||||
</record>
|
</record>
|
||||||
|
|||||||
@@ -1,3 +0,0 @@
|
|||||||
.model-viewer-in-list {
|
|
||||||
width: 150px;
|
|
||||||
}
|
|
||||||
@@ -63,16 +63,11 @@ StepViewer.supportedTypes = ["binary"];
|
|||||||
StepViewer.props = {
|
StepViewer.props = {
|
||||||
...standardFieldProps,
|
...standardFieldProps,
|
||||||
url: {type: String, optional: true},
|
url: {type: String, optional: true},
|
||||||
isInList: {type: Boolean, optional: true},
|
|
||||||
};
|
};
|
||||||
|
|
||||||
StepViewer.extractProps = ({attrs}) => {
|
StepViewer.extractProps = ({attrs}) => {
|
||||||
const modifiedAttrs = JSON.parse(attrs.modifiers || '{}');
|
|
||||||
|
|
||||||
|
|
||||||
return {
|
return {
|
||||||
url: attrs.options.url,
|
url: attrs.options.url,
|
||||||
isInList: modifiedAttrs.isInList,
|
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -5,7 +5,6 @@
|
|||||||
|
|
||||||
<t t-if="props.value">
|
<t t-if="props.value">
|
||||||
<model-viewer
|
<model-viewer
|
||||||
t-att-class="props.isInList ? 'model-viewer-in-list' : ''"
|
|
||||||
t-att-src='props.url'
|
t-att-src='props.url'
|
||||||
name="3D model"
|
name="3D model"
|
||||||
alt="3D model"
|
alt="3D model"
|
||||||
|
|||||||
Reference in New Issue
Block a user