Merge branch 'develop' of https://e.coding.net/jikimo-hn/jikimo_sfs/jikimo_sf into feature/修改机床参数bug
This commit is contained in:
@@ -4,6 +4,7 @@ import {patch} from '@web/core/utils/patch';
|
||||
// import { Dialog } from "@web/core/dialog/dialog";
|
||||
import {_t} from "@web/core/l10n/translation";
|
||||
import {FormStatusIndicator} from "@web/views/form/form_status_indicator/form_status_indicator";
|
||||
import {ListRenderer} from "@web/views/list/list_renderer";
|
||||
|
||||
import {Field} from "@web/views/fields/field";
|
||||
|
||||
@@ -42,7 +43,14 @@ const filedRequiredList = {
|
||||
// 制造大模块
|
||||
'production_line_id': { multiple: false, noLabel: false },
|
||||
'date_approve': { multiple: false, noLabel: false },
|
||||
'date_planned_start': { multiple: false, noLabel: false },
|
||||
'date_planned_finished': { multiple: false, noLabel: false },
|
||||
}
|
||||
const tableRequiredList = [
|
||||
'product_template_id', 'product_uom_qty', 'price_unit','product_id','product_qty',
|
||||
'name', 'fault_type', 'maintenance_standards', 'Period'
|
||||
]
|
||||
|
||||
patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
|
||||
// 你可以重写或者添加一些方法和属性
|
||||
async _onDiscardChanges() {
|
||||
@@ -83,12 +91,8 @@ patch(FormStatusIndicator.prototype, 'jikimo_frontend.FormStatusIndicator', {
|
||||
);
|
||||
patch(Field.prototype, 'jikimo_frontend.Field', {
|
||||
setup() {
|
||||
this.FieldComponent = this.props.fieldInfo.FieldComponent;
|
||||
if (!this.FieldComponent) {
|
||||
const fieldType = this.props.record.fields[this.props.name].type;
|
||||
this.FieldComponent = getFieldClassFromRegistry(fieldType, this.props.type);
|
||||
}
|
||||
owl.onMounted(this.setRequired);
|
||||
return this._super(...arguments);
|
||||
},
|
||||
setRequired() {
|
||||
const id = this.props.id
|
||||
@@ -112,7 +116,39 @@ patch(Field.prototype, 'jikimo_frontend.Field', {
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
patch(ListRenderer.prototype, 'jikimo_frontend.ListRenderer', {
|
||||
setup(){
|
||||
owl.onMounted(() => {
|
||||
this.activeElement = this.uiService.activeElement;
|
||||
this.setRequired()
|
||||
})
|
||||
return this._super(...arguments);
|
||||
},
|
||||
setRequired() {
|
||||
this.allColumns.forEach(_ => {
|
||||
if( tableRequiredList.indexOf(_.name) >= 0 ) {
|
||||
const dom = $(`th[data-name=${_.name}]`)
|
||||
dom.addClass('addRequired')
|
||||
}
|
||||
})
|
||||
try {
|
||||
const dom = this.tableRef.el
|
||||
if(dom ) {
|
||||
const tfoot = $(dom).children('tfoot')
|
||||
const tbooy = $(dom).children('tbody')
|
||||
if(tfoot.length) {
|
||||
const tfoot_tr = tfoot.children().eq(0)
|
||||
const tbody_tr = tbooy.children().eq(0)
|
||||
if(tfoot_tr.children().length < tbody_tr.children().length) {
|
||||
tfoot_tr.prepend('<td class="prepend">')
|
||||
}
|
||||
}
|
||||
}
|
||||
} catch (e) {
|
||||
console.log(e)
|
||||
}
|
||||
}
|
||||
})
|
||||
|
||||
$(function () {
|
||||
document.addEventListener('click', function () {
|
||||
@@ -162,45 +198,13 @@ $(function () {
|
||||
}, 500)
|
||||
}
|
||||
|
||||
function setRequired(dom = {label: [], table: []}) {
|
||||
let domTimer = null
|
||||
let timer_count = 0
|
||||
clearInterval(domTimer)
|
||||
domTimer = setInterval(() => {
|
||||
timer_count++
|
||||
const lint = $('.o_form_view_container')
|
||||
if (lint.length) {
|
||||
clearInterval(domTimer)
|
||||
const { table} = dom
|
||||
|
||||
if (table.length) {
|
||||
table.forEach(_ => {
|
||||
const th = $(`th[data-name=${_}]`)
|
||||
const t = th.find('span').eq(0).text().replace('*','')
|
||||
th.find('span').eq(0).html('<i style="color: red">*</i>' + t)
|
||||
|
||||
})
|
||||
|
||||
}
|
||||
}
|
||||
if (timer_count == 20) {
|
||||
clearInterval(domTimer)
|
||||
}
|
||||
}, 500)
|
||||
}
|
||||
|
||||
var currentUrl = location.href
|
||||
const customRequiredDom = {
|
||||
table: ['product_template_id', 'product_uom_qty', 'price_unit','product_id','product_qty', 'name', 'fault_type', 'maintenance_standards', 'Period']
|
||||
}
|
||||
const listenerUrl = setInterval(() => {
|
||||
const isChange = currentUrl != location.href
|
||||
if (isChange) {
|
||||
currentUrl = location.href
|
||||
customRequired()
|
||||
setRequired(customRequiredDom)
|
||||
}
|
||||
}, 500)
|
||||
customRequired()
|
||||
setRequired(customRequiredDom)
|
||||
})
|
||||
|
||||
@@ -3,6 +3,13 @@
|
||||
import { registry } from "@web/core/registry";
|
||||
import { url } from "@web/core/utils/urls";
|
||||
import { ImageField, imageCacheKey } from '@web/views/fields/image/image_field';
|
||||
import { isBinarySize } from "@web/core/utils/binary";
|
||||
export const fileTypeMagicWordMap = {
|
||||
"/": "jpg",
|
||||
R: "gif",
|
||||
i: "png",
|
||||
P: "svg+xml",
|
||||
};
|
||||
|
||||
const placeholder = "/web/static/img/placeholder.png";
|
||||
|
||||
@@ -15,7 +22,7 @@ export class CustomImageField extends ImageField {
|
||||
getUrl(previewFieldName) {
|
||||
console.log('8888888888886666666666666666666')
|
||||
if (this.state.isValid && this.props.value) {
|
||||
if (1) {
|
||||
if (isBinarySize(this.props.value) || this.props.value.length < 50) {
|
||||
if (!this.rawCacheKey) {
|
||||
this.rawCacheKey = this.props.record.data.__last_update;
|
||||
}
|
||||
|
||||
@@ -467,3 +467,28 @@ div:has(.o_required_modifier) > label::before {
|
||||
background: #71639e;
|
||||
color: #fff
|
||||
}
|
||||
|
||||
// 修改时间输入框宽度
|
||||
.o_datepicker_input.o_input.datetimepicker-input {
|
||||
width: 200px;
|
||||
}
|
||||
|
||||
|
||||
.o_form_view .o_form_editable .o_row > .o_field_widget, .o_form_view .o_form_editable .o_row > .o_field_widget.o_field_float_time {
|
||||
width: auto !important;
|
||||
flex: unset;
|
||||
}
|
||||
.addRequired {
|
||||
padding-left: calc(0.3rem + 2px)!important;
|
||||
}
|
||||
.addRequired:before {
|
||||
content: '*';
|
||||
color: red;
|
||||
position: absolute;
|
||||
left: 0;
|
||||
top: 50%;
|
||||
transform: translateY(-50%);
|
||||
}
|
||||
.o_list_renderer .o_list_table tfoot .o_list_number {
|
||||
text-align: left;
|
||||
}
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from datetime import date
|
||||
from odoo import fields, models, api
|
||||
from odoo.exceptions import UserError
|
||||
|
||||
|
||||
class CuttingToolMaterial(models.Model):
|
||||
@@ -308,3 +309,41 @@ class ToolGroups(models.Model):
|
||||
# records = super(ToolGroups, self).create(vals_list)
|
||||
# self._register_tool_groups(records)
|
||||
# return records
|
||||
|
||||
|
||||
class ToolInventory(models.Model):
|
||||
_name = 'sf.tool.inventory'
|
||||
_description = '功能刀具清单'
|
||||
|
||||
name = fields.Char('功能刀具名称', required=True)
|
||||
type = fields.Char('类型')
|
||||
functional_cutting_tool_model_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型')
|
||||
prefix = fields.Char('前缀')
|
||||
postfix = fields.Char('后缀')
|
||||
diameter = fields.Float('直径(mm)')
|
||||
angle = fields.Float('R角(mm)')
|
||||
tool_length = fields.Float('刀具总长(mm)')
|
||||
blade_length = fields.Float('避空长/刃长(mm)')
|
||||
knife_head_name = fields.Char('刀头名称')
|
||||
cutter_number = fields.Char('刀号')
|
||||
blade_number = fields.Integer('刃数(个)')
|
||||
extension = fields.Float('伸出长度(mm)')
|
||||
work_material = fields.Selection([('钢', '钢'), ('铝', '铝')], string='加工材料')
|
||||
life_span = fields.Float('寿命(h)')
|
||||
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', string='刀具组')
|
||||
|
||||
active = fields.Boolean('已归档', default=True)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
# 名称重复校验
|
||||
name_list = []
|
||||
for val in vals_list:
|
||||
tool_inventory = self.search([('name', '=', val['name'])])
|
||||
if tool_inventory:
|
||||
name_list.append(val['name'])
|
||||
if name_list:
|
||||
raise UserError("功能刀具名称%s已存在,请重新输入" % name_list)
|
||||
records = super(ToolInventory, self).create(vals_list)
|
||||
return records
|
||||
|
||||
@@ -65,7 +65,7 @@
|
||||
<record id="group_plan_dispatch" model="res.groups">
|
||||
<field name="name">计划调度岗</field>
|
||||
<field name="category_id" ref="module_category_plan"/>
|
||||
<field name="implied_ids" eval="[(4, ref('base.group_user'))]"/>
|
||||
<!-- <field name="implied_ids" eval="[(4, ref('base.group_user'))]"/> -->
|
||||
</record>
|
||||
|
||||
<record id="group_plan_director" model="res.groups">
|
||||
|
||||
@@ -9,16 +9,25 @@ access_sf_machine_brand_tags,sf_machine_brand_tags,model_sf_machine_brand_tags,b
|
||||
access_sf_machine_brand_tags_admin,sf_machine_brand_tags_admin,model_sf_machine_brand_tags,base.group_system,1,1,1,0
|
||||
access_sf_machine_control_system,sf_machine_control_system,model_sf_machine_control_system,base.group_user,1,1,1,0
|
||||
access_sf_machine_control_system_admin,sf_machine_control_system_admin,model_sf_machine_control_system,base.group_system,1,1,1,0
|
||||
access_sf_production_process_group_sale_director,sf_production_process_group_sale_director,model_sf_production_process,sf_base.group_sale_director,1,0,0,0
|
||||
access_sf_production_process_group_sale_salemanager,sf_production_process_group_sale_salemanager,model_sf_production_process,sf_base.group_sale_salemanager,1,0,0,0
|
||||
|
||||
access_sf_production_process,sf_production_process,model_sf_production_process,base.group_user,1,1,1,0
|
||||
access_sf_production_process_admin,sf_production_process_admin,model_sf_production_process,base.group_system,1,1,1,0
|
||||
access_sf_production_materials,sf_production_materials,model_sf_production_materials,base.group_user,1,1,1,0
|
||||
access_sf_production_materials_group_sale_director,sf_production_materials_group_sale_director,model_sf_production_materials,sf_base.group_sale_director,1,0,0,0
|
||||
access_sf_production_materials_group_sale_salemanager,sf_production_materials_group_sale_salemanager,model_sf_production_materials,sf_base.group_sale_salemanager,1,0,0,0
|
||||
|
||||
access_sf_production_materials_admin,sf_production_materials_admin,model_sf_production_materials,base.group_system,1,1,1,0
|
||||
access_sf_materials_model,sf_materials_model,model_sf_materials_model,base.group_user,1,1,1,0
|
||||
access_sf_materials_model_admin,sf_materials_model_admin,model_sf_materials_model,base.group_system,1,1,1,0
|
||||
access_sf_supplier_sort,sf_supplier_sort,model_sf_supplier_sort,base.group_user,1,1,1,0
|
||||
access_sf_supplier_sort_admin,sf_supplier_sort_admin,model_sf_supplier_sort,base.group_system,1,1,1,0
|
||||
access_sf_production_process_parameter,sf_production_process_parameter,model_sf_production_process_parameter,base.group_user,1,1,1,0
|
||||
access_sf_production_process_parameter_group_sale_director,sf_production_process_parameter_group_sale_director,model_sf_production_process_parameter,sf_base.group_sale_director,1,0,0,0
|
||||
access_sf_production_process_parameter_group_sale_salemanager,sf_production_process_parameter_group_sale_salemanager,model_sf_production_process_parameter,sf_base.group_sale_salemanager,1,0,0,0
|
||||
|
||||
|
||||
access_sf_production_process_parameter_group_plan_director,sf_production_process_parameter_group_plan_director,model_sf_production_process_parameter,sf_base.group_plan_director,1,0,0,0
|
||||
access_sf_production_process_parameter_group_purchase_director,sf_production_process_parameter_group_purchase_director,model_sf_production_process_parameter,sf_base.group_purchase_director,1,0,0,0
|
||||
access_sf_production_process_parameter_group_sale_director,sf_production_process_parameter_group_sale_director,model_sf_production_process_parameter,sf_base.group_sale_director,1,0,0,0
|
||||
@@ -101,6 +110,10 @@ access_sf_production_materials_group_plan_director,sf_production_materials_group
|
||||
access_sf_production_materials_group_purchase_director,sf_production_materials_group_purchase_director,model_sf_production_materials,sf_base.group_purchase_director,1,1,0,0
|
||||
access_sf_production_materials_group_sale_director,sf_production_materials_group_sale_director,model_sf_production_materials,sf_base.group_sale_director,1,1,0,0
|
||||
access_sf_materials_model,sf_materials_model,model_sf_materials_model,sf_base.group_sf_mrp_user,1,0,0,0
|
||||
access_sf_materials_model_group_sale_salemanager,sf_materials_model_group_sale_salemanager,model_sf_materials_model,sf_base.group_sale_salemanager,1,0,0,0
|
||||
access_sf_materials_model_group_sale_director,sf_materials_model_group_sale_director,model_sf_materials_model,sf_base.group_sale_director,1,0,0,0
|
||||
|
||||
|
||||
access_sf_materials_model_group_plan_director,sf_materials_model_group_plan_director,model_sf_materials_model,sf_base.group_plan_director,1,0,0,0
|
||||
access_sf_materials_model_group_purchase_director,sf_materials_model_group_purchase_director,model_sf_materials_model,sf_base.group_purchase_director,1,0,0,0
|
||||
access_sf_materials_model_group_sale_director,sf_materials_model_group_sale_director,model_sf_materials_model,sf_base.group_sale_director,1,0,0,0
|
||||
@@ -145,6 +158,7 @@ access_purchase_order_group_purchase,access_purchase_order_group_purchase,purcha
|
||||
access_purchase_order_line_group_purchase,access_purchase_order_line_group_purchase,purchase.model_purchase_order_line,sf_base.group_purchase,1,1,1,0
|
||||
access_spindle_taper_type,spindle_taper_type,model_spindle_taper_type,base.group_user,1,1,1,1
|
||||
access_sf_tool_groups_group_plan_dispatch,sf_tool_groups,model_sf_tool_groups,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_sf_tool_groups_group_plan_director,sf_tool_groups,model_sf_tool_groups,sf_base.group_plan_director,1,1,1,0
|
||||
access_sf_tool_groups_group_sf_tool_user,sf_tool_groups,model_sf_tool_groups,sf_base.group_sf_tool_user,1,1,1,1
|
||||
access_purchase_order,purchase.order,purchase.model_purchase_order,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_res_partner,res.partner,base.model_res_partner,sf_base.group_plan_dispatch,1,0,0,0
|
||||
@@ -192,3 +206,24 @@ access_sf_machine_brand_tags_group_purchase_director,sf_machine_brand_tags_group
|
||||
|
||||
access_printer,printer,model_printer,base.group_user,1,1,1,1
|
||||
access_printer_configuration,printer.configuration,model_printer_configuration,base.group_user,1,1,1,1
|
||||
|
||||
access_group_sf_mrp_user,sf_tool_inventory,model_sf_tool_inventory,base.group_user,1,1,1,0
|
||||
access_group_sf_mrp_user_admin,sf_tool_inventory_admin,model_sf_tool_inventory,base.group_system,1,1,1,0
|
||||
access_group_sf_mrp_user_group_purchase_director,sf_tool_inventory_group_purchase_director,model_sf_tool_inventory,sf_base.group_purchase_director,1,0,1,0
|
||||
access_group_sf_mrp_user_group_sale_director,sf_tool_inventory_group_sale_director,model_sf_tool_inventory,sf_base.group_sale_director,1,0,1,0
|
||||
access_sf_cutting_tool_material_group_plan_director,sf_tool_inventory_group_plan_director,model_sf_tool_inventory,sf_base.group_plan_director,1,0,1,0
|
||||
access_group_sf_mrp_user_group_sf_mrp_user,sf_tool_inventory_group_sf_mrp_user,model_sf_tool_inventory,sf_base.group_sf_mrp_user,1,1,0,0
|
||||
|
||||
|
||||
access_sf_fixture_material_group_purchase_director,sf_fixture_material_group_purchase_director,model_sf_fixture_material,sf_base.group_purchase_director,1,0,0,0
|
||||
access_sf_multi_mounting_type_group_purchase_director,sf_multi_mounting_type_group_purchase_director,model_sf_multi_mounting_type,sf_base.group_purchase_director,1,0,0,0
|
||||
access_sf_fixture_model_group_purchase_director,sf_fixture_model_group_purchase_director,model_sf_fixture_model,sf_base.group_purchase_director,1,0,0,0
|
||||
access_sf_fixture_materials_basic_parameters_group_purchase_director,sf_fixture_materials_basic_parameters_group_purchase_director,model_sf_fixture_materials_basic_parameters,sf_base.group_purchase_director,1,0,0,0
|
||||
access_sf_machine_tool_type_group_purchase_director,sf_machine_tool_type_group_purchase_director,model_sf_machine_tool_type,sf_base.group_purchase_director,1,0,0,0
|
||||
|
||||
access_sf_fixture_material_group_sale_director,sf_fixture_material_group_sale_director,model_sf_fixture_material,sf_base.group_sale_director,1,0,0,0
|
||||
access_sf_multi_mounting_type_group_sale_director,sf_multi_mounting_type_group_sale_director,model_sf_multi_mounting_type,sf_base.group_sale_director,1,0,0,0
|
||||
access_sf_fixture_model_group_sale_director,sf_fixture_model_group_sale_director,model_sf_fixture_model,sf_base.group_sale_director,1,0,0,0
|
||||
access_sf_fixture_materials_basic_parameters_group_sale_director,sf_fixture_materials_basic_parameters_group_sale_director,model_sf_fixture_materials_basic_parameters,sf_base.group_sale_director,1,0,0,0
|
||||
access_sf_machine_tool_type_group_sale_director,sf_machine_tool_type_group_sale_director,model_sf_machine_tool_type,sf_base.group_sale_director,1,0,0,0
|
||||
|
||||
|
||||
|
@@ -189,3 +189,6 @@ td.o_required_modifier {
|
||||
flex-direction: row !important;
|
||||
}
|
||||
|
||||
.supplier_ids_set_css thead th[data-name=partner_id]{
|
||||
width: 500px!important;
|
||||
}
|
||||
@@ -27,7 +27,7 @@
|
||||
<group>
|
||||
<field name="code" readonly="1"/>
|
||||
<field name="process_id" readonly="1"/>
|
||||
<field name="gain_way" />
|
||||
<field name="gain_way"/>
|
||||
</group>
|
||||
|
||||
</group>
|
||||
@@ -231,6 +231,9 @@
|
||||
<field name="name" string="名称搜索" filter_domain="[('name','ilike',self)]"/>
|
||||
<field name="code" string="编码搜索" filter_domain="[('code','ilike',self)]"/>
|
||||
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
|
||||
<searchpanel>
|
||||
<field name="category_id" icon="fa-building" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
@@ -266,7 +269,7 @@
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="供应商">
|
||||
<field name='supplier_ids'>
|
||||
<field name='supplier_ids' class="supplier_ids_set_css">
|
||||
<tree editable='bottom'>
|
||||
<field name="sequence" widget="handle" string="序号"/>
|
||||
<field name="partner_id" string="名称"/>
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
<field name="name">刀具标准库</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.cutting_tool.standard.library</field>
|
||||
<!-- <field name="context">{'default_cutting_tool_material_id': cutting_tool_material_id}</field>-->
|
||||
<!-- <field name="context">{'default_cutting_tool_material_id': cutting_tool_material_id}</field>-->
|
||||
<field name="view_mode">tree,form</field>
|
||||
</record>
|
||||
<!-- 功能刀具action -->
|
||||
@@ -59,46 +59,54 @@
|
||||
id="menu_sf_cutting_tool_type"
|
||||
parent="menu_sf_cutting_tool"
|
||||
name="刀具类型"
|
||||
sequence="2"
|
||||
sequence="10"
|
||||
action="action_sf_cutting_tool_type"
|
||||
/>
|
||||
<menuitem
|
||||
id="menu_sf_cutting_tool_standard_library"
|
||||
parent="menu_sf_cutting_tool"
|
||||
name="刀具标准库"
|
||||
sequence="3"
|
||||
sequence="20"
|
||||
action="action_sf_cutting_tool_standard_library"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
id="menu_sf_tool_inventory"
|
||||
parent="menu_sf_cutting_tool"
|
||||
name="功能刀具清单"
|
||||
sequence="25"
|
||||
action="action_sf_tool_inventory"
|
||||
/>
|
||||
<!-- 功能刀具 -->
|
||||
<!-- <menuitem-->
|
||||
<!-- id="menu_sf_functional_cutting_tool"-->
|
||||
<!-- parent="menu_sf_cutting_tool"-->
|
||||
<!-- name="功能刀具"-->
|
||||
<!-- sequence="5"-->
|
||||
<!-- action="action_sf_functional_cutting_tool"-->
|
||||
<!-- />-->
|
||||
<!-- <menuitem-->
|
||||
<!-- id="menu_sf_functional_cutting_tool"-->
|
||||
<!-- parent="menu_sf_cutting_tool"-->
|
||||
<!-- name="功能刀具"-->
|
||||
<!-- sequence="5"-->
|
||||
<!-- action="action_sf_functional_cutting_tool"-->
|
||||
<!-- />-->
|
||||
<!-- 功能刀具类型 -->
|
||||
<menuitem
|
||||
id="menu_sf_functional_cutting_tool_model_type"
|
||||
parent="menu_sf_cutting_tool"
|
||||
name="功能刀具类型"
|
||||
sequence="4"
|
||||
sequence="30"
|
||||
action="action_sf_functional_cutting_tool_model_type"
|
||||
/>
|
||||
|
||||
<menuitem
|
||||
id="menu_sf_maintenance_equipment_image"
|
||||
name="能力特征库"
|
||||
parent="menu_sf_cutting_tool"
|
||||
action="action_maintenance_equipment_image"
|
||||
sequence="5"/>
|
||||
id="menu_sf_maintenance_equipment_image"
|
||||
name="能力特征库"
|
||||
parent="menu_sf_cutting_tool"
|
||||
action="action_maintenance_equipment_image"
|
||||
sequence="40"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_sf_tool_groups"
|
||||
name="刀具组"
|
||||
parent="menu_sf_cutting_tool"
|
||||
action="sf_tool_groups_view_act"
|
||||
sequence="10"/>
|
||||
id="menu_sf_tool_groups"
|
||||
name="刀具组"
|
||||
parent="menu_sf_cutting_tool"
|
||||
action="sf_tool_groups_view_act"
|
||||
sequence="50"/>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -123,7 +123,7 @@
|
||||
<form string="刀具标准库" delete="0" create="0" edit="0">
|
||||
<sheet>
|
||||
<field name="image" widget='image' class="oe_avatar"
|
||||
required="1"/>
|
||||
required="1"/>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="code" readonly="1" force_save="1"/>
|
||||
@@ -547,7 +547,66 @@
|
||||
<!-- <field name="cutting_depth"/>-->
|
||||
<!-- </tree>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
<!-- </record>-->'
|
||||
|
||||
<!-- ================================================功能刀具清单================================================ -->
|
||||
<record id="view_tool_inventory_tree" model="ir.ui.view">
|
||||
<field name="name">sf.tool.inventory.tree</field>
|
||||
<field name="model">sf.tool.inventory</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具清单" create="1" edit="1" delete="0" editable="bottom">
|
||||
<field name="name"/>
|
||||
<field name="functional_cutting_tool_model_id"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="work_material"/>
|
||||
<field name="life_span"/>
|
||||
<field name="prefix" optional="hide"/>
|
||||
<field name="postfix" optional="hide"/>
|
||||
<field name="diameter"/>
|
||||
<field name="angle"/>
|
||||
<field name="tool_length"/>
|
||||
<field name="blade_length"/>
|
||||
<field name="knife_head_name" optional="hide"/>
|
||||
<field name="cutter_number"/>
|
||||
<field name="blade_number"/>
|
||||
<field name="extension"/>
|
||||
<field name="create_uid" string="创建人" optional="hide"/>
|
||||
<field name="create_date" string="创建时间" optional="hide"/>
|
||||
<field name="type" invisible="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record model="ir.ui.view" id="view_cutting_tool_material_search">
|
||||
<field name="name">sf.tool.inventory.search</field>
|
||||
<field name="model">sf.tool.inventory</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="功能刀具清单">
|
||||
<field name="name" string="名称搜索" filter_domain="[('name','ilike',self)]"/>
|
||||
<field name="functional_cutting_tool_model_id"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="work_material"/>
|
||||
<field name="life_span"/>
|
||||
<field name="prefix"/>
|
||||
<field name="postfix"/>
|
||||
<field name="diameter"/>
|
||||
<field name="angle"/>
|
||||
<field name="tool_length"/>
|
||||
<field name="blade_length"/>
|
||||
<field name="knife_head_name"/>
|
||||
<field name="cutter_number"/>
|
||||
<field name="blade_number"/>
|
||||
<field name="extension"/>
|
||||
<filter name="filter_active" string="已归档" domain="[('active','=',False)]"/>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_sf_tool_inventory" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具清单</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.tool.inventory</field>
|
||||
<field name="view_mode">tree</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
|
||||
@@ -10,6 +10,7 @@
|
||||
<field name='categ_id' class="custom_required" attrs="{'readonly': [('id', '!=', False)]}"/>
|
||||
<field name='is_bfm' invisible="1"/>
|
||||
<field name='categ_type' invisible="1"/>
|
||||
<field name='manual_quotation' attrs="{'invisible':[('upload_model_file', '=', [])]}"/>
|
||||
<field name="upload_model_file"
|
||||
widget="many2many_binary"
|
||||
attrs="{'invisible': ['|', '|',('categ_type', '!=', '成品'),('categ_type', '=', False),('is_bfm','=', True)]}"/>
|
||||
@@ -41,14 +42,15 @@
|
||||
context="{'default_cutting_tool_type': cutting_tool_type,'default_standard_library_id':cutting_tool_model_id}"
|
||||
attrs="{'invisible': [('categ_type', '!=', '刀具')],'required': [('categ_type', '=', '刀具')],'readonly': [('id', '!=', False)]}"
|
||||
domain="[('standard_library_id','=',cutting_tool_model_id)]"/>
|
||||
<field name="fixture_material_id" attrs="{'invisible': [('categ_type', '!=', '夹具')]}"
|
||||
<field name="fixture_material_id"
|
||||
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
|
||||
placeholder="请选择" options="{'no_create': True}"/>
|
||||
<field name="fixture_model_id" string="型号" placeholder="请选择" options="{'no_create': True}"
|
||||
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
|
||||
domain="[('fixture_material_id','=',fixture_material_id)]"/>
|
||||
<field name="specification_fixture_id" string="规格" placeholder="请选择"
|
||||
options="{'no_create': True}"
|
||||
attrs="{'invisible': [('categ_type', '!=', '夹具')]}"
|
||||
attrs="{'invisible': [('categ_type', '!=', '夹具')],'required': [('categ_type', '=', '夹具')]}"
|
||||
domain="[('fixture_model_id','=',fixture_model_id)]"/>
|
||||
</field>
|
||||
<xpath expr="//label[@for='volume']" position="before">
|
||||
|
||||
@@ -148,7 +148,7 @@ class SfMaintenanceEquipment(models.Model):
|
||||
MTcode = fields.Char("机台编码")
|
||||
created_user = fields.Many2one('res.users', string='创建人', default=lambda self: self.env.user)
|
||||
equipment_type = fields.Selection([('机床', '机床'), ('机器人', '机器人'), ('AGV小车', 'AGV小车'),
|
||||
('检测设备', '检测设备')], compute='_compute_category_id')
|
||||
('检测设备', '检测设备'), ('其他', '其他')], compute='_compute_category_id')
|
||||
|
||||
@api.depends('category_id')
|
||||
def _compute_category_id(self):
|
||||
|
||||
@@ -24,6 +24,7 @@
|
||||
'views/mrp_workcenter_views.xml',
|
||||
'views/mrp_workorder_view.xml',
|
||||
'views/model_type_view.xml',
|
||||
'views/agv_setting_views.xml',
|
||||
'views/sf_maintenance_equipment.xml',
|
||||
|
||||
],
|
||||
|
||||
@@ -1,6 +1,7 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
import json
|
||||
from datetime import datetime
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
|
||||
@@ -114,7 +115,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
logging.info('RfidCode:%s' % ret['RfidCode'])
|
||||
if 'RfidCode' in ret:
|
||||
workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('routing_type', '=', '装夹预调'), ('rfid_code', '=', ret['RfidCode'])])
|
||||
[('routing_type', '=', '装夹预调'), ('rfid_code', '=', ret['RfidCode'])], limit=1, order='id asc')
|
||||
if workorder:
|
||||
for item in workorder:
|
||||
if item.material_center_point:
|
||||
@@ -122,8 +123,8 @@ class Manufacturing_Connect(http.Controller):
|
||||
res['Datas'].append({
|
||||
'XOffset': 0 if not item.material_center_point else offset[0],
|
||||
'YOffset': 0 if not item.material_center_point else offset[1],
|
||||
'ZOffet': 0 if not item.material_center_point else offset[2],
|
||||
'COffset': 0 if not item.X_deviation_angle else item.X_deviation_angle,
|
||||
'ZOffset': 0 if not item.material_center_point else offset[2],
|
||||
'COffset': 0,
|
||||
'Coordinate': 'G54'
|
||||
})
|
||||
else:
|
||||
@@ -238,7 +239,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
workorder = request.env['mrp.workorder'].sudo().search(
|
||||
[('production_id', '=', production_id), ('routing_type', '=', routing_type)], limit=1)
|
||||
if workorder:
|
||||
workorder.test_result = ret['Quality']
|
||||
# workorder.test_results = ret['Quality']
|
||||
logging.info('制造订单:%s' % workorder.production_id.name)
|
||||
if 'ReportPaht' in ret:
|
||||
download_state = request.env['mrp.workorder'].with_user(
|
||||
@@ -261,8 +262,7 @@ class Manufacturing_Connect(http.Controller):
|
||||
('picking_id', '=', stock_picking.id)])
|
||||
if quality_check:
|
||||
logging.info('质检单:%s' % quality_check.name)
|
||||
quality_check.write({'report_pdf': workorder.detection_report,
|
||||
'report_result': workorder.test_result})
|
||||
quality_check.write({'report_pdf': workorder.detection_report})
|
||||
elif download_state == 2:
|
||||
res = {'Succeed': False, 'ErrorCode': 205,
|
||||
'Error': 'ReportPaht中的工件号与制造订单%s不匹配,请检查ReportPaht是否正确' % workorder.production_id.name}
|
||||
@@ -431,14 +431,15 @@ class Manufacturing_Connect(http.Controller):
|
||||
if 'DeviceId' in ret:
|
||||
logging.info('DeviceId:%s' % ret['DeviceId'])
|
||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
[('feeder_station_destination', '=', ret['DeviceId'])])
|
||||
[('feeder_station_start_id.name', '=', ret['DeviceId']),
|
||||
('status', '=', '待配送')], limit=1, order='id asc')
|
||||
if workpiece_delivery:
|
||||
for wd in workpiece_delivery:
|
||||
logging.info('wd.workorder_id:%s' % wd.workorder_id.name)
|
||||
logging.info('wd.production_id:%s' % wd.production_id.name)
|
||||
if wd.workorder_id.state == 'done' and wd.production_id.production_line_state == '待上产线':
|
||||
logging.info('wd.production_id:%s' % wd.production_id.name)
|
||||
logging.info('wd.production_line_state:%s' % wd.production_id.production_line_state)
|
||||
wd.production_id.write({'production_line_state': '已上产线'})
|
||||
wd.write({'production_line_state': '已上产线'})
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '该DeviceId没有对应的工件配送数据'}
|
||||
else:
|
||||
@@ -465,14 +466,28 @@ class Manufacturing_Connect(http.Controller):
|
||||
if 'DeviceId' in ret:
|
||||
logging.info('DeviceId:%s' % ret['DeviceId'])
|
||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
[('feeder_station_destination', '=', ret['DeviceId'])])
|
||||
[('feeder_station_destination_id.name', '=', ret['DeviceId']),
|
||||
('status', '=', '待配送')], limit=1, order='id asc')
|
||||
if workpiece_delivery:
|
||||
for wd in workpiece_delivery:
|
||||
logging.info('wd.workorder_id:%s' % wd.workorder_id.name)
|
||||
logging.info('wd.production_id:%s' % wd.production_id.name)
|
||||
if wd.workorder_id.state == 'done' and wd.production_id.production_line_state == '已上产线':
|
||||
logging.info('wd.production_id:%s' % wd.production_id.name)
|
||||
logging.info('wd.production_line_state:%s' % wd.production_id.production_line_state)
|
||||
workpiece_delivery_off = request.env['sf.workpiece.delivery'].sudo().create({
|
||||
'production_id': wd.production_id.id,
|
||||
'feeder_station_start_id': workpiece_delivery.feeder_station_start_id.id,
|
||||
'feeder_station_destination_id': '',
|
||||
'workorder_id': workpiece_delivery.workorder_id.id,
|
||||
'workpiece_code': workpiece_delivery.workpiece_code,
|
||||
'production_line_id': workpiece_delivery.production_line_id.id,
|
||||
'task_delivery_time': datetime.now(),
|
||||
'production_line_state': '已下产线'
|
||||
})
|
||||
wd.production_id.write({'production_line_state': '已下产线'})
|
||||
logging.info('开始向agv下发下产线任务')
|
||||
workpiece_delivery_off._delivery_avg()
|
||||
logging.info('agv下发下产线任务已配送')
|
||||
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 203, 'Error': '该DeviceId没有对应的工件配送数据'}
|
||||
else:
|
||||
@@ -481,3 +496,35 @@ class Manufacturing_Connect(http.Controller):
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
||||
logging.info('AGVDownProduct error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@http.route('/AutoDeviceApi/EquipmentBaseCoordinate', type='json', auth='none', methods=['GET', 'POST'], csrf=False,
|
||||
cors="*")
|
||||
def PutEquipmentBaseCoordinate(self, **kw):
|
||||
"""
|
||||
获取机床基坐标
|
||||
:param kw:
|
||||
:return:
|
||||
"""
|
||||
logging.info('PutEquipmentBaseCoordinate:%s' % kw)
|
||||
try:
|
||||
res = {'Succeed': True}
|
||||
datas = request.httprequest.data
|
||||
ret = json.loads(datas)
|
||||
if 'DeviceId' in ret:
|
||||
equipment = request.env['maintenance.equipment'].sudo().search('name', '=', ret['DeviceId'])
|
||||
if equipment:
|
||||
equipment.sudo().write({
|
||||
'base_coordinate_fixture_model_id': ret['base_coordinate_fixture_model_id'],
|
||||
'base_coordinate_g_coordinate': ret['base_coordinate_g_coordinate'],
|
||||
'base_coordinate_x': ret['base_coordinate_x'],
|
||||
'base_coordinate_y': ret['base_coordinate_y'],
|
||||
'base_coordinate_z': ret['base_coordinate_z'],
|
||||
})
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 203, 'Error': 'DeviceId为%s的设备不存在!' % ret['DeviceId']}
|
||||
else:
|
||||
res = {'Succeed': False, 'ErrorCode': 201, 'Error': '未传DeviceId字段'}
|
||||
except Exception as e:
|
||||
res = {'Succeed': False, 'ErrorCode': 202, 'Error': e}
|
||||
logging.info('AGVDownProduct error:%s' % e)
|
||||
return json.JSONEncoder().encode(res)
|
||||
|
||||
@@ -25,7 +25,7 @@ class Workpiece(http.Controller):
|
||||
if 'method' in ret:
|
||||
if ret['method'] == 'end':
|
||||
workpiece_delivery = request.env['sf.workpiece.delivery'].sudo().search(
|
||||
[('production_id.name', '=', ret['reqCode'])])
|
||||
[('production_id.name', '=', ret['reqCode']), ('agv_task_code'), '=', ret['taskCode']])
|
||||
if workpiece_delivery:
|
||||
workpiece_delivery.write({'status': '已配送', 'task_completion_time': ret['reqTime']})
|
||||
else:
|
||||
|
||||
@@ -67,5 +67,21 @@
|
||||
search="[('barcode','=','WH-PREPRODUCTION')]"/>
|
||||
<field name="default_location_dest_id" ref="stock_location_locations_virtual_outcontract"/>
|
||||
</record>
|
||||
|
||||
<record id="route_surface_technology_outsourcing" model="stock.route">
|
||||
<field name="name">表面工艺外协</field>
|
||||
<!-- <field name="company_id"></field>-->
|
||||
<field name="active">True</field>
|
||||
<field name="sequence">11</field>
|
||||
</record>
|
||||
<!-- <record id="route_surface_technology_outsourcing" model="stock.rule">-->
|
||||
<!-- <field name="name">外协出库单</field>-->
|
||||
<!-- <field name="action">push</field>-->
|
||||
<!-- <field name="pick_type_id" ref="outcontract_picking_out"></field>-->
|
||||
<!-- <field name="location_src_id" ref=""/>-->
|
||||
<!-- <field name="location_dest_id" ref="stock_location_locations_virtual_outcontract"/>-->
|
||||
<!-- <field name="active">True</field>-->
|
||||
<!-- <field name="sequence">11</field>-->
|
||||
<!-- </record>-->
|
||||
</data>
|
||||
</odoo>
|
||||
|
||||
@@ -8,3 +8,4 @@ from . import mrp_routing_workcenter
|
||||
from . import stock
|
||||
from . import res_user
|
||||
from . import production_line_base
|
||||
from . import agv_setting
|
||||
|
||||
35
sf_manufacturing/models/agv_setting.py
Normal file
35
sf_manufacturing/models/agv_setting.py
Normal file
@@ -0,0 +1,35 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
from odoo import fields, models
|
||||
|
||||
|
||||
class AgvSetting(models.Model):
|
||||
_name = 'sf.agv.site'
|
||||
_description = 'agv站点'
|
||||
|
||||
number = fields.Integer('序号')
|
||||
name = fields.Char('位置编号')
|
||||
owning_region = fields.Char('所属区域')
|
||||
state = fields.Selection([
|
||||
('占用', '占用'),
|
||||
('空闲', '空闲')], string='状态')
|
||||
divide_the_work = fields.Char('主要分工')
|
||||
|
||||
|
||||
class AgvTaskRoute(models.Model):
|
||||
_name = 'sf.agv.task.route'
|
||||
_description = 'agv任务路线'
|
||||
|
||||
name = fields.Char('名称')
|
||||
type = fields.Selection([
|
||||
('F01', '搬运'), ], string='类型', default="F01")
|
||||
start_site_id = fields.Many2one('sf.agv.site', '起点接驳站位置编号')
|
||||
end_site_id = fields.Many2one('sf.agv.site', '终点接驳站位置编号')
|
||||
destination_production_line_id = fields.Many2one('sf.production.line', '目的生产线')
|
||||
priority = fields.Selection([
|
||||
('0', '正常'),
|
||||
('1', '低'),
|
||||
('2', '中'),
|
||||
('3', '高'),
|
||||
('4', '紧急'),
|
||||
], string='优先级', default='0')
|
||||
active = fields.Boolean('有效', default=True)
|
||||
@@ -54,8 +54,11 @@ class MrpProduction(models.Model):
|
||||
glb_file = fields.Binary("glb模型文件")
|
||||
production_line_id = fields.Many2one('sf.production.line', string='生产线')
|
||||
plan_start_processing_time = fields.Datetime('计划开始加工时间')
|
||||
production_line_state = fields.Selection([('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
|
||||
string='上/下产线', default='待上产线')
|
||||
production_line_state = fields.Selection(
|
||||
[('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
|
||||
string='上/下产线', default='待上产线')
|
||||
|
||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
||||
|
||||
@api.depends(
|
||||
'move_raw_ids.state', 'move_raw_ids.quantity_done', 'move_finished_ids.state',
|
||||
@@ -132,6 +135,15 @@ class MrpProduction(models.Model):
|
||||
# cnc程序获取
|
||||
def fetchCNC(self):
|
||||
cnc = self.env['mrp.production'].search([('id', '=', self.id)])
|
||||
quick_order = self.env['quick.easy.order'].search(
|
||||
[('name', '=', cnc.product_id.default_code.rsplit('-', 1)[0])])
|
||||
programme_way = False
|
||||
if cnc.manual_quotation is True:
|
||||
programme_way = 'manual operation'
|
||||
else:
|
||||
programme_way = 'auto'
|
||||
if quick_order:
|
||||
programme_way = 'manual operation'
|
||||
try:
|
||||
res = {'model_code': '' if not cnc.product_id.model_code else cnc.product_id.model_code,
|
||||
'production_no': cnc.name,
|
||||
@@ -146,8 +158,9 @@ class MrpProduction(models.Model):
|
||||
'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height,
|
||||
'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
|
||||
'order_no': cnc.origin,
|
||||
'model_order_no': cnc.product_id.default_code.rsplit(' -', 1)[0],
|
||||
'model_order_no': cnc.product_id.default_code,
|
||||
'user': cnc.env.user.name,
|
||||
'programme_way': programme_way,
|
||||
'model_file': '' if not cnc.product_id.model_file else base64.b64encode(
|
||||
cnc.product_id.model_file).decode('utf-8')
|
||||
}
|
||||
|
||||
@@ -1,10 +1,14 @@
|
||||
import re
|
||||
|
||||
import logging
|
||||
import base64
|
||||
import urllib.parse
|
||||
from datetime import date
|
||||
from datetime import datetime, timedelta
|
||||
import requests
|
||||
import os
|
||||
import math
|
||||
from lxml import etree
|
||||
from dateutil.relativedelta import relativedelta
|
||||
# import subprocess
|
||||
from odoo import api, fields, models, SUPERUSER_ID, _
|
||||
@@ -42,6 +46,8 @@ class ResMrpWorkOrder(models.Model):
|
||||
], string="工序类型")
|
||||
results = fields.Char('结果')
|
||||
|
||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
||||
|
||||
@api.onchange('users_ids')
|
||||
def get_user_permissions(self):
|
||||
uid = self.env.uid
|
||||
@@ -95,11 +101,12 @@ class ResMrpWorkOrder(models.Model):
|
||||
Y10_axis = fields.Float(default=0)
|
||||
Z10_axis = fields.Float(default=0)
|
||||
X_deviation_angle = fields.Integer(string="X轴偏差度", default=0)
|
||||
test_result = fields.Char("检测结果")
|
||||
test_results = fields.Selection([("合格", "合格"), ("返工", "返工"), ("报废", "报废")], default='合格',
|
||||
string="检测结果")
|
||||
cnc_ids = fields.One2many("sf.cnc.processing", 'workorder_id', string="CNC加工程序")
|
||||
cmm_ids = fields.One2many("sf.cmm.program", 'workorder_id', string="CMM程序")
|
||||
tray_code = fields.Char(string="托盘编码")
|
||||
glb_file = fields.Binary("glb模型文件")
|
||||
glb_file = fields.Binary("glb模型文件", related='production_id.model_file')
|
||||
is_subcontract = fields.Boolean(string='是否外协')
|
||||
surface_technics_parameters_id = fields.Many2one('sf.production.process.parameter', string="表面工艺可选参数")
|
||||
picking_in_id = fields.Many2one('stock.picking', string='外协入库单')
|
||||
@@ -111,6 +118,19 @@ class ResMrpWorkOrder(models.Model):
|
||||
processing_user_id = fields.Many2one('res.users', string='加工人')
|
||||
# 检测人
|
||||
inspection_user_id = fields.Many2one('res.users', string='检测人')
|
||||
# 保存名称
|
||||
save_name = fields.Char(string='检测文件保存名称', compute='_compute_save_name')
|
||||
# 获取数据状态
|
||||
data_state = fields.Boolean(string='获取数据状态', default=False)
|
||||
|
||||
@api.depends('production_id')
|
||||
def _compute_save_name(self):
|
||||
"""
|
||||
保存名称
|
||||
"""
|
||||
for record in self:
|
||||
record.save_name = record.production_id.name.replace('/', '_')
|
||||
|
||||
schedule_state = fields.Selection(related='production_id.schedule_state', store=True)
|
||||
# 工件装夹信息
|
||||
functional_fixture_code = fields.Char(string="功能夹具编码", readonly=True)
|
||||
@@ -140,6 +160,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
production_line_state = fields.Selection(related='production_id.production_line_state',
|
||||
string='上/下产线', store=True)
|
||||
detection_report = fields.Binary('检测报告', readonly=True)
|
||||
is_remanufacture = fields.Boolean(string='是否重新生成制造订单', default=True)
|
||||
|
||||
def get_plan_workorder(self, production_line):
|
||||
tomorrow = (date.today() + timedelta(days=+1)).strftime("%Y-%m-%d")
|
||||
@@ -182,6 +203,149 @@ class ResMrpWorkOrder(models.Model):
|
||||
[('surface_technics_parameters_id', '!=', False), ('production_id', '=', production_id)])
|
||||
return process_parameter_workorder
|
||||
|
||||
# 获取三次元检测点数据
|
||||
def get_three_check_datas(self):
|
||||
factory_nick_name = 'XT'
|
||||
ftp_resconfig = self.env['res.config.settings'].get_values()
|
||||
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']),
|
||||
ftp_resconfig['ftp_user'],
|
||||
ftp_resconfig['ftp_password'])
|
||||
# ftp.connect()
|
||||
|
||||
local_dir_path = '/ftp/before'
|
||||
os.makedirs(local_dir_path, exist_ok=True)
|
||||
local_filename = self.save_name + '.xls'
|
||||
local_file_path = os.path.join(local_dir_path, local_filename)
|
||||
logging.info('local_file_path:%s' % local_file_path)
|
||||
remote_path = '/home/ftp/ftp_root/ThreeTest/XT/Before/' + local_filename
|
||||
logging.info('remote_path:%s' % remote_path)
|
||||
|
||||
if not ftp.file_exists(remote_path):
|
||||
raise UserError(f"文件不存在: {remote_path}")
|
||||
|
||||
with open(local_file_path, 'wb') as local_file:
|
||||
ftp.ftp.retrbinary('RETR ' + remote_path, local_file.write)
|
||||
logging.info('下载文件成功')
|
||||
# 解析本地文件
|
||||
# file_path = 'WH_MO_00099.xls' # 使用下载的实际文件路径
|
||||
parser = etree.XMLParser(recover=True) # Using recover to handle errors
|
||||
tree = etree.parse(local_file_path, parser)
|
||||
logging.info('tree:%s' % tree)
|
||||
root = tree.getroot()
|
||||
logging.info('root:%s' % root)
|
||||
|
||||
# 准备一个外部字典来存储以PT为键的坐标字典
|
||||
pt_coordinates = {}
|
||||
# 遍历每个工作表和行
|
||||
for worksheet in root.iterfind('.//{urn:schemas-microsoft-com:office:spreadsheet}Worksheet'):
|
||||
sheet_name = worksheet.attrib.get('{urn:schemas-microsoft-com:office:spreadsheet}Name')
|
||||
logging.info('sheet_name:%s' % sheet_name)
|
||||
if sheet_name == "Sheet1": # 确保我们只查看包含数据的工作表
|
||||
current_pt = None
|
||||
for row in worksheet.iterfind('.//{urn:schemas-microsoft-com:office:spreadsheet}Row'):
|
||||
cells = list(row.iterfind('.//{urn:schemas-microsoft-com:office:spreadsheet}Cell'))
|
||||
for i, cell in enumerate(cells):
|
||||
data_cell = cell.find('.//{urn:schemas-microsoft-com:office:spreadsheet}Data')
|
||||
if data_cell is not None and data_cell.text is not None: # 添加检查以确保data_cell.text不为空
|
||||
# 检查是否是PT标识
|
||||
logging.info(f"Data in cell: {data_cell.text}") # 输出单元格数据
|
||||
if "PT" in data_cell.text:
|
||||
current_pt = data_cell.text
|
||||
pt_coordinates[current_pt] = []
|
||||
elif data_cell.text in ["X", "Y", "Z"] and current_pt is not None:
|
||||
# 确保当前单元格后面还有单元格存在,以获取理论值
|
||||
if i + 1 < len(cells):
|
||||
next_cell = cells[i + 1]
|
||||
theory_value = next_cell.find(
|
||||
'.//{urn:schemas-microsoft-com:office:spreadsheet}Data')
|
||||
if theory_value is not None:
|
||||
# 为当前PT键添加坐标数据
|
||||
pt_coordinates[current_pt].append({
|
||||
data_cell.text: float(theory_value.text)
|
||||
})
|
||||
logging.info(f"PT: {current_pt} - {data_cell.text}: {theory_value.text}")
|
||||
logging.info('pt_coordinates=====%s' % pt_coordinates)
|
||||
# pt_coordinates:{'PT1': [{'X': 38.9221}, {'Y': -18.7304}, {'Z': 128.0783}],
|
||||
# 'PT2': [{'X': 39.2456}, {'Y': -76.9169}, {'Z': 123.7541}]}
|
||||
|
||||
# 检查是否存在PT1等键
|
||||
if 'PT1' in pt_coordinates and pt_coordinates['PT1']:
|
||||
self.X1_axis = pt_coordinates['PT3'][0]['X']
|
||||
self.Y1_axis = pt_coordinates['PT3'][1]['Y']
|
||||
self.Z1_axis = pt_coordinates['PT3'][2]['Z']
|
||||
else:
|
||||
raise UserError('PT1点未测或数据错误')
|
||||
if 'PT2' in pt_coordinates and pt_coordinates['PT2']:
|
||||
self.X2_axis = pt_coordinates['PT4'][0]['X']
|
||||
self.Y2_axis = pt_coordinates['PT4'][1]['Y']
|
||||
self.Z2_axis = pt_coordinates['PT4'][2]['Z']
|
||||
else:
|
||||
raise UserError('PT2点未测或数据错误')
|
||||
if 'PT3' in pt_coordinates and pt_coordinates['PT3']:
|
||||
self.X3_axis = pt_coordinates['PT5'][0]['X']
|
||||
self.Y3_axis = pt_coordinates['PT5'][1]['Y']
|
||||
self.Z3_axis = pt_coordinates['PT5'][2]['Z']
|
||||
else:
|
||||
raise UserError('PT3点未测或数据错误')
|
||||
if 'PT4' in pt_coordinates and pt_coordinates['PT4']:
|
||||
self.X4_axis = pt_coordinates['PT6'][0]['X']
|
||||
self.Y4_axis = pt_coordinates['PT6'][1]['Y']
|
||||
self.Z4_axis = pt_coordinates['PT6'][2]['Z']
|
||||
else:
|
||||
raise UserError('PT4点未测或数据错误')
|
||||
if 'PT5' in pt_coordinates and pt_coordinates['PT5']:
|
||||
self.X5_axis = pt_coordinates['PT7'][0]['X']
|
||||
self.Y5_axis = pt_coordinates['PT7'][1]['Y']
|
||||
self.Z5_axis = pt_coordinates['PT7'][2]['Z']
|
||||
else:
|
||||
raise UserError('PT5点未测或数据错误')
|
||||
if 'PT6' in pt_coordinates and pt_coordinates['PT6']:
|
||||
self.X6_axis = pt_coordinates['PT8'][0]['X']
|
||||
self.Y6_axis = pt_coordinates['PT8'][1]['Y']
|
||||
self.Z6_axis = pt_coordinates['PT8'][2]['Z']
|
||||
else:
|
||||
raise UserError('PT6点未测或数据错误')
|
||||
if 'PT7' in pt_coordinates and pt_coordinates['PT7']:
|
||||
self.X7_axis = pt_coordinates['PT9'][0]['X']
|
||||
self.Y7_axis = pt_coordinates['PT9'][1]['Y']
|
||||
self.Z7_axis = pt_coordinates['PT9'][2]['Z']
|
||||
else:
|
||||
raise UserError('PT7点未测或数据错误')
|
||||
if 'PT8' in pt_coordinates and pt_coordinates['PT8']:
|
||||
self.X8_axis = pt_coordinates['PT10'][0]['X']
|
||||
self.Y8_axis = pt_coordinates['PT10'][1]['Y']
|
||||
self.Z8_axis = pt_coordinates['PT10'][2]['Z']
|
||||
else:
|
||||
raise UserError('PT8点未测或数据错误')
|
||||
if 'PT9' in pt_coordinates and pt_coordinates['PT9']:
|
||||
self.X9_axis = pt_coordinates['PT1'][0]['X']
|
||||
self.Y9_axis = pt_coordinates['PT1'][1]['Y']
|
||||
self.Z9_axis = pt_coordinates['PT1'][2]['Z']
|
||||
else:
|
||||
raise UserError('PT9点未测或数据错误')
|
||||
if 'PT10' in pt_coordinates and pt_coordinates['PT10']:
|
||||
self.X10_axis = pt_coordinates['PT2'][0]['X']
|
||||
self.Y10_axis = pt_coordinates['PT2'][1]['Y']
|
||||
self.Z10_axis = pt_coordinates['PT2'][2]['Z']
|
||||
else:
|
||||
raise UserError('PT10点未测或数据错误')
|
||||
|
||||
self.data_state = True
|
||||
|
||||
return True
|
||||
|
||||
# ftp.download_file('three_check_datas.xls', '/home/ftpuser/three_check_datas.xls')
|
||||
# ftp.close()
|
||||
# data = xlrd.open_workbook('/home/ftpuser/three_check_datas.xls')
|
||||
# table = data.sheets()[0]
|
||||
# nrows = table.nrows
|
||||
# # 点坐标列表
|
||||
# point_list = []
|
||||
# datas = []
|
||||
# for i in range(1, nrows):
|
||||
# datas.append(table.row_values(i))
|
||||
# return datas
|
||||
|
||||
# 计算配料中心点和与x轴倾斜度方法
|
||||
def getcenter(self):
|
||||
try:
|
||||
@@ -202,6 +366,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
y7 = self.Y7_axis
|
||||
y8 = self.Y8_axis
|
||||
z1 = self.Z9_axis
|
||||
z2 = self.Z10_axis
|
||||
x0 = ((x3 - x4) * (x2 * y1 - x1 * y2) - (x1 - x2) * (x4 * y3 - x3 * y4)) / (
|
||||
(x3 - x4) * (y1 - y2) - (x1 - x2) * (y3 - y4))
|
||||
y0 = ((y3 - y4) * (y2 * x1 - y1 * x2) - (y1 - y2) * (y4 * x3 - y3 * x4)) / (
|
||||
@@ -212,7 +377,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
(y7 - y8) * (x5 - x6) - (y5 - y6) * (x7 - x8))
|
||||
x = (x0 + x1) / 2
|
||||
y = (y0 + y1) / 2
|
||||
z = z1 / 2
|
||||
z = (z1 + z2) / 2
|
||||
|
||||
jd = math.atan2((x5 - x6), (y5 - y6))
|
||||
jdz = jd * 180 / math.pi
|
||||
@@ -225,27 +390,31 @@ class ResMrpWorkOrder(models.Model):
|
||||
work.compensation_value_x = eval(self.material_center_point)[0]
|
||||
work.compensation_value_y = eval(self.material_center_point)[1]
|
||||
workorder.button_finish()
|
||||
except:
|
||||
raise UserError("参数计算有误")
|
||||
except Exception as e:
|
||||
# 重新抛出捕获到的异常信息
|
||||
raise UserError(str(e))
|
||||
|
||||
def button_workpiece_delivery(self):
|
||||
if self.routing_type == '装夹预调':
|
||||
for item in self.workpiece_delivery_ids:
|
||||
if not item.feeder_station_start:
|
||||
raise UserError('【工件配送】明细中请输入起点接驳站')
|
||||
if not item.route_id:
|
||||
raise UserError('【工件配送】明细中请选择【任务路线】')
|
||||
# if not item.workpiece_code:
|
||||
# raise UserError('请对【同运工件】进行扫描')
|
||||
else:
|
||||
if item.status == '待下发':
|
||||
return {
|
||||
'name': _('确认'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'sf.workpiece.delivery.wizard',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_workorder_id': self.id,
|
||||
}}
|
||||
if self.cnc_program_down_state == '已下发':
|
||||
if item.status == '待下发':
|
||||
return {
|
||||
'name': _('确认'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'sf.workpiece.delivery.wizard',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_workorder_id': self.id,
|
||||
}}
|
||||
else:
|
||||
raise UserError(_("该制造订单还未下发CNC程序单,无法进行工件配送"))
|
||||
|
||||
# 拼接工单对象属性值
|
||||
def json_workorder_str(self, k, production, route):
|
||||
@@ -443,7 +612,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
"""
|
||||
重新生成制造订单或者重新生成工单
|
||||
"""
|
||||
if self.test_result == '报废':
|
||||
if self.test_results == '报废':
|
||||
values = self.env['mrp.production'].create_production1_values(self.production_id)
|
||||
productions = self.env['mrp.production'].with_user(SUPERUSER_ID).sudo().with_company(
|
||||
self.production_id.company_id).create(
|
||||
@@ -475,7 +644,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
'mail.message_origin_link',
|
||||
values={'self': production, 'origin': origin_production},
|
||||
subtype_id=self.env.ref('mail.mt_note').id)
|
||||
if self.test_result == '返工':
|
||||
if self.test_results == '返工':
|
||||
productions = self.production_id
|
||||
# self.env['stock.move'].sudo().create(productions._get_moves_raw_values())
|
||||
# self.env['stock.move'].sudo().create(productions._get_moves_finished_values())
|
||||
@@ -483,47 +652,6 @@ class ResMrpWorkOrder(models.Model):
|
||||
else:
|
||||
self.results = '合格'
|
||||
|
||||
# cnc程序获取
|
||||
def fetchCNC(self):
|
||||
try:
|
||||
cnc = self.env['mrp.workorder'].search(
|
||||
[('routing_type', '=', 'CNC加工'), ('production_id', '=', self.production_id.id)], limit=1)
|
||||
res = {'model_code': '' if not cnc.product_id.model_code else cnc.product_id.model_code,
|
||||
'production_no': self.production_id.name,
|
||||
'machine_tool_code': cnc.workcenter_id.equipment_id.code,
|
||||
'material_code': cnc.env['sf.production.materials'].search(
|
||||
[('id', '=', cnc.product_id.materials_id.id)]).materials_no,
|
||||
'material_type_code': cnc.env['sf.materials.model'].search(
|
||||
[('id', '=', cnc.product_id.materials_type_id.id)]).materials_no,
|
||||
'machining_processing_panel': cnc.product_id.model_processing_panel,
|
||||
'machining_precision': cnc.product_id.model_machining_precision,
|
||||
'embryo_long': cnc.product_id.bom_ids.bom_line_ids.product_id.length,
|
||||
'embryo_height': cnc.product_id.bom_ids.bom_line_ids.product_id.height,
|
||||
'embryo_width': cnc.product_id.bom_ids.bom_line_ids.product_id.width,
|
||||
'order_no': cnc.production_id.origin,
|
||||
'model_order_no': cnc.product_id.default_code.rsplit(' -', 1)[0],
|
||||
'user': self.env.user.name,
|
||||
'model_file': '' if not cnc.product_id.model_file else base64.b64encode(
|
||||
cnc.product_id.model_file).decode('utf-8')
|
||||
}
|
||||
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/create'
|
||||
config_url = configsettings['sf_url'] + url
|
||||
# res_str = json.dumps(res)
|
||||
ret = requests.post(config_url, json={}, data=res, headers=config_header)
|
||||
ret = ret.json()
|
||||
logging.info('fetchCNC-ret:%s' % ret)
|
||||
if ret['status'] == 1:
|
||||
self.write(
|
||||
{'programming_no': ret['programming_no'], 'programming_state': '编程中', 'work_state': '编程中'})
|
||||
else:
|
||||
raise UserError(ret['message'])
|
||||
except Exception as e:
|
||||
logging.info('fetchCNC error:%s' % e)
|
||||
raise UserError("cnc程序获取编程单失败,请联系管理员")
|
||||
|
||||
def json_workorder_str1(self, k, production, route):
|
||||
workorders_values_str = [0, '', {
|
||||
'product_uom_id': production.product_uom_id.id,
|
||||
@@ -555,6 +683,12 @@ class ResMrpWorkOrder(models.Model):
|
||||
picking_out.write({'state': 'assigned'})
|
||||
if self.state == 'waiting' or self.state == 'ready' or self.state == 'progress':
|
||||
self.move_raw_ids = self.production_id.move_raw_ids
|
||||
self.move_raw_ids[0].write({
|
||||
'materiel_length': self.move_raw_ids[0].product_id.length,
|
||||
'materiel_width': self.move_raw_ids[0].product_id.width,
|
||||
'materiel_height': self.move_raw_ids[0].product_id.height
|
||||
})
|
||||
|
||||
self.ensure_one()
|
||||
if any(not time.date_end for time in self.time_ids.filtered(lambda t: t.user_id.id == self.env.user.id)):
|
||||
return True
|
||||
@@ -605,6 +739,8 @@ class ResMrpWorkOrder(models.Model):
|
||||
if self.routing_type == '装夹预调':
|
||||
if not self.material_center_point and self.X_deviation_angle > 0:
|
||||
raise UserError("请对前置三元检测定位参数进行计算定位")
|
||||
if not self.rfid_code:
|
||||
raise UserError("请扫RFID码进行绑定")
|
||||
if self.picking_out_id:
|
||||
picking_out = self.env['stock.picking'].search([('id', '=', self.picking_out_id.id)])
|
||||
if picking_out.workorder_out_id:
|
||||
@@ -647,7 +783,7 @@ class ResMrpWorkOrder(models.Model):
|
||||
production_no_ftp = reportpath.split('/')
|
||||
production_no = workorder.production_id.name.replace('/', '_')
|
||||
# ftp地址
|
||||
remotepath = os.path.join('/', production_no_ftp[1], 'detection')
|
||||
remotepath = os.path.join('/NC', production_no_ftp[1], 'detection')
|
||||
logging.info('ftp地址:%s' % remotepath)
|
||||
if reportpath.find(production_no) != -1:
|
||||
# 服务器内临时地址
|
||||
@@ -726,7 +862,7 @@ class CNCprocessing(models.Model):
|
||||
'cutting_tool_handle_type': obj['cutting_tool_handle_type'],
|
||||
'estimated_processing_time': obj['estimated_processing_time'],
|
||||
'remark': obj['remark'],
|
||||
'program_path': program_path.replace('/tmp', '')
|
||||
'program_path': program_path.replace('/tmp', '/home/ftp/ftp_root/NC')
|
||||
})
|
||||
cnc_processing.get_cnc_processing_file(program_path_tmp, cnc_processing, program_path)
|
||||
# cnc_workorder.state = 'done'
|
||||
@@ -735,7 +871,7 @@ class CNCprocessing(models.Model):
|
||||
# cnc_workorder.time_ids.date_end = datetime.now()
|
||||
# cnc_workorder.button_finish()
|
||||
|
||||
# 根据程序名和加工面匹配到ftp里对应的Nc程序名
|
||||
# 根据程序名和加工面匹配到ftp里对应的Nc程序名,可优化为根据cnc_processing.program_path进行匹配
|
||||
def get_cnc_processing_file(self, serverdir, cnc_processing, program_path):
|
||||
logging.info('serverdir:%s' % serverdir)
|
||||
for root, dirs, files in os.walk(serverdir):
|
||||
@@ -765,7 +901,7 @@ class CNCprocessing(models.Model):
|
||||
|
||||
# 将FTP的nc文件下载到临时目录
|
||||
def download_file_tmp(self, production_no, processing_panel):
|
||||
remotepath = os.path.join('/', production_no, 'return', processing_panel)
|
||||
remotepath = os.path.join('/NC', production_no, 'return', processing_panel)
|
||||
serverdir = os.path.join('/tmp', production_no, 'return', processing_panel)
|
||||
ftp_resconfig = self.env['res.config.settings'].get_values()
|
||||
ftp = FtpController(str(ftp_resconfig['ftp_host']), int(ftp_resconfig['ftp_port']), ftp_resconfig['ftp_user'],
|
||||
@@ -777,7 +913,7 @@ class CNCprocessing(models.Model):
|
||||
# 将nc文件存到attach的datas里
|
||||
def write_file(self, nc_file_path, cnc):
|
||||
nc_file_name = nc_file_path.split('/')
|
||||
logging.info('nc_file_name:%s' % nc_file_name[-1])
|
||||
logging.info('file_name:%s' % nc_file_name[-1])
|
||||
if os.path.exists(nc_file_path):
|
||||
with open(nc_file_path, 'rb') as file:
|
||||
data_bytes = file.read()
|
||||
@@ -818,25 +954,35 @@ class SfWorkOrderBarcodes(models.Model):
|
||||
workorder = self.env['mrp.workorder'].browse(self.ids)
|
||||
# workorder = self.env['mrp.workorder'].search(
|
||||
# [('routing_type', '=', '装夹预调'), ('production_id', '=', self.production_id.id)])
|
||||
workorder_old = self.env['mrp.workorder'].search([('rfid_code', '=', barcode)])
|
||||
if workorder_old:
|
||||
raise UserError('该托盘已绑定工件,请先解除绑定!!!')
|
||||
if workorder:
|
||||
if workorder.routing_type == '装夹预调':
|
||||
stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)])
|
||||
if stock_move_line.product_id.categ_type == '夹具':
|
||||
workorder.write({
|
||||
'tray_serial_number': stock_move_line.lot_name,
|
||||
'tray_product_id': stock_move_line.product_id.id,
|
||||
'tray_brand_id': stock_move_line.product_id.brand_id.id,
|
||||
'tray_type_id': stock_move_line.product_id.fixture_material_id.id,
|
||||
'tray_model_id': stock_move_line.product_id.fixture_model_id.id
|
||||
})
|
||||
workorder.button_start()
|
||||
# return {
|
||||
# 'type': 'ir.actions.act_window',
|
||||
# 'res_model': 'mrp.workorder',
|
||||
# 'view_mode': 'form',
|
||||
# 'domain': [('id', 'in', workorder.id)],
|
||||
# 'target': 'current'
|
||||
# }
|
||||
if workorder.state in ['done']:
|
||||
work_state = {'done': '已完工'}
|
||||
raise UserError('装夹%s,请勿重复扫码' % work_state.get(workorder.state))
|
||||
lots = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)])
|
||||
logging.info("托盘信息:%s" % lots)
|
||||
if lots:
|
||||
for lot in lots:
|
||||
if lot.product_id.categ_type == '夹具':
|
||||
val = {
|
||||
'tray_serial_number': lot.name,
|
||||
'tray_product_id': lot.product_id.id,
|
||||
'tray_brand_id': lot.product_id.brand_id.id,
|
||||
'tray_type_id': lot.product_id.fixture_material_id.id,
|
||||
'tray_model_id': lot.product_id.fixture_model_id.id,
|
||||
'rfid_code': barcode
|
||||
}
|
||||
workorder.write(val)
|
||||
self.write(val)
|
||||
workorder_rfid = self.env['mrp.workorder'].search(
|
||||
[('production_id', '=', workorder.production_id.id)])
|
||||
if workorder_rfid:
|
||||
for item in workorder_rfid:
|
||||
item.write({'rfid_code': barcode})
|
||||
logging.info("Rfid绑定成功!!!")
|
||||
else:
|
||||
embryo_stock_lot = self.env['stock.lot'].search([('name', '=', barcode)])
|
||||
if embryo_stock_lot:
|
||||
@@ -868,7 +1014,58 @@ class SfWorkOrderBarcodes(models.Model):
|
||||
[('production_id', '=', workorder.production_id.id)])
|
||||
if workorder_rfid:
|
||||
for item in workorder_rfid:
|
||||
item.write({'rfid_code': barcode})
|
||||
if item.state == "progress":
|
||||
item.write({'rfid_code': barcode})
|
||||
raise UserError('该托盘信息不存在!!!')
|
||||
# stock_move_line = self.env['stock.move.line'].search([('lot_name', '=', barcode)])
|
||||
# if stock_move_line.product_id.categ_type == '夹具':
|
||||
# workorder.write({
|
||||
# 'tray_serial_number': stock_move_line.lot_name,
|
||||
# 'tray_product_id': stock_move_line.product_id.id,
|
||||
# 'tray_brand_id': stock_move_line.product_id.brand_id.id,
|
||||
# 'tray_type_id': stock_move_line.product_id.fixture_material_id.id,
|
||||
# 'tray_model_id': stock_move_line.product_id.fixture_model_id.id
|
||||
# })
|
||||
# workorder.button_start()
|
||||
# # return {
|
||||
# # 'type': 'ir.actions.act_window',
|
||||
# # 'res_model': 'mrp.workorder',
|
||||
# # 'view_mode': 'form',
|
||||
# # 'domain': [('id', 'in', workorder.id)],
|
||||
# # 'target': 'current'
|
||||
# # }
|
||||
# else:
|
||||
# embryo_stock_lot = self.env['stock.lot'].search([('name', '=', barcode)])
|
||||
# if embryo_stock_lot:
|
||||
# embryo_stock_move_line = self.env['stock.move.line'].search(
|
||||
# [('product_id', '=', embryo_stock_lot.product_id.id),
|
||||
# ('reference', '=', workorder.production_id.name),
|
||||
# ('lot_id', '=', embryo_stock_lot.id),
|
||||
# ('product_category_name', '=', '坯料')])
|
||||
# if embryo_stock_move_line:
|
||||
# bom_production = self.env['mrp.production'].search(
|
||||
# [('product_id', '=', embryo_stock_lot.product_id.id),
|
||||
# ('origin', '=', workorder.production_id.name)], limit=1, order='id asc')
|
||||
# workpiece_delivery = self.env['sf.workpiece.delivery'].search(
|
||||
# [('workorder_id', '=', workorder.id)], limit=1, order='id asc')
|
||||
# if workpiece_delivery:
|
||||
# embryo_workpiece_code = workpiece_delivery.workpiece_code
|
||||
# if bom_production:
|
||||
# if workpiece_delivery.workpiece_code and bom_production.name not in \
|
||||
# workpiece_delivery.workpiece_code:
|
||||
# embryo_workpiece_code = workpiece_delivery.workpiece_code + ',' + \
|
||||
# bom_production.name
|
||||
# if not workpiece_delivery.workpiece_code:
|
||||
# embryo_workpiece_code = bom_production.name
|
||||
# workpiece_delivery.write({'workpiece_code': embryo_workpiece_code})
|
||||
# else:
|
||||
# raise UserError('工件生产线不一致,请重新确认')
|
||||
# else:
|
||||
# workorder_rfid = self.env['mrp.workorder'].search(
|
||||
# [('production_id', '=', workorder.production_id.id)])
|
||||
# if workorder_rfid:
|
||||
# for item in workorder_rfid:
|
||||
# item.write({'rfid_code': barcode})
|
||||
|
||||
|
||||
class WorkPieceDelivery(models.Model):
|
||||
@@ -882,53 +1079,88 @@ class WorkPieceDelivery(models.Model):
|
||||
store=True)
|
||||
plan_start_processing_time = fields.Datetime('计划开始加工时间', readonly=True)
|
||||
workpiece_code = fields.Char('同运工件编码')
|
||||
feeder_station_start = fields.Char('起点接驳站')
|
||||
feeder_station_destination = fields.Char('目的接驳站')
|
||||
route_id = fields.Many2one('sf.agv.task.route', '任务路线')
|
||||
feeder_station_start_id = fields.Many2one('sf.agv.site', '起点接驳站')
|
||||
feeder_station_destination_id = fields.Many2one('sf.agv.site', '目的接驳站')
|
||||
task_delivery_time = fields.Datetime('任务下发时间')
|
||||
task_completion_time = fields.Datetime('任务完成时间')
|
||||
delivery_duration = fields.Float('配送时长', compute='_compute_delivery_duration')
|
||||
status = fields.Selection(
|
||||
[('待下发', '待下发'), ('待配送', '待配送'), ('已配送', '已配送')], string='状态',
|
||||
default='待下发')
|
||||
production_line_state = fields.Selection(
|
||||
[('待上产线', '待上产线'), ('已上产线', '已上产线'), ('已下产线', '已下产线')],
|
||||
string='上/下产线', default='待上产线')
|
||||
cnc_program_down_state = fields.Selection([('待下发', '待下发'), ('已下发', '已下发')],
|
||||
string='CNC程序下发状态', default='待下发')
|
||||
agv_task_code = fields.Char('agv任务单号')
|
||||
|
||||
@api.onchange('route_id')
|
||||
def onchage_route(self):
|
||||
if self.route_id:
|
||||
self.feeder_station_start_id = self.route_id.start_site_id
|
||||
self.feeder_station_destination_id = self.route_id.end_site_id
|
||||
|
||||
# 工件配送
|
||||
def button_delivery(self):
|
||||
if self.status == '待下发':
|
||||
return {
|
||||
'name': _('确认'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'sf.workpiece.delivery.wizard',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_delivery_id': self.id,
|
||||
}}
|
||||
if self.cnc_program_down_state == '待下发':
|
||||
if self.route_id:
|
||||
if self.status == '待下发':
|
||||
return {
|
||||
'name': _('确认'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'sf.workpiece.delivery.wizard',
|
||||
'target': 'new',
|
||||
'context': {
|
||||
'default_delivery_id': self.id,
|
||||
}}
|
||||
else:
|
||||
raise UserError('状态为【待下发】的工件记录可进行配送')
|
||||
else:
|
||||
raise UserError('请选择任务路线再进行配送')
|
||||
else:
|
||||
raise UserError('状态为【待下发】的工件记录可进行配送')
|
||||
raise UserError(_("该制造订单还未下发CNC程序单,无法进行工件配送"))
|
||||
|
||||
# 配送至avg小车
|
||||
def _delivery_avg(self):
|
||||
config = self.env['res.config.settings'].get_values()
|
||||
positionCode_Arr = []
|
||||
if self.feeder_station_start_id:
|
||||
positionCode_Arr.append({
|
||||
'positionCode': self.feeder_station_start_id.name,
|
||||
'code': '00'
|
||||
})
|
||||
if self.feeder_station_destination_id:
|
||||
positionCode_Arr.append({
|
||||
'positionCode': self.feeder_station_destination_id.name,
|
||||
'code': '00'
|
||||
})
|
||||
res = {'reqCode': self.production_id.name, 'reqTime': '', 'clientCode': '', 'tokenCode': '',
|
||||
'taskTyp': 'F01', 'ctnrTyp': '', 'ctnrCode': '', 'wbCode': '', 'positionCodePath': [], 'podCode': '',
|
||||
'taskTyp': 'F01', 'ctnrTyp': '', 'ctnrCode': '', 'wbCode': config['wbcode'],
|
||||
'positionCodePath': positionCode_Arr,
|
||||
'podCode': '',
|
||||
'podDir': '', 'materialLot': '', 'priority': '', 'taskCode': '', 'agvCode': '', 'materialLot': '',
|
||||
'data': ''}
|
||||
config = self.env['res.config.settings'].get_values()
|
||||
try:
|
||||
logging.info('config-AGV请求路径:%s' % config['agv_rcms_url'])
|
||||
logging.info('config-json:%s' % res)
|
||||
ret = requests.post((config['agv_rcms_url']), json=res)
|
||||
config['agv_rcs_url'] = 'http://172.16.10.114:8182/rcms/services/rest/hikRpcService/genAgvSchedulingTask'
|
||||
logging.info('AGV请求路径:%s' % config['agv_rcs_url'])
|
||||
logging.info('AGV-json:%s' % res)
|
||||
headers = {'Content-Type': 'application/json'}
|
||||
ret = requests.post((config['agv_rcs_url']), json=res, headers=headers)
|
||||
ret = ret.json()
|
||||
logging.info('config-ret:%s' % ret)
|
||||
if ret['code'] == 0:
|
||||
if self.production_id.name == ret['reqCode']:
|
||||
self.write({'task_delivery_time': fields.Datetime.now(), 'status': '待配送'})
|
||||
self.write(
|
||||
{'task_delivery_time': fields.Datetime.now(), 'status': '待配送', 'agv_task_code': ret['data']})
|
||||
else:
|
||||
raise UserError(ret['message'])
|
||||
except Exception as e:
|
||||
logging.info('config-e:%s' % e)
|
||||
raise UserError("工件配送请求agv失败")
|
||||
|
||||
@api.depends('production_id.production_line_id')
|
||||
@api.onchange('production_id.production_line_id')
|
||||
def _compute_production_line_id(self):
|
||||
if self.production_id.production_line_id:
|
||||
self.production_line_id = self.production_id.production_line_id.id
|
||||
@@ -948,7 +1180,77 @@ class CMMprogram(models.Model):
|
||||
_name = 'sf.cmm.program'
|
||||
_description = "CMM程序"
|
||||
|
||||
program_path = fields.Char('程序文件路径')
|
||||
post_processing_name = fields.Char('后处理名称')
|
||||
program_date = fields.Datetime('程序日期')
|
||||
cmm_id = fields.Many2one('ir.attachment')
|
||||
sequence_number = fields.Integer('序号')
|
||||
program_name = fields.Char('程序名')
|
||||
cutting_tool_name = fields.Char('刀具名称')
|
||||
cutting_tool_no = fields.Char('刀号')
|
||||
processing_type = fields.Char('加工类型')
|
||||
margin_x_y = fields.Char('余量_X/Y')
|
||||
margin_z = fields.Char('余量_Z')
|
||||
depth_of_processing_z = fields.Char('加工深度(Z)')
|
||||
cutting_tool_extension_length = fields.Char('刀具伸出长度')
|
||||
cutting_tool_handle_type = fields.Char('刀柄型号')
|
||||
estimated_processing_time = fields.Char('预计加工时间')
|
||||
remark = fields.Text('备注')
|
||||
workorder_id = fields.Many2one('mrp.workorder', string="工单")
|
||||
production_id = fields.Many2one('mrp.production', string="制造订单")
|
||||
program_path = fields.Char('程序文件路径')
|
||||
|
||||
def cmm_program_create(self, ret, program_path, program_path_tmp):
|
||||
for obj in ret['programming_list']:
|
||||
workorder = self.env['mrp.workorder'].search([('production_id.name', '=', ret['production_order_no']),
|
||||
('processing_panel', '=', obj['processing_panel']),
|
||||
('routing_type', '=', 'CNC加工')])
|
||||
if obj['program_name'] in program_path:
|
||||
logging.info('obj:%s' % obj['program_name'])
|
||||
cmm_program = self.sudo().create({
|
||||
'workorder_id': workorder.id,
|
||||
'sequence_number': obj['sequence_number'],
|
||||
'program_name': obj['program_name'],
|
||||
'cutting_tool_name': obj['cutting_tool_name'],
|
||||
'cutting_tool_no': obj['cutting_tool_no'],
|
||||
'processing_type': obj['processing_type'],
|
||||
'margin_x_y': obj['margin_x_y'],
|
||||
'margin_z': obj['margin_z'],
|
||||
'depth_of_processing_z': obj['depth_of_processing_z'],
|
||||
'cutting_tool_extension_length': obj['cutting_tool_extension_length'],
|
||||
'cutting_tool_handle_type': obj['cutting_tool_handle_type'],
|
||||
'estimated_processing_time': obj['estimated_processing_time'],
|
||||
'remark': obj['remark'],
|
||||
'program_path': program_path.replace('/tmp', '')
|
||||
})
|
||||
cmm_program.get_cmm_program_file(program_path_tmp, cmm_program, program_path)
|
||||
|
||||
# 根据程序名和加工面匹配到ftp里对应的cmm程序名
|
||||
def get_cmm_program_file(self, serverdir, cmm_program, program_path):
|
||||
logging.info('cmm-serverdir:%s' % serverdir)
|
||||
for root, dirs, files in os.walk(serverdir):
|
||||
for f in files:
|
||||
if f in program_path:
|
||||
cmm_program_file_path = os.path.join(serverdir, root, f)
|
||||
self.write_file_cmm(cmm_program_file_path, cmm_program)
|
||||
|
||||
# 创建附件(nc文件)
|
||||
def attachment_create(self, name, data):
|
||||
attachment = self.env['ir.attachment'].create({
|
||||
'datas': base64.b64encode(data),
|
||||
'type': 'binary',
|
||||
'public': True,
|
||||
'description': '程序文件',
|
||||
'name': name
|
||||
})
|
||||
return attachment
|
||||
|
||||
# 将cmm文件存到attach的datas里
|
||||
def write_file_cmm(self, cmm_file_path, cnc):
|
||||
cmm_file_name = cmm_file_path.split('/')
|
||||
logging.info('cmm_file_name:%s' % cmm_file_name[-1])
|
||||
if os.path.exists(cmm_file_path):
|
||||
with open(cmm_file_path, 'rb') as file:
|
||||
data_bytes = file.read()
|
||||
attachment = self.attachment_create(cnc.program_name + cmm_file_name[-1], data_bytes)
|
||||
cnc.write({'cmm_id': attachment.id})
|
||||
file.close()
|
||||
else:
|
||||
return False
|
||||
|
||||
@@ -1,15 +1,14 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import logging
|
||||
import requests
|
||||
import base64
|
||||
import hashlib
|
||||
import os
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.modules import get_resource_path
|
||||
|
||||
|
||||
from OCC.Extend.DataExchange import read_step_file
|
||||
from OCC.Extend.DataExchange import write_stl_file
|
||||
# from OCC.Extend.DataExchange import read_step_file
|
||||
# from OCC.Extend.DataExchange import write_stl_file
|
||||
|
||||
|
||||
class ResProductMo(models.Model):
|
||||
@@ -107,7 +106,10 @@ class ResProductMo(models.Model):
|
||||
|
||||
@api.onchange('cutting_tool_model_id')
|
||||
def _onchange_cutting_tool_model_id(self):
|
||||
self.specification_id = False
|
||||
for item in self:
|
||||
if item:
|
||||
item.specification_id = False
|
||||
item.cutting_tool_chuck_id = item.cutting_tool_model_id.chuck_id
|
||||
|
||||
@api.onchange('cutting_tool_material_id')
|
||||
def _onchange_cutting_tool_material_id(self):
|
||||
@@ -310,7 +312,6 @@ class ResProductMo(models.Model):
|
||||
self.cutting_tool_is_safety_lock = self.specification_id.is_safe_lock
|
||||
self.cutting_tool_fit_nut_model = self.specification_id.nut
|
||||
self.cutting_tool_wrench = self.specification_id.spanner
|
||||
self.cutting_tool_chuck_id = self.specification_id.chuck_id.id
|
||||
self.cutting_tool_jump_accuracy = self.specification_id.diameter_slip_accuracy
|
||||
self.cutting_tool_taper_shank_model = self.specification_id.taper_shank_model
|
||||
self.cutting_tool_cooling_type = self.specification_id.cooling_model
|
||||
@@ -521,6 +522,9 @@ class ResProductMo(models.Model):
|
||||
string='注册状态', default='未注册')
|
||||
industry_code = fields.Char('行业编码', readonly=True)
|
||||
|
||||
# bfm下单
|
||||
manual_quotation = fields.Boolean('人工编程', default=False, readonly=True)
|
||||
|
||||
@api.constrains('tool_length')
|
||||
def _check_tool_length_size(self):
|
||||
if self.tool_length > 1000000:
|
||||
@@ -615,6 +619,7 @@ class ResProductMo(models.Model):
|
||||
'process_parameters_code') else self.get_process_parameters_id(item['process_parameters_code']),
|
||||
'model_remark': item['remark'],
|
||||
'default_code': '%s-%s' % (order_number, i),
|
||||
'manual_quotation': item['manual_quotation'] or False,
|
||||
'active': True,
|
||||
}
|
||||
copy_product_id.sudo().write(vals)
|
||||
@@ -888,6 +893,33 @@ class SfMaintenanceEquipmentAndProductTemplate(models.Model):
|
||||
vals.append(res)
|
||||
return vals[0]
|
||||
|
||||
base_coordinate_fixture_model_id = fields.Many2one('sf.fixture.model', '基坐标卡盘型号',
|
||||
domain=[('fixture_material_id', '=', '零点卡盘')])
|
||||
base_coordinate_g_coordinate = fields.Char('G坐标')
|
||||
base_coordinate_x = fields.Float('x轴', digits=(12, 3))
|
||||
base_coordinate_y = fields.Float('y轴', digits=(12, 3))
|
||||
base_coordinate_z = fields.Float('z轴', digits=(12, 3))
|
||||
|
||||
# ==========获取机床基坐标接口==========
|
||||
def get_equipment_base_coordinate(self):
|
||||
headers = {'Authorization': 'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A'}
|
||||
crea_url = "https://x24467i973.zicp.fun/AutoDeviceApi/EquipmentBaseCoordinate"
|
||||
params = {"DeviceId": self.name}
|
||||
r = requests.get(crea_url, params=params, headers=headers)
|
||||
ret = r.json()
|
||||
logging.info('register_equipment_tool:%s' % ret)
|
||||
self.write({
|
||||
'base_coordinate_fixture_model_id': ret['base_coordinate_fixture_model_id'],
|
||||
'base_coordinate_g_coordinate': ret['base_coordinate_g_coordinate'],
|
||||
'base_coordinate_x': ret['base_coordinate_x'],
|
||||
'base_coordinate_y': ret['base_coordinate_y'],
|
||||
'base_coordinate_z': ret['base_coordinate_z'],
|
||||
})
|
||||
if ret['Succeed']:
|
||||
return "机床基坐标获取成功"
|
||||
else:
|
||||
raise ValidationError("机床基坐标获取失败")
|
||||
|
||||
|
||||
class SfMaintenanceEquipmentTool(models.Model):
|
||||
_name = 'maintenance.equipment.tool'
|
||||
|
||||
@@ -17,6 +17,50 @@ from io import BytesIO
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class stockWarehouse(models.Model):
|
||||
_inherit = 'stock.warehouse'
|
||||
|
||||
subcontracting_surface_technology_pull_out_id = fields.Many2one(
|
||||
'stock.rule', '表面工艺规则1')
|
||||
subcontracting_surface_technology_pull_in_id = fields.Many2one(
|
||||
'stock.rule', '表面工艺规则2'
|
||||
)
|
||||
|
||||
def _get_global_route_rules_values(self):
|
||||
rules = super(stockWarehouse, self)._get_global_route_rules_values()
|
||||
location_virtual_id = self.env.ref(
|
||||
'sf_manufacturing.stock_location_locations_virtual_outcontract').id,
|
||||
location_pre_id = self.env['stock.location'].search(
|
||||
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id,
|
||||
rules.update({
|
||||
'subcontracting_surface_technology_pull_in_id': {
|
||||
'create_values': {
|
||||
'action': 'pull',
|
||||
'picking_type_id': self.env.ref('sf_manufacturing.outcontract_picking_in').id,
|
||||
'group_propagation_option': 'none',
|
||||
'company_id': self.company_id.id,
|
||||
'location_src_id': location_virtual_id,
|
||||
'location_dest_id': location_pre_id,
|
||||
'route_id': self._find_global_route('sf_manufacturing.route_surface_technology_outsourcing',
|
||||
_('表面工艺外协')).id,
|
||||
}
|
||||
},
|
||||
'subcontracting_surface_technology_pull_out_id': {
|
||||
'create_values': {
|
||||
'action': 'pull',
|
||||
'picking_type_id': self.env.ref('sf_manufacturing.outcontract_picking_out').id,
|
||||
'group_propagation_option': 'none',
|
||||
'company_id': self.company_id.id,
|
||||
'location_src_id': location_pre_id,
|
||||
'location_dest_id': location_virtual_id,
|
||||
'route_id': self._find_global_route('sf_manufacturing.route_surface_technology_outsourcing',
|
||||
_('表面工艺外协')).id,
|
||||
}
|
||||
}
|
||||
})
|
||||
return rules
|
||||
|
||||
|
||||
class StockRule(models.Model):
|
||||
_inherit = 'stock.rule'
|
||||
|
||||
@@ -222,6 +266,21 @@ class ProductionLot(models.Model):
|
||||
_name = 'stock.lot'
|
||||
_inherit = ['stock.lot', 'printing.utils']
|
||||
|
||||
rfid = fields.Char('Rfid', readonly=True)
|
||||
product_specification = fields.Char('规格', compute='_compute_product_specification', store=True)
|
||||
|
||||
@api.depends('product_id')
|
||||
def _compute_product_specification(self):
|
||||
for stock in self:
|
||||
if stock:
|
||||
if stock.product_id:
|
||||
if stock.product_id.categ_id.name in '刀具':
|
||||
stock.product_specification = stock.product_id.specification_id.name
|
||||
elif stock.product_id.categ_id.name in '夹具':
|
||||
stock.product_specification = stock.product_id.specification_fixture_id.name
|
||||
else:
|
||||
stock.product_specification = stock.product_id.default_code
|
||||
|
||||
@api.model
|
||||
def generate_lot_names1(self, display_name, first_lot, count):
|
||||
"""Generate `lot_names` from a string."""
|
||||
@@ -258,13 +317,15 @@ class ProductionLot(models.Model):
|
||||
"""
|
||||
now = datetime.now().strftime("%Y%m%d")
|
||||
last_serial = self.env['stock.lot'].search(
|
||||
[('company_id', '=', company.id), ('product_id', '=', product.id), ('name', 'like', now)],
|
||||
[('company_id', '=', company.id), ('product_id', '=', product.id)],
|
||||
limit=1, order='id DESC')
|
||||
if product.cutting_tool_model_id:
|
||||
split_codes = product.cutting_tool_model_id.code.split('-')
|
||||
if not last_serial:
|
||||
return "%s-%s%03d" % (product.cutting_tool_model_id.code[:-12], now, 1)
|
||||
return "%s-T-%s-%s-%03d" % (split_codes[0], now, product.specification_id.name, 1)
|
||||
else:
|
||||
return "%s-%s%03d" % (product.cutting_tool_model_id.code[:-12], now, int(last_serial.name[-3:]) + 2)
|
||||
return "%s-T-%s-%s-%03d" % (
|
||||
split_codes[0], now, product.specification_id.name, int(last_serial.name[-3:]) + 1)
|
||||
else:
|
||||
raise ValidationError('该刀具物料产品的型号字段为空,请补充完整!!!')
|
||||
|
||||
@@ -282,7 +343,8 @@ class ProductionLot(models.Model):
|
||||
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:
|
||||
return "%s-%s%03d" % (product.cutting_tool_model_id.code[:-12], now, 1)
|
||||
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)
|
||||
|
||||
qr_code_image = fields.Binary(string='二维码', compute='_generate_qr_code')
|
||||
@@ -319,7 +381,7 @@ class ProductionLot(models.Model):
|
||||
# port = 9100 # 可以根据实际情况修改
|
||||
|
||||
# 获取默认打印机配置
|
||||
printer_config = self.env['printer.configuration'].search([('model', '=', self._name)], limit=1)
|
||||
printer_config = self.env['printer.configuration'].sudo().search([('model', '=', self._name)], limit=1)
|
||||
if not printer_config:
|
||||
raise UserError('请先配置打印机')
|
||||
host = printer_config.printer_id.ip_address
|
||||
@@ -366,10 +428,10 @@ class StockPicking(models.Model):
|
||||
# 设置外协出入单的名称
|
||||
def _get_name_Res(self, rescode):
|
||||
last_picking = self.sudo().search([('name', 'like', rescode)], order='create_date DESC', limit=1)
|
||||
logging.info('编号:' + last_picking.name)
|
||||
if not last_picking:
|
||||
num = "%04d" % 1
|
||||
else:
|
||||
logging.info('编号:' + last_picking.name)
|
||||
m = int(last_picking.name[-3:]) + 1
|
||||
num = "%04d" % m
|
||||
return '%s%s' % (rescode, num)
|
||||
@@ -419,7 +481,7 @@ class StockPicking(models.Model):
|
||||
location_id = self.env.ref(
|
||||
'sf_manufacturing.stock_location_locations_virtual_outcontract').id,
|
||||
location_dest_id = self.env['stock.location'].search(
|
||||
[('barcode', '=', 'WH-PREPRODUCTION')]).id,
|
||||
[('barcode', 'ilike', 'WH-PREPRODUCTION')]).id,
|
||||
outcontract_picking_type_in = self.env.ref(
|
||||
'sf_manufacturing.outcontract_picking_in').id,
|
||||
outcontract_picking_type_out = self.env.ref(
|
||||
@@ -480,6 +542,65 @@ class ReStockMove(models.Model):
|
||||
else:
|
||||
raise UserError(_("没有可打印的标签数据"))
|
||||
|
||||
def action_show_details(self):
|
||||
""" Returns an action that will open a form view (in a popup) allowing to work on all the
|
||||
move lines of a particular move. This form view is used when "show operations" is not
|
||||
checked on the picking type.
|
||||
"""
|
||||
self.ensure_one()
|
||||
|
||||
# If "show suggestions" is not checked on the picking type, we have to filter out the
|
||||
# reserved move lines. We do this by displaying `move_line_nosuggest_ids`. We use
|
||||
# different views to display one field or another so that the webclient doesn't have to
|
||||
# fetch both.
|
||||
if self.picking_type_id.show_reserved:
|
||||
view = self.env.ref('stock.view_stock_move_operations')
|
||||
else:
|
||||
view = self.env.ref('stock.view_stock_move_nosuggest_operations')
|
||||
|
||||
if self.product_id.tracking == "serial" and self.state == "assigned":
|
||||
print(self.origin)
|
||||
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)
|
||||
|
||||
return {
|
||||
'name': _('Detailed Operations'),
|
||||
'type': 'ir.actions.act_window',
|
||||
'view_mode': 'form',
|
||||
'res_model': 'stock.move',
|
||||
'views': [(view.id, 'form')],
|
||||
'view_id': view.id,
|
||||
'target': 'new',
|
||||
'res_id': self.id,
|
||||
'context': dict(
|
||||
self.env.context,
|
||||
show_owner=self.picking_type_id.code != 'incoming',
|
||||
show_lots_m2o=self.has_tracking != 'none' and (
|
||||
self.picking_type_id.use_existing_lots or self.state == 'done' or self.origin_returned_move_id.id),
|
||||
# able to create lots, whatever the value of ` use_create_lots`.
|
||||
show_lots_text=self.has_tracking != 'none' and self.picking_type_id.use_create_lots and not self.picking_type_id.use_existing_lots and self.state != 'done' and not self.origin_returned_move_id.id,
|
||||
show_source_location=self.picking_type_id.code != 'incoming',
|
||||
show_destination_location=self.picking_type_id.code != 'outgoing',
|
||||
show_package=not self.location_id.usage == 'supplier',
|
||||
show_reserved_quantity=self.state != 'done' and not self.picking_id.immediate_transfer and self.picking_type_id.code != 'incoming'
|
||||
),
|
||||
}
|
||||
|
||||
def _get_tool_next_serial(self, company, product, origin):
|
||||
"""Return the next serial number to be attributed to the product."""
|
||||
if product.tracking == "serial":
|
||||
last_serial = self.env['stock.lot'].search(
|
||||
[('company_id', '=', company.id), ('product_id', '=', product.id), ('name', 'ilike', origin)],
|
||||
limit=1, order='id DESC')
|
||||
split_codes = product.cutting_tool_model_id.code.split('-')
|
||||
if last_serial:
|
||||
return "%s-T-%s-%s-%03d" % (
|
||||
split_codes[0], origin, product.specification_id.name, int(last_serial.name[-3:]) + 1)
|
||||
else:
|
||||
return "%s-T-%s-%s-%03d" % (split_codes[0], origin, product.specification_id.name, 1)
|
||||
|
||||
|
||||
class ReStockQuant(models.Model):
|
||||
_inherit = 'stock.quant'
|
||||
|
||||
BIN
sf_manufacturing/security/img.png
Normal file
BIN
sf_manufacturing/security/img.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 14 KiB |
@@ -130,3 +130,6 @@ access_mrp_workcenter_productivity,mrp.workcenter.productivity,mrp.model_mrp_wor
|
||||
access_maintenance_equipment_tool_group_plan_dispatch,maintenance.equipment.tool,sf_manufacturing.model_maintenance_equipment_tool,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_workpiece_delivery_group_plan_dispatch,sf.workpiece.delivery,sf_manufacturing.model_sf_workpiece_delivery,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_agv_site_group_sf_order_user,sf_agv_site_group_sf_order_user,model_sf_agv_site,sf_base.group_sf_order_user,1,1,1,0
|
||||
access_sf_agv_task_route_group_sf_order_user,sf_agv_task_route_group_sf_order_user,model_sf_agv_task_route,sf_base.group_sf_order_user,1,1,1,0
|
||||
|
59
sf_manufacturing/views/agv_setting_views.xml
Normal file
59
sf_manufacturing/views/agv_setting_views.xml
Normal file
@@ -0,0 +1,59 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- agv站点 -->
|
||||
<record id="view_agv_site_tree" model="ir.ui.view">
|
||||
<field name="name">agv站点</field>
|
||||
<field name="model">sf.agv.site</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom">
|
||||
<field name="number" required="1"/>
|
||||
<field name="name" required="1"/>
|
||||
<field name="owning_region" required="1"/>
|
||||
<field name="state" required="1"/>
|
||||
<field name="divide_the_work" required="1"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_agv_site_form" model="ir.actions.act_window">
|
||||
<field name="name">AGV站点</field>
|
||||
<field name="res_model">sf.agv.site</field>
|
||||
<field name="view_mode">tree</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_action_agv_site"
|
||||
parent="sf_base.menu_sf_base"
|
||||
name="AGV站点"
|
||||
sequence="12"
|
||||
action="action_agv_site_form"/>
|
||||
|
||||
<!-- agv任务路线 -->
|
||||
<record id="view_agv_task_route_tree" model="ir.ui.view">
|
||||
<field name="name">AGV任务路线</field>
|
||||
<field name="model">sf.agv.task.route</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree editable="bottom">
|
||||
<field name="name" required="1"/>
|
||||
<field name="type" readonly="1"/>
|
||||
<field name="start_site_id" required="1" options="{'no_create': True}" string="起点接驳站"/>
|
||||
<field name="end_site_id" required="1" options="{'no_create': True}" string="终点接驳站"/>
|
||||
<field name="destination_production_line_id" required="1" options="{'no_create': True}"/>
|
||||
<field name="priority" widget="priority"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_agv_task_route_form" model="ir.actions.act_window">
|
||||
<field name="name">AGV任务路线</field>
|
||||
<field name="res_model">sf.agv.task.route</field>
|
||||
<field name="view_mode">tree</field>
|
||||
</record>
|
||||
|
||||
<menuitem id="menu_action_agv_task_route"
|
||||
parent="sf_base.menu_sf_base"
|
||||
name="AGV任务路线"
|
||||
sequence="13"
|
||||
action="action_agv_task_route_form"/>
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -422,7 +422,8 @@
|
||||
|
||||
<div name="product_specification_id" class="mt-1">
|
||||
规格:
|
||||
<field name="specification_id"></field>
|
||||
<field name="specification_id"/>
|
||||
<field name="specification_fixture_id"/>
|
||||
</div>
|
||||
<t t-if="record.default_code.value">[<field name="default_code"/>]
|
||||
</t>
|
||||
|
||||
@@ -46,6 +46,9 @@
|
||||
<attribute name="invisible">1</attribute>
|
||||
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='name']" position="after">
|
||||
<field name="production_id"/>
|
||||
</xpath>
|
||||
<!-- <button name="button_start" type="object" string="Start" class="btn-success"-->
|
||||
<!-- attrs="{'invisible': ['|', '|', '|', ('production_state','in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')), ('is_user_working', '!=', False)]}"/>-->
|
||||
<!-- <button name="button_pending" type="object" string="Pause" class="btn-warning"-->
|
||||
@@ -104,22 +107,20 @@
|
||||
<field name='user_permissions' invisible="1"/>
|
||||
<field name='name' invisible="1"/>
|
||||
<field name='is_delivery' invisible="1"/>
|
||||
<!-- 工单form页面的开始停工按钮等 -->
|
||||
<!-- 工单form页面的开始停工按钮等 -->
|
||||
<button name="button_start" type="object" string="开始" class="btn-success"
|
||||
attrs="{'invisible': ['|', '|', '|', '|','|', ('production_state','in', ('draft', 'done',
|
||||
'cancel')), ('working_state', '=', 'blocked'), ('state', 'in', ('done', 'cancel')),
|
||||
('is_user_working', '!=', False),('user_permissions','=',False), ('routing_type', '=', 'CNC加工')]}"
|
||||
attrs="{'invisible': ['|', ('production_state', '!=', 'pending_processing'), ('state','!=','ready')]}"
|
||||
groups="sf_base.group_sf_mrp_user"/>
|
||||
<button name="button_pending" type="object" string="暂停" class="btn-warning"
|
||||
groups="sf_base.group_sf_mrp_user"
|
||||
attrs="{'invisible': ['|', '|','|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}"/>
|
||||
attrs="{'invisible': ['|', ('production_state', '!=', 'pending_processing'), ('state','!=','progress')]}"
|
||||
groups="sf_base.group_sf_mrp_user"/>
|
||||
<button name="button_finish" type="object" string="完成" class="btn-success"
|
||||
groups="sf_base.group_sf_mrp_user"
|
||||
attrs="{'invisible': ['|', '|','|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'), ('is_user_working', '=', False), ('routing_type', '=', 'CNC加工')]}"/>
|
||||
attrs="{'invisible': ['|', ('production_state', '!=', 'pending_processing'), ('state','!=','progress')]}"
|
||||
groups="sf_base.group_sf_mrp_user" confirm="是否确认完工"/>
|
||||
<button name="%(mrp.act_mrp_block_workcenter_wo)d" type="action" string="停工"
|
||||
context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
|
||||
groups="sf_base.group_sf_mrp_user"
|
||||
attrs="{'invisible': ['|', '|','|', '|', ('production_state', 'in', ('draft', 'done', 'cancel')), ('working_state', '=', 'blocked'),('user_permissions','=',False),('state','=','done'), ('routing_type', '=', 'CNC加工')]}"/>
|
||||
attrs="{'invisible': ['|', ('production_state', '!=', 'pending_processing'), ('state','!=','progress')]}"/>
|
||||
<button name="button_unblock" type="object" string="Unblock"
|
||||
context="{'default_workcenter_id': workcenter_id}" class="btn-danger"
|
||||
groups="sf_base.group_sf_mrp_user"
|
||||
@@ -184,10 +185,10 @@
|
||||
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
|
||||
<field name="functional_fixture_type_id"
|
||||
attrs='{"invisible": [("routing_type","!=","装夹预调")]}'/>
|
||||
<field name="rfid_code" force_save="1" readonly="1" class="customRFID"
|
||||
|
||||
<field name="rfid_code" force_save="1" readonly="1" cache="True"
|
||||
attrs="{'invisible': [('rfid_code_old', '!=', False)]}"/>
|
||||
<field name="rfid_code_old" readonly="1" attrs="{'invisible': [('rfid_code_old', '=', False)]}"/>
|
||||
<script src="/sf_manufacturing/static/src/js/customRFID.js"></script>
|
||||
</group>
|
||||
<!-- <group>-->
|
||||
<!-- <div>-->
|
||||
@@ -209,12 +210,12 @@
|
||||
<field name="programming_state" readonly="1"
|
||||
attrs='{"invisible": [("programming_no","=",False)]}'/>
|
||||
</group>
|
||||
<group>
|
||||
<div class="col-12 col-lg-6 o_setting_box" style="white-space: nowrap">
|
||||
<button type="object" class="oe_highlight" name="fetchCNC" string="获取CNC程序代码"
|
||||
/>
|
||||
</div>
|
||||
</group>
|
||||
<!-- <group>-->
|
||||
<!-- <div class="col-12 col-lg-6 o_setting_box" style="white-space: nowrap">-->
|
||||
<!-- <button type="object" class="oe_highlight" name="fetchCNC" string="获取CNC程序代码"-->
|
||||
<!-- />-->
|
||||
<!-- </div>-->
|
||||
<!-- </group>-->
|
||||
</page>
|
||||
</xpath>
|
||||
<!-- <page string="Components" name="components">-->
|
||||
@@ -242,6 +243,7 @@
|
||||
<!-- </page>-->
|
||||
<page string="工件装夹" attrs='{"invisible": [("routing_type","!=","装夹预调")]}'>
|
||||
<group>
|
||||
<field name="_barcode_scanned" widget="barcode_handler"/>
|
||||
<group string="卡盘">
|
||||
<field name="chuck_serial_number"/>
|
||||
<field name="chuck_name"/>
|
||||
@@ -250,7 +252,6 @@
|
||||
<field name="chuck_model_id"/>
|
||||
</group>
|
||||
<group string="托盘">
|
||||
<field name="_barcode_scanned" widget="barcode_handler"/>
|
||||
<field name="tray_serial_number" readonly="1" string="序列号"/>
|
||||
<field name="tray_product_id" readonly="1" string="名称"/>
|
||||
<field name="tray_brand_id" readonly="1" string="品牌"/>
|
||||
@@ -407,8 +408,11 @@
|
||||
</div>
|
||||
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<field name="data_state" invisible="1"/>
|
||||
<button type="object" class="oe_highlight" name="get_three_check_datas" string="获取数据"
|
||||
attrs='{"invisible": ["|", "|", "|", ("material_center_point","!=",False),("state","!=","progress"),("user_permissions","=",False), ("data_state", "=", True)]}'/>
|
||||
<button type="object" class="oe_highlight" name="getcenter" string="计算定位"
|
||||
attrs='{"invisible": ["|","|",("material_center_point","!=",False),("state","!=","progress"),("user_permissions","=",False)]}'/>
|
||||
attrs='{"invisible": ["|","|", "|",("material_center_point","!=",False),("state","!=","progress"),("user_permissions","=",False), ("data_state", "=", False)]}'/>
|
||||
</div>
|
||||
|
||||
<group>
|
||||
@@ -421,8 +425,10 @@
|
||||
<tree editable="bottom">
|
||||
<field name="production_id" invisible="1"/>
|
||||
<field name="workpiece_code"/>
|
||||
<field name="feeder_station_start" force_save="1"/>
|
||||
<field name="feeder_station_destination" force_save="1"/>
|
||||
<field name="route_id" options="{'no_create': True}"/>
|
||||
<field name="feeder_station_start_id" readonly="1" force_save="1"/>
|
||||
<field name="feeder_station_destination_id" readonly="1" force_save="1"/>
|
||||
<field name="cnc_program_down_state" readonly="1"/>
|
||||
<field name="production_line_id"/>
|
||||
<field name="task_delivery_time" readonly="1"/>
|
||||
<field name="task_completion_time" readonly="1"/>
|
||||
@@ -437,16 +443,17 @@
|
||||
<field name="results" invisible="1"/>
|
||||
<page string="后置三元检测" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||
<group>
|
||||
<field name="test_result" readonly="1" attrs='{"invisible":[("results","!=",False)]}'/>
|
||||
<field name="test_results" attrs='{"invisible":[("results","!=",False)]}'/>
|
||||
<field name="is_remanufacture" attrs='{"invisible":[("test_results","=","合格")]}'/>
|
||||
<field name="results" readonly="1" attrs='{"invisible":[("results","!=","合格")]}'/>
|
||||
<field name="detection_report" attrs='{"invisible":[("results","!=",False)]}'
|
||||
widget="pdf_viewer"/>
|
||||
</group>
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<button type="object" class="oe_highlight" name="recreateManufacturingOrWorkerOrder"
|
||||
string="检测确认"
|
||||
attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/>
|
||||
</div>
|
||||
<!-- <div class="col-12 col-lg-6 o_setting_box">-->
|
||||
<!-- <button type="object" class="oe_highlight" name="recreateManufacturingOrWorkerOrder"-->
|
||||
<!-- string="检测确认"-->
|
||||
<!-- attrs='{"invisible": ["|","|",("state","!=","progress"),("user_permissions","=",False),("results","=","合格")]}'/>-->
|
||||
<!-- </div>-->
|
||||
</page>
|
||||
</xpath>
|
||||
<xpath expr="//page[1]" position="before">
|
||||
@@ -476,9 +483,19 @@
|
||||
<page string="CMM程序" attrs='{"invisible": [("routing_type","!=","CNC加工")]}'>
|
||||
<field name="cmm_ids" widget="one2many" string="CMM程序">
|
||||
<tree>
|
||||
<field name="program_path"/>
|
||||
<field name="program_date"/>
|
||||
<field name="post_processing_name"/>
|
||||
<field name="sequence_number"/>
|
||||
<field name="program_name"/>
|
||||
<field name="cmm_id" string="文件"/>
|
||||
<field name="cutting_tool_name"/>
|
||||
<field name="cutting_tool_no"/>
|
||||
<field name="processing_type"/>
|
||||
<field name="margin_x_y"/>
|
||||
<field name="margin_z"/>
|
||||
<field name="depth_of_processing_z"/>
|
||||
<field name="cutting_tool_extension_length"/>
|
||||
<field name="cutting_tool_handle_type"/>
|
||||
<field name="estimated_processing_time"/>
|
||||
<field name="remark"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
@@ -510,6 +527,8 @@
|
||||
<field name="is_ok"/>
|
||||
<field name="processing_user_id"/>
|
||||
<field name="inspection_user_id"/>
|
||||
<field name="save_name" widget="CopyClipboardChar"
|
||||
attrs="{'invisible':[('routing_type','!=','装夹预调')]}"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
@@ -540,7 +559,7 @@
|
||||
<field name="name">工件配送</field>
|
||||
<field name="model">sf.workpiece.delivery</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="工件配送">
|
||||
<tree string="工件配送" editable="bottom" class="center" create="0" delete="0">
|
||||
<header>
|
||||
<button name="button_delivery" type="object" string="配送" class="oe_highlight"/>
|
||||
</header>
|
||||
@@ -550,11 +569,13 @@
|
||||
decoration-danger="status == '待配送'"/>
|
||||
<field name="production_id" string="工件编码"/>
|
||||
<field name="workpiece_code"/>
|
||||
<field name="production_line_id"/>
|
||||
<field name="feeder_station_start"/>
|
||||
<field name="feeder_station_destination"/>
|
||||
<field name="task_delivery_time"/>
|
||||
<field name="task_completion_time"/>
|
||||
<field name="production_line_id" options="{'no_create': True}"/>
|
||||
<field name="route_id" options="{'no_create': True}"/>
|
||||
<field name="feeder_station_start_id" readonly="1" force_save="1"/>
|
||||
<field name="feeder_station_destination_id" readonly="1" force_save="1"/>
|
||||
<field name="cnc_program_down_state" readonly="1"/>
|
||||
<field name="task_delivery_time" readonly="1"/>
|
||||
<field name="task_completion_time" readonly="1"/>
|
||||
<field name="delivery_duration" widget="float_time"/>
|
||||
</tree>
|
||||
</field>
|
||||
@@ -567,16 +588,19 @@
|
||||
<search string="工件配送">
|
||||
<field name="production_id"/>
|
||||
<field name="workpiece_code"/>
|
||||
<field name="feeder_station_start"/>
|
||||
<field name="feeder_station_start_id"/>
|
||||
<field name="production_line_id"/>
|
||||
<field name="task_delivery_time"/>
|
||||
<field name="feeder_station_destination"/>
|
||||
<field name="feeder_station_destination_id"/>
|
||||
<field name="task_completion_time"/>
|
||||
<field name="delivery_duration"/>
|
||||
<field name="status"/>
|
||||
<searchpanel>
|
||||
<field name="production_line_id" icon="fa-building" enable_counters="1"/>
|
||||
<field name="status" icon="fa-building" enable_counters="1"/>
|
||||
<field name="production_line_state" icon="fa-building" enable_counters="1"/>
|
||||
<field name="cnc_program_down_state" icon="fa-building" enable_counters="1"/>
|
||||
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
|
||||
@@ -1,23 +1,38 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
|
||||
设备增加刀具库位table
|
||||
<!-- 设备增加刀具库位table-->
|
||||
<record id="sf_manufacturing_hr_equipment_view_form" model="ir.ui.view">
|
||||
<field name="name">sf_manufacturing_equipment.form</field>
|
||||
<field name="model">maintenance.equipment</field>
|
||||
<field name="inherit_id" ref="sf_maintenance.sf_hr_equipment_view_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//page[@name='sf_equipment']" position="after">
|
||||
<page string="标准刀库" name="sf_equipment_product_template"
|
||||
attrs="{'invisible': [('equipment_type', '!=', '机床')]}">
|
||||
<field name = 'product_template_ids' >
|
||||
<tree editable='bottom'>
|
||||
<field name="code"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<page string="机床基坐标" name="sf_equipment_base_coordinate"
|
||||
attrs="{'invisible': [('equipment_type', '!=', '机床')]}">
|
||||
<button name="get_equipment_base_coordinate" string="获取基坐标数据" type="object"
|
||||
class="oe_highlight"/>
|
||||
<separator invisible="0"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="base_coordinate_fixture_model_id" options="{'no_create': True}"/>
|
||||
<field name="base_coordinate_g_coordinate"/>
|
||||
<field name="base_coordinate_x"/>
|
||||
<field name="base_coordinate_y"/>
|
||||
<field name="base_coordinate_z"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
<page string="标准刀库" name="sf_equipment_product_template"
|
||||
attrs="{'invisible': [('equipment_type', '!=', '机床')]}">
|
||||
<field name='product_template_ids'>
|
||||
<tree editable='bottom'>
|
||||
<field name="code"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
</odoo>
|
||||
@@ -13,6 +13,12 @@
|
||||
<button string="打印二维码" name="print_single_method" type="object" class="btn-primary"/>
|
||||
</header>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='product_id']" position="before">
|
||||
<field name="rfid" attrs="{'invisible': [('rfid', '=', False)]}"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='product_id']" position="after">
|
||||
<field name="product_specification"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -5,14 +5,18 @@
|
||||
<field name="model">sf.workpiece.delivery.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<field name="delivery_id" invisible="True"/>
|
||||
<field name="workorder_id" invisible="True"/>
|
||||
|
||||
<group>
|
||||
<field name="delivery_id" invisible="True"/>
|
||||
<field name="workorder_id" invisible="True"/>
|
||||
<field name="route_id" required="1" options="{'no_create': True}"/>
|
||||
</group>
|
||||
<div>
|
||||
是否确定配送?
|
||||
<field name="is_ok"/>
|
||||
确认上述信息正确无误.
|
||||
</div>
|
||||
<footer>
|
||||
<button string="确认" name="confirm" type="object" class="oe_highlight"/>
|
||||
<button string="确认配送" name="confirm" type="object" class="oe_highlight"
|
||||
attrs="{'invisible':[('is_ok','=',False)]}"/>
|
||||
<button string="取消" class="btn btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
|
||||
@@ -11,10 +11,11 @@ class WorkpieceDeliveryWizard(models.TransientModel):
|
||||
|
||||
delivery_id = fields.Many2one('sf.workpiece.delivery', string='配送')
|
||||
workorder_id = fields.Many2one('mrp.workorder', string='工单')
|
||||
route_id = fields.Many2one('sf.agv.task.route', '任务路线')
|
||||
is_ok = fields.Boolean('确认上述信息正确无误.')
|
||||
|
||||
def confirm(self):
|
||||
if self.workorder_id:
|
||||
self.workorder_id.workpiece_delivery_ids._delivery_avg()
|
||||
else:
|
||||
self.delivery_id._delivery_avg()
|
||||
|
||||
|
||||
@@ -44,12 +44,18 @@ class Sf_Mrs_Connect(http.Controller):
|
||||
return json.JSONEncoder().encode(res)
|
||||
logging.info('创建cnc工单')
|
||||
program_path_tmp = os.path.join('/tmp', ret['folder_name'], 'return', r)
|
||||
# program_path_tmp = "C://Users//43484//Desktop//机企猫工作文档//其他//model_analysis"
|
||||
files = os.listdir(program_path_tmp)
|
||||
for f in files:
|
||||
program_path = os.path.join(program_path_tmp, f)
|
||||
logging.info('cnc程序路径 :%s' % program_path)
|
||||
if f.endswith(".doc"):
|
||||
# 插入cmm程序数据
|
||||
request.env['sf.cmm.program'].with_user(
|
||||
request.env.ref("base.user_admin")).cmm_program_create(ret, program_path, program_path_tmp)
|
||||
request.env['sf.cnc.processing'].with_user(
|
||||
request.env.ref("base.user_admin")).cnc_processing_create(cnc_production, ret, program_path,program_path_tmp)
|
||||
request.env.ref("base.user_admin")).cnc_processing_create(cnc_production, ret, program_path,
|
||||
program_path_tmp)
|
||||
return json.JSONEncoder().encode(res)
|
||||
else:
|
||||
res = {'status': 0, 'message': '该制造订单暂未开始'}
|
||||
|
||||
@@ -21,14 +21,32 @@ class FtpController():
|
||||
except Exception:
|
||||
logging.info("ftp连接失败")
|
||||
|
||||
def file_exists(self, path):
|
||||
# 检查文件是否存在于FTP服务器上
|
||||
try:
|
||||
self.ftp.cwd(os.path.dirname(path))
|
||||
files = self.ftp.nlst()
|
||||
return os.path.basename(path) in files
|
||||
except Exception as e:
|
||||
logging.error(f"Error checking file: {e}")
|
||||
return False
|
||||
|
||||
# 下载目录下的文件
|
||||
def download_file_tree(self, target_dir, serverdir):
|
||||
if not os.path.exists(serverdir):
|
||||
os.makedirs(serverdir)
|
||||
try:
|
||||
logging.info("进入FTP目录 ")
|
||||
self.ftp.cwd(target_dir) # 切换工作路径
|
||||
logging.info('FTP目录:%s' % target_dir)
|
||||
logging.info('目录:%s' % target_dir)
|
||||
target_dir1 = target_dir.split('/')
|
||||
logging.info('目录1:%s' % target_dir1[1])
|
||||
self.ftp.cwd(target_dir1[1]) # 切换工作路径
|
||||
logging.info('目录2:%s' % target_dir1[2])
|
||||
self.ftp.cwd(target_dir1[2]) # 切换工作路径
|
||||
logging.info('目录3:%s' % target_dir1[3])
|
||||
self.ftp.cwd(target_dir1[3]) # 切换工作路径
|
||||
logging.info('目录4:%s' % target_dir1[4])
|
||||
self.ftp.cwd(target_dir1[4]) # 切换工作路径
|
||||
remotenames = self.ftp.nlst()
|
||||
logging.info('FTP目录文件:%s' % remotenames)
|
||||
for file in remotenames:
|
||||
@@ -38,6 +56,9 @@ class FtpController():
|
||||
return 1
|
||||
except Exception:
|
||||
return 0
|
||||
finally:
|
||||
self.ftp.quit()
|
||||
logging.info("ftp已关闭")
|
||||
|
||||
# 下载目录下的检测文件
|
||||
def download_reportfile_tree(self, target_dir, serverdir, reportpath):
|
||||
@@ -51,6 +72,8 @@ class FtpController():
|
||||
self.ftp.cwd(target_dir1[1]) # 切换工作路径
|
||||
logging.info('目录2:%s' % target_dir1[2])
|
||||
self.ftp.cwd(target_dir1[2]) # 切换工作路径
|
||||
logging.info('目录2:%s' % target_dir1[3])
|
||||
self.ftp.cwd(target_dir1[3]) # 切换工作路径
|
||||
remotenames = self.ftp.nlst()
|
||||
logging.info('FTP目录检测报告文件:%s' % remotenames)
|
||||
for filename in remotenames:
|
||||
|
||||
@@ -13,9 +13,13 @@ class ResConfigSettings(models.TransientModel):
|
||||
token = fields.Char(string='TOKEN', default='b811ac06-3f00-11ed-9aed-0242ac110003')
|
||||
sf_secret_key = fields.Char(string='密钥', default='wBmxej38OkErKhD6')
|
||||
sf_url = fields.Char(string='访问地址', default='https://sf.cs.jikimo.com')
|
||||
agv_rcms_url = fields.Char(string='avg_rcms访问地址',
|
||||
default='http://IP:PORT/rcms/services/rest/hikRpcService/genAgvSchedulingTask')
|
||||
agv_rcs_url = fields.Char(string='avg_rcs访问地址', default='http://IP:PORT/xxx/agv/agvCallbackService/agvCallback')
|
||||
agv_rcs_url = fields.Char(string='avg_rcs访问地址',
|
||||
default='http://172.16.10.114:8182/rcms/services/rest/hikRpcService/genAgvSchedulingTask')
|
||||
center_control_url = fields.Char(string='中控访问地址',
|
||||
default='http://172.16.21.50:8001')
|
||||
wbcode = fields.Char('地码')
|
||||
agv_code = fields.Char(string='agv编号')
|
||||
task_type_no = fields.Char('任务单类型编号')
|
||||
model_parser_url = fields.Char('特征识别路径')
|
||||
ftp_host = fields.Char(string='FTP的ip')
|
||||
ftp_port = fields.Char(string='FTP端口')
|
||||
@@ -94,8 +98,10 @@ class ResConfigSettings(models.TransientModel):
|
||||
token = config.get_param('token', default='')
|
||||
sf_secret_key = config.get_param('sf_secret_key', default='')
|
||||
sf_url = config.get_param('sf_url', default='')
|
||||
agv_rcms_url = config.get_param('agv_rcms_url', default='')
|
||||
agv_rcs_url = config.get_param('agv_rcs_url', default='')
|
||||
wbcode = config.get_param('wbcode', default='')
|
||||
agv_code = config.get_param('agv_code', default='')
|
||||
center_control_url = config.get_param('center_control_url', default='')
|
||||
ftp_host = config.get_param('ftp_host', default='')
|
||||
ftp_port = config.get_param('ftp_port', default='')
|
||||
ftp_user = config.get_param('ftp_user', default='')
|
||||
@@ -105,8 +111,10 @@ class ResConfigSettings(models.TransientModel):
|
||||
token=token,
|
||||
sf_secret_key=sf_secret_key,
|
||||
sf_url=sf_url,
|
||||
agv_rcms_url=agv_rcms_url,
|
||||
agv_rcs_url=agv_rcs_url,
|
||||
wbcode=wbcode,
|
||||
agv_code=agv_code,
|
||||
center_control_url=center_control_url,
|
||||
ftp_host=ftp_host,
|
||||
ftp_port=ftp_port,
|
||||
ftp_user=ftp_user,
|
||||
@@ -120,8 +128,10 @@ class ResConfigSettings(models.TransientModel):
|
||||
ir_config.set_param("token", self.token or "")
|
||||
ir_config.set_param("sf_secret_key", self.sf_secret_key or "")
|
||||
ir_config.set_param("sf_url", self.sf_url or "")
|
||||
ir_config.set_param("agv_rcms_url", self.agv_rcms_url or "")
|
||||
ir_config.set_param("agv_rcs_url", self.agv_rcs_url or "")
|
||||
ir_config.set_param("wbcode", self.wbcode or "")
|
||||
ir_config.set_param("agv_code", self.agv_code or "")
|
||||
ir_config.set_param("center_control_url", self.center_control_url or "")
|
||||
ir_config.set_param("ftp_host", self.ftp_host or "")
|
||||
ir_config.set_param("ftp_port", self.ftp_port or "")
|
||||
ir_config.set_param("ftp_user", self.ftp_user or "")
|
||||
|
||||
@@ -52,8 +52,6 @@ class MrStaticResourceDataSync(models.Model):
|
||||
logging.info("夹具型号已每日同步成功")
|
||||
self.env['sf.fixture.materials.basic.parameters'].sync_fixture_materials_basic_parameters_yesterday()
|
||||
logging.info("夹具型号基本参数已每日同步成功")
|
||||
self.env['sf.functional.fixture.type'].sync_fixture_materials_basic_parameters_yesterday()
|
||||
logging.info("夹具型号基本参数已每日同步成功")
|
||||
self.env['sf.functional.fixture.type'].sync_functional_fixture_type_yesterday()
|
||||
logging.info("功能夹具类型已每日同步成功")
|
||||
self.env['sf.cutting.tool.material'].sync_cutting_tool_material_yesterday()
|
||||
@@ -593,6 +591,7 @@ class MachineBrand(models.Model):
|
||||
if not brand:
|
||||
self.create({
|
||||
"name": item['name'],
|
||||
"active": item['active'],
|
||||
"code": item['code'],
|
||||
"remark": item['remark'],
|
||||
"image_brand": '' if not item['image_brand'] else base64.b64decode(item['image_brand']),
|
||||
@@ -601,6 +600,7 @@ class MachineBrand(models.Model):
|
||||
})
|
||||
else:
|
||||
brand.name = item['name']
|
||||
brand.active = item['active']
|
||||
brand.remark = item['remark']
|
||||
brand.image_brand = '' if not item['image_brand'] else base64.b64decode(item['image_brand'])
|
||||
brand.tag_ids = self.env['sf.machine.brand.tags'].search(
|
||||
@@ -1952,24 +1952,22 @@ class CuttingSpeed(models.Model):
|
||||
'active': item['active'],
|
||||
})
|
||||
else:
|
||||
if item['active'] is False:
|
||||
item.write({'active': False})
|
||||
else:
|
||||
self.write({
|
||||
'execution_standard_id': self.env['sf.international.standards'].search(
|
||||
[('code', '=', item['execution_standard_code'])]).id,
|
||||
'material_name_id': self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['material_name'])]).id,
|
||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||
[('name', '=', item['cutting_width_depth'])]).id,
|
||||
'ability_feature_library': self.env['maintenance.equipment.image'].search(
|
||||
[('name', '=', item['ability_feature_library']), ('type', '=', '加工能力')]).id,
|
||||
'material_code': item['material_code'],
|
||||
'material_grade': item['material_grade'],
|
||||
'tensile_strength': item['tensile_strength'],
|
||||
'hardness': item['hardness'],
|
||||
'cutting_speed': item['cutting_speed'],
|
||||
'application': item['application'], })
|
||||
cutting_speed.write({
|
||||
'execution_standard_id': self.env['sf.international.standards'].search(
|
||||
[('code', '=', item['execution_standard_code'])]).id,
|
||||
'material_name_id': self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['material_name'])]).id,
|
||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||
[('name', '=', item['cutting_width_depth'])]).id,
|
||||
'ability_feature_library': self.env['maintenance.equipment.image'].search(
|
||||
[('name', '=', item['ability_feature_library']), ('type', '=', '加工能力')]).id,
|
||||
'material_code': item['material_code'],
|
||||
'material_grade': item['material_grade'],
|
||||
'tensile_strength': item['tensile_strength'],
|
||||
'hardness': item['hardness'],
|
||||
'cutting_speed': item['cutting_speed'],
|
||||
'application': item['application'],
|
||||
'active': item['active']})
|
||||
else:
|
||||
raise ValidationError("切削速度认证未通过")
|
||||
|
||||
@@ -2006,24 +2004,22 @@ class CuttingSpeed(models.Model):
|
||||
'active': item['active'],
|
||||
})
|
||||
else:
|
||||
if item['active'] is False:
|
||||
item.write({'active': False})
|
||||
else:
|
||||
self.write({
|
||||
'execution_standard_id': self.env['sf.international.standards'].search(
|
||||
[('code', '=', item['execution_standard_code'])]).id,
|
||||
'material_name_id': self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['material_name'])]).id,
|
||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||
[('name', '=', item['cutting_width_depth'])]).id,
|
||||
'ability_feature_library': self.env['maintenance.equipment.image'].search(
|
||||
[('name', '=', item['ability_feature_library']), ('type', '=', '加工能力')]).id,
|
||||
'material_code': item['material_code'],
|
||||
'material_grade': item['material_grade'],
|
||||
'tensile_strength': item['tensile_strength'],
|
||||
'hardness': item['hardness'],
|
||||
'cutting_speed': item['cutting_speed'],
|
||||
'application': item['application'], })
|
||||
cutting_speed.write({
|
||||
'execution_standard_id': self.env['sf.international.standards'].search(
|
||||
[('code', '=', item['execution_standard_code'])]).id,
|
||||
'material_name_id': self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['material_name'])]).id,
|
||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||
[('name', '=', item['cutting_width_depth'])]).id,
|
||||
'ability_feature_library': self.env['maintenance.equipment.image'].search(
|
||||
[('name', '=', item['ability_feature_library']), ('type', '=', '加工能力')]).id,
|
||||
'material_code': item['material_code'],
|
||||
'material_grade': item['material_grade'],
|
||||
'tensile_strength': item['tensile_strength'],
|
||||
'hardness': item['hardness'],
|
||||
'cutting_speed': item['cutting_speed'],
|
||||
'application': item['application'],
|
||||
'active': item['active']})
|
||||
else:
|
||||
raise ValidationError("切削速度认证未通过")
|
||||
|
||||
@@ -2098,16 +2094,14 @@ class CuttingSpeed(models.Model):
|
||||
'active': item['active'],
|
||||
})
|
||||
else:
|
||||
if item['active'] is False:
|
||||
item.write({'active': False})
|
||||
else:
|
||||
self.write({
|
||||
'materials_type_id': self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['materials_type_code'])]).id,
|
||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||
[('name', '=', item['cutting_width_depth'])]).id,
|
||||
'blade_diameter': item['blade_diameter'],
|
||||
'feed_per_tooth': item['feed_per_tooth'], })
|
||||
feed_per_tooth.write({
|
||||
'materials_type_id': self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['materials_type_code'])]).id,
|
||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||
[('name', '=', item['cutting_width_depth'])]).id,
|
||||
'blade_diameter': item['blade_diameter'],
|
||||
'feed_per_tooth': item['feed_per_tooth'],
|
||||
'active': item['active']})
|
||||
else:
|
||||
raise ValidationError("每齿走刀量认证未通过")
|
||||
|
||||
@@ -2136,16 +2130,14 @@ class CuttingSpeed(models.Model):
|
||||
'active': item['active'],
|
||||
})
|
||||
else:
|
||||
if item['active'] is False:
|
||||
item.write({'active': False})
|
||||
else:
|
||||
self.write({
|
||||
'materials_type_id': self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['materials_type_code'])]).id,
|
||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||
[('name', '=', item['cutting_width_depth'])]).id,
|
||||
'blade_diameter': item['blade_diameter'],
|
||||
'feed_per_tooth': item['feed_per_tooth'], })
|
||||
feed_per_tooth.write({
|
||||
'materials_type_id': self.env['sf.materials.model'].search(
|
||||
[('materials_no', '=', item['materials_type_code'])]).id,
|
||||
'cutting_width_depth_id': self.env['sf.cutting.width.depth'].search(
|
||||
[('name', '=', item['cutting_width_depth'])]).id,
|
||||
'blade_diameter': item['blade_diameter'],
|
||||
'feed_per_tooth': item['feed_per_tooth'],
|
||||
'active': item['active']})
|
||||
else:
|
||||
raise ValidationError("每齿走刀量认证未通过")
|
||||
|
||||
@@ -2383,6 +2375,7 @@ class CuttingToolBasicParameters(models.Model):
|
||||
r = requests.post(strUrl, json={}, data=None, headers=headers)
|
||||
r = r.json()
|
||||
result = json.loads(r['result'])
|
||||
logging.info(result)
|
||||
if result['status'] == 1:
|
||||
if 'basic_parameters_integral_tool' in result['cutting_tool_basic_parameters_all_list']:
|
||||
if result['cutting_tool_basic_parameters_all_list']['basic_parameters_integral_tool']:
|
||||
@@ -2421,7 +2414,7 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'active': integral_tool_item['active'],
|
||||
})
|
||||
else:
|
||||
self.write({
|
||||
self.search([('code', '=', integral_tool_item['code'])]).write({
|
||||
'name': integral_tool_item['name'],
|
||||
'total_length': integral_tool_item['total_length'],
|
||||
'blade_diameter': integral_tool_item['blade_diameter'],
|
||||
@@ -2482,7 +2475,7 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'active': blade_item['active'],
|
||||
})
|
||||
else:
|
||||
self.write({
|
||||
self.search([('code', '=', blade_item['code'])]).write({
|
||||
'name': blade_item['name'],
|
||||
'length': blade_item['length'],
|
||||
'thickness': blade_item['thickness'],
|
||||
@@ -2539,7 +2532,7 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'active': chuck_item['active'],
|
||||
})
|
||||
else:
|
||||
self.write({
|
||||
self.search([('code', '=', chuck_item['code'])]).write({
|
||||
'name': chuck_item['name'],
|
||||
'er_size_model': chuck_item['size_model'],
|
||||
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
||||
@@ -2598,7 +2591,7 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'active': cutter_arbor_item['active'],
|
||||
})
|
||||
else:
|
||||
self.write({
|
||||
self.search([('code', '=', cutter_arbor_item['code'])]).write({
|
||||
'name': cutter_arbor_item['name'],
|
||||
'height': cutter_arbor_item['height'],
|
||||
'width': cutter_arbor_item['width'],
|
||||
@@ -2662,7 +2655,7 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'active': cutter_head_item['active'],
|
||||
})
|
||||
else:
|
||||
self.write({
|
||||
self.search([('code', '=', cutter_head_item['code'])]).write({
|
||||
'name': cutter_head_item['name'],
|
||||
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
||||
'blade_diameter': cutter_head_item['blade_diameter'],
|
||||
@@ -2691,57 +2684,38 @@ class CuttingToolBasicParameters(models.Model):
|
||||
for knife_handle_item in basic_parameters_knife_handle_list:
|
||||
knife_handle = self.search(
|
||||
[('code', '=', knife_handle_item['code']), ('active', 'in', [True, False])])
|
||||
val = {
|
||||
'name': knife_handle_item['name'],
|
||||
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
||||
'total_length': knife_handle_item['total_length'],
|
||||
'flange_shank_length': knife_handle_item['flange_length'],
|
||||
'flange_diameter': knife_handle_item['flange_diameter'],
|
||||
'shank_length': knife_handle_item['shank_length'],
|
||||
'shank_diameter': knife_handle_item['shank_diameter'],
|
||||
'min_clamping_diameter': knife_handle_item['clamping_diameter_min'],
|
||||
'max_clamping_diameter': knife_handle_item['clamping_diameter_max'],
|
||||
'clamping_mode': knife_handle_item['clamping_way'],
|
||||
'tool_changing_time': knife_handle_item['tool_changing_time'],
|
||||
'max_rotate_speed': knife_handle_item['rotate_speed_max'],
|
||||
'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'],
|
||||
'cooling_model': knife_handle_item['cooling_model'],
|
||||
'fit_chuck_size': knife_handle_item['fit_chuck_size'],
|
||||
'is_quick_cutting': knife_handle_item['is_quick_cutting'],
|
||||
'is_safe_lock': knife_handle_item['is_safe_lock'],
|
||||
'screw': knife_handle_item['fit_wrench_model'],
|
||||
'nut': knife_handle_item['fit_nut_model'],
|
||||
'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
|
||||
'active': knife_handle_item['active'],
|
||||
}
|
||||
if not knife_handle:
|
||||
self.create({
|
||||
'name': knife_handle_item['name'],
|
||||
'code': knife_handle_item['code'],
|
||||
'cutting_tool_type': '刀柄',
|
||||
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
||||
'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,
|
||||
'total_length': knife_handle_item['total_length'],
|
||||
'flange_shank_length': knife_handle_item['flange_length'],
|
||||
'flange_diameter': knife_handle_item['flange_diameter'],
|
||||
'shank_length': knife_handle_item['shank_length'],
|
||||
'shank_diameter': knife_handle_item['shank_diameter'],
|
||||
'min_clamping_diameter': knife_handle_item['clamping_diameter_min'],
|
||||
'max_clamping_diameter': knife_handle_item['clamping_diameter_max'],
|
||||
'clamping_mode': knife_handle_item['clamping_way'],
|
||||
'tool_changing_time': knife_handle_item['tool_changing_time'],
|
||||
'max_rotate_speed': knife_handle_item['rotate_speed_max'],
|
||||
'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'],
|
||||
'cooling_model': knife_handle_item['cooling_model'],
|
||||
'is_quick_cutting': knife_handle_item['is_quick_cutting'],
|
||||
'is_safe_lock': knife_handle_item['is_safe_lock'],
|
||||
'screw': knife_handle_item['fit_wrench_model'],
|
||||
'nut': knife_handle_item['fit_nut_model'],
|
||||
'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
|
||||
'active': knife_handle_item['active'],
|
||||
})
|
||||
val['code'] = knife_handle_item['code']
|
||||
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)
|
||||
else:
|
||||
self.write({
|
||||
'name': knife_handle_item['name'],
|
||||
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
||||
'total_length': knife_handle_item['total_length'],
|
||||
'flange_shank_length': knife_handle_item['flange_length'],
|
||||
'flange_diameter': knife_handle_item['flange_diameter'],
|
||||
'shank_length': knife_handle_item['shank_length'],
|
||||
'shank_diameter': knife_handle_item['shank_diameter'],
|
||||
'min_clamping_diameter': knife_handle_item['clamping_diameter_min'],
|
||||
'max_clamping_diameter': knife_handle_item['clamping_diameter_max'],
|
||||
'clamping_mode': knife_handle_item['clamping_way'],
|
||||
'tool_changing_time': knife_handle_item['tool_changing_time'],
|
||||
'max_rotate_speed': knife_handle_item['rotate_speed_max'],
|
||||
'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'],
|
||||
'cooling_model': knife_handle_item['cooling_model'],
|
||||
'is_quick_cutting': knife_handle_item['is_quick_cutting'],
|
||||
'is_safe_lock': knife_handle_item['is_safe_lock'],
|
||||
'screw': knife_handle_item['fit_wrench_model'],
|
||||
'nut': knife_handle_item['fit_nut_model'],
|
||||
'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
|
||||
'active': knife_handle_item['active'],
|
||||
})
|
||||
self.search([('code', '=', knife_handle_item['code'])]).write(val)
|
||||
else:
|
||||
raise ValidationError("刀具物料基本参数认证未通过")
|
||||
|
||||
@@ -2790,29 +2764,26 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'active': integral_tool_item['active'],
|
||||
})
|
||||
else:
|
||||
if integral_tool_item['active'] is False:
|
||||
integral_tool.write({'active': False})
|
||||
else:
|
||||
self.write({
|
||||
'name': integral_tool_item['name'],
|
||||
'total_length': integral_tool_item['total_length'],
|
||||
'blade_diameter': integral_tool_item['blade_diameter'],
|
||||
'blade_length': integral_tool_item['blade_length'],
|
||||
'blade_number': integral_tool_item['blade_number'],
|
||||
'neck_length': integral_tool_item['neck_length'],
|
||||
'neck_diameter': integral_tool_item['neck_diameter'],
|
||||
'handle_diameter': integral_tool_item['shank_diameter'],
|
||||
'handle_length': integral_tool_item['shank_length'],
|
||||
'blade_tip_diameter': integral_tool_item['tip_diameter'],
|
||||
'blade_tip_working_size': integral_tool_item['tip_handling_size'],
|
||||
'blade_tip_taper': integral_tool_item['knife_tip_taper'],
|
||||
'blade_helix_angle': integral_tool_item['blade_helix_angle'],
|
||||
'blade_width': integral_tool_item['blade_width'],
|
||||
'blade_depth': integral_tool_item['blade_depth'],
|
||||
'pitch': integral_tool_item['pitch'],
|
||||
'cutting_depth': integral_tool_item['cutting_depth_max'],
|
||||
'active': integral_tool_item['active'],
|
||||
})
|
||||
integral_tool.write({
|
||||
'name': integral_tool_item['name'],
|
||||
'total_length': integral_tool_item['total_length'],
|
||||
'blade_diameter': integral_tool_item['blade_diameter'],
|
||||
'blade_length': integral_tool_item['blade_length'],
|
||||
'blade_number': integral_tool_item['blade_number'],
|
||||
'neck_length': integral_tool_item['neck_length'],
|
||||
'neck_diameter': integral_tool_item['neck_diameter'],
|
||||
'handle_diameter': integral_tool_item['shank_diameter'],
|
||||
'handle_length': integral_tool_item['shank_length'],
|
||||
'blade_tip_diameter': integral_tool_item['tip_diameter'],
|
||||
'blade_tip_working_size': integral_tool_item['tip_handling_size'],
|
||||
'blade_tip_taper': integral_tool_item['knife_tip_taper'],
|
||||
'blade_helix_angle': integral_tool_item['blade_helix_angle'],
|
||||
'blade_width': integral_tool_item['blade_width'],
|
||||
'blade_depth': integral_tool_item['blade_depth'],
|
||||
'pitch': integral_tool_item['pitch'],
|
||||
'cutting_depth': integral_tool_item['cutting_depth_max'],
|
||||
'active': integral_tool_item['active'],
|
||||
})
|
||||
if 'basic_parameters_blade' in result['cutting_tool_basic_parameters_yesterday_list']:
|
||||
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_blade']:
|
||||
basic_parameters_blade_list = json.loads(
|
||||
@@ -2854,35 +2825,33 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'active': blade_item['active'],
|
||||
})
|
||||
else:
|
||||
if blade_item['active'] is False:
|
||||
blade.write({'active': False})
|
||||
else:
|
||||
self.write({
|
||||
'name': blade_item['name'],
|
||||
'length': blade_item['length'],
|
||||
'thickness': blade_item['thickness'],
|
||||
'cutting_blade_length': blade_item['cutting_blade_length'],
|
||||
'relief_angle': blade_item['relief_angle'],
|
||||
'blade_tip_circular_arc_radius': blade_item['radius_tip_re'],
|
||||
'inscribed_circle_diameter': blade_item['diameter_inner_circle'],
|
||||
'install_aperture_diameter': blade_item['diameter_mounting_hole'],
|
||||
'pitch': blade_item['pitch'],
|
||||
'chip_breaker_groove': blade_item['is_chip_breaker'],
|
||||
'chip_breaker_type_code': blade_item['chip_breaker_type_code'],
|
||||
'blade_teeth_model': '无' if not blade_item['blade_profile'] else blade_item[
|
||||
'blade_profile'],
|
||||
'blade_blade_number': blade_item['blade_number'],
|
||||
'cutting_depth': blade_item['cutting_depth_max'],
|
||||
'blade_width': blade_item['blade_width'],
|
||||
'main_included_angle': blade_item['edge_angle'],
|
||||
'top_angle': blade_item['top_angle'],
|
||||
'thread_model': '无' if not blade_item['thread_type'] else blade_item[
|
||||
'thread_type'],
|
||||
'thread_num': blade_item['threads_per_inch'],
|
||||
'blade_tip_height_tolerance': blade_item['tip_height_tolerance'],
|
||||
'inscribed_circle_tolerance': blade_item['internal_circle_tolerance'],
|
||||
'thickness_tolerance': blade_item['thickness_tolerance'],
|
||||
})
|
||||
blade.write({
|
||||
'name': blade_item['name'],
|
||||
'length': blade_item['length'],
|
||||
'thickness': blade_item['thickness'],
|
||||
'cutting_blade_length': blade_item['cutting_blade_length'],
|
||||
'relief_angle': blade_item['relief_angle'],
|
||||
'blade_tip_circular_arc_radius': blade_item['radius_tip_re'],
|
||||
'inscribed_circle_diameter': blade_item['diameter_inner_circle'],
|
||||
'install_aperture_diameter': blade_item['diameter_mounting_hole'],
|
||||
'pitch': blade_item['pitch'],
|
||||
'chip_breaker_groove': blade_item['is_chip_breaker'],
|
||||
'chip_breaker_type_code': blade_item['chip_breaker_type_code'],
|
||||
'blade_teeth_model': '无' if not blade_item['blade_profile'] else blade_item[
|
||||
'blade_profile'],
|
||||
'blade_blade_number': blade_item['blade_number'],
|
||||
'cutting_depth': blade_item['cutting_depth_max'],
|
||||
'blade_width': blade_item['blade_width'],
|
||||
'main_included_angle': blade_item['edge_angle'],
|
||||
'top_angle': blade_item['top_angle'],
|
||||
'thread_model': '无' if not blade_item['thread_type'] else blade_item[
|
||||
'thread_type'],
|
||||
'thread_num': blade_item['threads_per_inch'],
|
||||
'blade_tip_height_tolerance': blade_item['tip_height_tolerance'],
|
||||
'inscribed_circle_tolerance': blade_item['internal_circle_tolerance'],
|
||||
'thickness_tolerance': blade_item['thickness_tolerance'],
|
||||
'active': blade_item['active']
|
||||
})
|
||||
if 'basic_parameters_chuck' in result['cutting_tool_basic_parameters_yesterday_list']:
|
||||
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_chuck']:
|
||||
basic_parameters_chuck_list = json.loads(
|
||||
@@ -2913,24 +2882,22 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'active': chuck_item['active'],
|
||||
})
|
||||
else:
|
||||
if chuck_item['active'] is False:
|
||||
chuck.write({'active': False})
|
||||
else:
|
||||
self.write({
|
||||
'name': chuck_item['name'],
|
||||
'er_size_model': chuck_item['size_model'],
|
||||
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
||||
'max_clamping_diameter': chuck_item['clamping_diameter_max'],
|
||||
'outer_diameter': chuck_item['outer_diameter'],
|
||||
'inner_diameter': chuck_item['inner_diameter'],
|
||||
'run_out_accuracy': chuck_item['run_out_accuracy'],
|
||||
'total_length': chuck_item['total_length'],
|
||||
'taper': chuck_item['taper'],
|
||||
'top_diameter': chuck_item['top_diameter'],
|
||||
'weight': chuck_item['weight'],
|
||||
'max_load_capacity': chuck_item['load_capacity_max'],
|
||||
'cooling_jacket': chuck_item['cooling_sleeve_model'],
|
||||
})
|
||||
chuck.write({
|
||||
'name': chuck_item['name'],
|
||||
'er_size_model': chuck_item['size_model'],
|
||||
'min_clamping_diameter': chuck_item['clamping_diameter_min'],
|
||||
'max_clamping_diameter': chuck_item['clamping_diameter_max'],
|
||||
'outer_diameter': chuck_item['outer_diameter'],
|
||||
'inner_diameter': chuck_item['inner_diameter'],
|
||||
'run_out_accuracy': chuck_item['run_out_accuracy'],
|
||||
'total_length': chuck_item['total_length'],
|
||||
'taper': chuck_item['taper'],
|
||||
'top_diameter': chuck_item['top_diameter'],
|
||||
'weight': chuck_item['weight'],
|
||||
'max_load_capacity': chuck_item['load_capacity_max'],
|
||||
'cooling_jacket': chuck_item['cooling_sleeve_model'],
|
||||
'active': chuck_item['active']
|
||||
})
|
||||
if 'basic_parameters_cutter_arbor' in result['cutting_tool_basic_parameters_yesterday_list']:
|
||||
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_arbor']:
|
||||
basic_parameters_cutter_arbor_list = json.loads(
|
||||
@@ -2974,38 +2941,36 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'active': cutter_arbor_item['active'],
|
||||
})
|
||||
else:
|
||||
if cutter_arbor_item['active'] is False:
|
||||
cutter_arbor.write({'active': False})
|
||||
else:
|
||||
self.write({
|
||||
'name': cutter_arbor_item['name'],
|
||||
'height': cutter_arbor_item['height'],
|
||||
'width': cutter_arbor_item['width'],
|
||||
'total_length': cutter_arbor_item['total_length'],
|
||||
'knife_head_height': cutter_arbor_item['head_length'],
|
||||
'knife_head_width': cutter_arbor_item['head_width'],
|
||||
'knife_head_length': cutter_arbor_item['head_length'],
|
||||
'cutter_arbor_diameter': cutter_arbor_item['arbor_diameter'],
|
||||
'main_included_angle': cutter_arbor_item['edge_angle'],
|
||||
'relief_angle': cutter_arbor_item['relief_angle'],
|
||||
'cutting_depth': cutter_arbor_item['cutting_depth_max'],
|
||||
'min_machining_aperture': cutter_arbor_item['machining_aperture_min'],
|
||||
'install_blade_tip_num': cutter_arbor_item['number_blade_installed'],
|
||||
'is_cooling_hole': cutter_arbor_item['is_cooling_hole'],
|
||||
'locating_slot_code': cutter_arbor_item['locator_slot_code'],
|
||||
'installing_structure': cutter_arbor_item['mounting_structure'],
|
||||
'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else
|
||||
self.env[
|
||||
'sf.cutting_tool.standard.library'].search(
|
||||
[('code', '=',
|
||||
cutter_arbor_item['fit_blade_model_code'].replace("JKM", result[
|
||||
'factory_short_name']))]).id,
|
||||
'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
|
||||
'cotter_pin': cutter_arbor_item['fit_pin_model'],
|
||||
'pressing_plate': cutter_arbor_item['fit_plate_model'],
|
||||
'screw': cutter_arbor_item['fit_screw_model'],
|
||||
'spanner': cutter_arbor_item['fit_wrench_model'],
|
||||
})
|
||||
cutter_arbor.write({
|
||||
'name': cutter_arbor_item['name'],
|
||||
'height': cutter_arbor_item['height'],
|
||||
'width': cutter_arbor_item['width'],
|
||||
'total_length': cutter_arbor_item['total_length'],
|
||||
'knife_head_height': cutter_arbor_item['head_length'],
|
||||
'knife_head_width': cutter_arbor_item['head_width'],
|
||||
'knife_head_length': cutter_arbor_item['head_length'],
|
||||
'cutter_arbor_diameter': cutter_arbor_item['arbor_diameter'],
|
||||
'main_included_angle': cutter_arbor_item['edge_angle'],
|
||||
'relief_angle': cutter_arbor_item['relief_angle'],
|
||||
'cutting_depth': cutter_arbor_item['cutting_depth_max'],
|
||||
'min_machining_aperture': cutter_arbor_item['machining_aperture_min'],
|
||||
'install_blade_tip_num': cutter_arbor_item['number_blade_installed'],
|
||||
'is_cooling_hole': cutter_arbor_item['is_cooling_hole'],
|
||||
'locating_slot_code': cutter_arbor_item['locator_slot_code'],
|
||||
'installing_structure': cutter_arbor_item['mounting_structure'],
|
||||
'blade_id': False if not cutter_arbor_item['fit_blade_model_code'] else
|
||||
self.env[
|
||||
'sf.cutting_tool.standard.library'].search(
|
||||
[('code', '=',
|
||||
cutter_arbor_item['fit_blade_model_code'].replace("JKM", result[
|
||||
'factory_short_name']))]).id,
|
||||
'tool_shim': cutter_arbor_item['fit_knife_pad_model'],
|
||||
'cotter_pin': cutter_arbor_item['fit_pin_model'],
|
||||
'pressing_plate': cutter_arbor_item['fit_plate_model'],
|
||||
'screw': cutter_arbor_item['fit_screw_model'],
|
||||
'spanner': cutter_arbor_item['fit_wrench_model'],
|
||||
'active': cutter_arbor_item['active']
|
||||
})
|
||||
if 'basic_parameters_cutter_head' in result['cutting_tool_basic_parameters_yesterday_list']:
|
||||
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_cutter_head']:
|
||||
basic_parameters_cutter_head_list = json.loads(
|
||||
@@ -3042,30 +3007,28 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'active': cutter_head_item['active'],
|
||||
})
|
||||
else:
|
||||
if cutter_head_item['active'] is False:
|
||||
cutter_head.write({'active': False})
|
||||
else:
|
||||
self.write({
|
||||
'name': cutter_head_item['name'],
|
||||
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
||||
'blade_diameter': cutter_head_item['blade_diameter'],
|
||||
'cutter_head_diameter': cutter_head_item['cutter_diameter'],
|
||||
'interface_diameter': cutter_head_item['interface_diameter'],
|
||||
'total_length': cutter_head_item['total_length'],
|
||||
'blade_length': cutter_head_item['blade_length'],
|
||||
'cutting_depth': cutter_head_item['cutting_depth_max'],
|
||||
'main_included_angle': cutter_head_item['edge_angle'],
|
||||
'installing_structure': cutter_head_item['mounting_structure'],
|
||||
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
|
||||
'sf.cutting_tool.standard.library'].search(
|
||||
[('code', '=',
|
||||
cutter_head_item['fit_blade_model_code'].replace("JKM", result[
|
||||
'factory_short_name']))]).id,
|
||||
'screw': cutter_head_item['fit_screw_model'],
|
||||
'spanner': cutter_head_item['fit_wrench_model'],
|
||||
'is_cooling_hole': cutter_head_item['is_cooling_hole'],
|
||||
'locating_slot_code': cutter_head_item['locator_slot_code'],
|
||||
})
|
||||
cutter_head.write({
|
||||
'name': cutter_head_item['name'],
|
||||
'install_blade_tip_num': cutter_head_item['number_blade_installed'],
|
||||
'blade_diameter': cutter_head_item['blade_diameter'],
|
||||
'cutter_head_diameter': cutter_head_item['cutter_diameter'],
|
||||
'interface_diameter': cutter_head_item['interface_diameter'],
|
||||
'total_length': cutter_head_item['total_length'],
|
||||
'blade_length': cutter_head_item['blade_length'],
|
||||
'cutting_depth': cutter_head_item['cutting_depth_max'],
|
||||
'main_included_angle': cutter_head_item['edge_angle'],
|
||||
'installing_structure': cutter_head_item['mounting_structure'],
|
||||
'blade_id': False if not cutter_head_item['fit_blade_model_code'] else self.env[
|
||||
'sf.cutting_tool.standard.library'].search(
|
||||
[('code', '=',
|
||||
cutter_head_item['fit_blade_model_code'].replace("JKM", result[
|
||||
'factory_short_name']))]).id,
|
||||
'screw': cutter_head_item['fit_screw_model'],
|
||||
'spanner': cutter_head_item['fit_wrench_model'],
|
||||
'is_cooling_hole': cutter_head_item['is_cooling_hole'],
|
||||
'locating_slot_code': cutter_head_item['locator_slot_code'],
|
||||
'active': cutter_head_item['active']
|
||||
})
|
||||
if 'basic_parameters_knife_handle' in result['cutting_tool_basic_parameters_yesterday_list']:
|
||||
if result['cutting_tool_basic_parameters_yesterday_list']['basic_parameters_knife_handle']:
|
||||
basic_parameters_knife_handle_list = json.loads(
|
||||
@@ -3097,35 +3060,35 @@ class CuttingToolBasicParameters(models.Model):
|
||||
'cooling_model': knife_handle_item['cooling_model'],
|
||||
'is_quick_cutting': knife_handle_item['is_quick_cutting'],
|
||||
'is_safe_lock': knife_handle_item['is_safe_lock'],
|
||||
'fit_chuck_size': knife_handle_item['fit_chuck_size'],
|
||||
'screw': knife_handle_item['fit_wrench_model'],
|
||||
'nut': knife_handle_item['fit_nut_model'],
|
||||
'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
|
||||
'active': knife_handle_item['active'],
|
||||
})
|
||||
else:
|
||||
if knife_handle_item['active'] is False:
|
||||
knife_handle.write({'active': False})
|
||||
else:
|
||||
self.write({
|
||||
'name': knife_handle_item['name'],
|
||||
'total_length': knife_handle_item['total_length'],
|
||||
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
||||
'flange_shank_length': knife_handle_item['flange_length'],
|
||||
'flange_diameter': knife_handle_item['flange_diameter'],
|
||||
'shank_length': knife_handle_item['shank_length'],
|
||||
'shank_diameter': knife_handle_item['shank_diameter'],
|
||||
'min_clamping_diameter': knife_handle_item['clamping_diameter_min'],
|
||||
'max_clamping_diameter': knife_handle_item['clamping_diameter_max'],
|
||||
'clamping_mode': knife_handle_item['clamping_way'],
|
||||
'tool_changing_time': knife_handle_item['tool_changing_time'],
|
||||
'max_rotate_speed': knife_handle_item['rotate_speed_max'],
|
||||
'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'],
|
||||
'cooling_model': knife_handle_item['cooling_model'],
|
||||
'is_quick_cutting': knife_handle_item['is_quick_cutting'],
|
||||
'is_safe_lock': knife_handle_item['is_safe_lock'],
|
||||
'screw': knife_handle_item['fit_wrench_model'],
|
||||
'nut': knife_handle_item['fit_nut_model'],
|
||||
'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
|
||||
})
|
||||
knife_handle.write({
|
||||
'name': knife_handle_item['name'],
|
||||
'total_length': knife_handle_item['total_length'],
|
||||
'taper_shank_model': knife_handle_item['taper_shank_model'],
|
||||
'flange_shank_length': knife_handle_item['flange_length'],
|
||||
'flange_diameter': knife_handle_item['flange_diameter'],
|
||||
'shank_length': knife_handle_item['shank_length'],
|
||||
'shank_diameter': knife_handle_item['shank_diameter'],
|
||||
'min_clamping_diameter': knife_handle_item['clamping_diameter_min'],
|
||||
'max_clamping_diameter': knife_handle_item['clamping_diameter_max'],
|
||||
'clamping_mode': knife_handle_item['clamping_way'],
|
||||
'tool_changing_time': knife_handle_item['tool_changing_time'],
|
||||
'max_rotate_speed': knife_handle_item['rotate_speed_max'],
|
||||
'diameter_slip_accuracy': knife_handle_item['diameter_slip_accuracy'],
|
||||
'cooling_model': knife_handle_item['cooling_model'],
|
||||
'fit_chuck_size': knife_handle_item['fit_chuck_size'],
|
||||
'is_quick_cutting': knife_handle_item['is_quick_cutting'],
|
||||
'is_safe_lock': knife_handle_item['is_safe_lock'],
|
||||
'screw': knife_handle_item['fit_wrench_model'],
|
||||
'nut': knife_handle_item['fit_nut_model'],
|
||||
'dynamic_balance_class': knife_handle_item['dynamic_balance_class'],
|
||||
'active': knife_handle_item['active']
|
||||
})
|
||||
else:
|
||||
raise ValidationError("刀具物料基本参数认证未通过")
|
||||
|
||||
@@ -81,12 +81,30 @@
|
||||
<div class="o_setting_left_pane"/>
|
||||
<div class="o_setting_right_pane">
|
||||
<div class="text-muted">
|
||||
<label for="agv_rcms_url" string="调度系统(cms)访问地址"/>
|
||||
<field name="agv_rcms_url"/>
|
||||
<label for="agv_rcs_url" string="访问地址"/>
|
||||
<field name="agv_rcs_url"/>
|
||||
</div>
|
||||
<div class="text-muted">
|
||||
<label for="agv_rcs_url" string="RCS-2000系统访问地址"/>
|
||||
<field name="agv_rcs_url"/>
|
||||
<label for="agv_code" string="车辆编号"/>
|
||||
<field name="agv_code"/>
|
||||
</div>
|
||||
<div class="text-muted">
|
||||
<label for="wbcode"/>
|
||||
<field name="wbcode"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div>
|
||||
<h2>中控参数配置</h2>
|
||||
<div class="row mt16 o_settings_container">
|
||||
<div class="col-12 col-lg-6 o_setting_box">
|
||||
<div class="o_setting_left_pane"/>
|
||||
<div class="o_setting_right_pane">
|
||||
<div class="text-muted">
|
||||
<label for="center_control_url" string="访问地址"/>
|
||||
<field name="center_control_url"/>
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
@@ -71,7 +71,7 @@
|
||||
<field name="order_deadline"/>
|
||||
<!-- <field name="process_time"/> -->
|
||||
<field name="schedule_setting"/>
|
||||
<field name="production_line_id"/>
|
||||
<field name="production_line_id" domain="[('name', 'ilike', 'CNC')]"/>
|
||||
|
||||
|
||||
<!-- Chatter -->
|
||||
|
||||
@@ -6,7 +6,7 @@
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<group>
|
||||
<field name="production_line_id"/>
|
||||
<field name="production_line_id" domain="[('name', 'ilike', 'CNC')]"/>
|
||||
</group>
|
||||
<footer>
|
||||
<button string="确认排程" name="action_plan_all" type="object" class="btn-primary"/>
|
||||
|
||||
@@ -19,7 +19,10 @@ class QualityCheck(models.Model):
|
||||
# headers = Common.get_headers(self, token, sf_secret_key)
|
||||
headers = {'Authorization': 'Ba F2CF5DCC-1A00-4234-9E95-65603F70CC8A'}
|
||||
crea_url = "https://x24467i973.zicp.fun/AutoDeviceApi/PartSpecProc"
|
||||
val = ['0037835872']
|
||||
origin = self.picking_id.origin
|
||||
production_id = self.env['mrp.production'].sudo().search([('name', '=', origin)])
|
||||
rfid = '' if not production_id.workorder_ids else production_id.workorder_ids[-1].rfid_code or ''
|
||||
val = [rfid]
|
||||
r = requests.post(crea_url, json=val, headers=headers)
|
||||
ret = r.json()
|
||||
logging.info('_register_quality_check:%s' % ret)
|
||||
@@ -33,4 +36,5 @@ class QualityCheck(models.Model):
|
||||
'quality_state': 'fail',
|
||||
'user_id': self.env.user.id,
|
||||
'control_date': datetime.now()})
|
||||
self._register_quality_check()
|
||||
if self.picking_id and 'WH/MO/' in self.picking_id.origin:
|
||||
self._register_quality_check()
|
||||
|
||||
@@ -43,8 +43,6 @@ access_quality_alert_team_group_sf_mrp_manager,quality_alert_team_group_sf_mrp_m
|
||||
|
||||
access_product_template_group_quality,product_template_group_quality,product.model_product_template,sf_base.group_quality,1,0,0,0
|
||||
access_product_template_group_quality_director,product_template_group_quality_director,product.model_product_template,sf_base.group_quality_director,1,0,0,0
|
||||
access_product_template_group_plan_dispatch,product_template_group_plan_dispatch,product.model_product_template,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_product_template_group_plan_director,product_template_group_plan_director,product.model_product_template,sf_base.group_plan_director,1,0,0,0
|
||||
access_product_template_group_sf_equipment_user,product_template_group_sf_equipment_user,product.model_product_template,sf_base.group_sf_equipment_user,1,0,0,0
|
||||
access_product_template_group_sf_tool_user,product_template_group_sf_tool_user,product.model_product_template,sf_base.group_sf_tool_user,1,0,0,0
|
||||
access_product_template_group_sf_order_user,product_template_group_sf_order_user,product.model_product_template,sf_base.group_sf_order_user,1,0,0,0
|
||||
|
||||
|
@@ -1,5 +1,6 @@
|
||||
from . import sale_order
|
||||
from . import quick_easy_order
|
||||
# from . import quick_easy_order
|
||||
from . import quick_easy_order_old
|
||||
from . import auto_quatotion_common
|
||||
from . import parser_and_calculate_work_time
|
||||
from . import preload_datas_functions
|
||||
|
||||
@@ -2,7 +2,7 @@
|
||||
import logging
|
||||
from odoo.modules import get_resource_path
|
||||
from odoo import fields, models, api
|
||||
from quatotion import readSql, feature_recognize, auto_quatotion
|
||||
# from quatotion import readSql, feature_recognize, auto_quatotion
|
||||
|
||||
__author__ = 'jinling.yang'
|
||||
_logger = logging.getLogger(__name__)
|
||||
|
||||
@@ -8,8 +8,8 @@ from datetime import datetime
|
||||
import requests
|
||||
from odoo import http
|
||||
from odoo.http import request
|
||||
from OCC.Extend.DataExchange import read_step_file
|
||||
from OCC.Extend.DataExchange import write_stl_file
|
||||
# from OCC.Extend.DataExchange import read_step_file
|
||||
# from OCC.Extend.DataExchange import write_stl_file
|
||||
from odoo import models, fields, api
|
||||
from odoo.modules import get_resource_path
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
|
||||
311
sf_sale/models/quick_easy_order_old.py
Normal file
311
sf_sale/models/quick_easy_order_old.py
Normal file
@@ -0,0 +1,311 @@
|
||||
import logging
|
||||
import base64
|
||||
import hashlib
|
||||
import requests
|
||||
import os
|
||||
from datetime import datetime
|
||||
from stl import mesh
|
||||
# from OCC.Core.GProp import GProp_GProps
|
||||
# from OCC.Extend.DataExchange import read_step_file
|
||||
# from OCC.Extend.DataExchange import write_stl_file
|
||||
from odoo.addons.sf_base.commons.common import Common
|
||||
from odoo import models, fields, api
|
||||
from odoo.modules import get_resource_path
|
||||
from odoo.exceptions import ValidationError, UserError
|
||||
|
||||
|
||||
class QuickEasyOrder(models.Model):
|
||||
_name = 'quick.easy.order'
|
||||
_description = '简易下单'
|
||||
_order = 'id desc'
|
||||
|
||||
name = fields.Char('订单编号', default=lambda self: self.env['ir.sequence'].next_by_code('quick.easy.order'))
|
||||
model_length = fields.Float('长(mm)', digits=(16, 3))
|
||||
model_width = fields.Float('宽(mm)', digits=(16, 3))
|
||||
model_height = fields.Float('高(mm)', digits=(16, 3))
|
||||
model_volume = fields.Float('体积(mm³)', digits=(16, 3))
|
||||
model_processing_side = fields.Char('加工面', default='A')
|
||||
model_feature = fields.Char('特征')
|
||||
machining_precision = fields.Selection([
|
||||
('0.10', '±0.10mm'),
|
||||
('0.05', '±0.05mm'),
|
||||
('0.03', '±0.03mm'),
|
||||
('0.02', '±0.02mm'),
|
||||
('0.01', '±0.01mm')], string='加工精度', default='0.10')
|
||||
material_id = fields.Many2one('sf.production.materials', '材料')
|
||||
material_model_id = fields.Many2one('sf.materials.model', '型号', domain="[('materials_id', '=', material_id)]")
|
||||
# process_id = fields.Many2one('sf.production.process', string='表面工艺')
|
||||
parameter_ids = fields.Many2many('sf.production.process.parameter', 'process_item_order_rel', string='可选参数')
|
||||
quantity = fields.Integer('数量', default=1)
|
||||
unit_price = fields.Float('单价')
|
||||
price = fields.Float('总价')
|
||||
model_file = fields.Binary('glb模型文件')
|
||||
upload_model_file = fields.Many2many('ir.attachment', 'upload_qf_model_file_attachment_ref', string='上传模型文件')
|
||||
delivery_time = fields.Date('交货日期')
|
||||
customer_id = fields.Many2one('res.partner', string='客户', default=lambda self: self.env.user.partner_id.id)
|
||||
state = fields.Selection([('草稿', '草稿'), ('待派单', '待派单'),
|
||||
('待接单', '待接单'), ('加工中', '加工中'),
|
||||
('物流中', '物流中'), ('已交付', '已交付')], string='订单状态', default='草稿',
|
||||
readonly=True)
|
||||
model_color_state = fields.Selection([
|
||||
('success', '成功'),
|
||||
('fail', '失败')], string='模型上色状态')
|
||||
processing_time = fields.Integer('加工时长(min)')
|
||||
|
||||
@api.depends('unit_price', 'quantity')
|
||||
def _compute_total_amount(self):
|
||||
for item in self:
|
||||
item.price = item.unit_price * item.quantity
|
||||
|
||||
@api.depends('material_id', 'material_model_id')
|
||||
def _compute_material_model(self):
|
||||
for item in self:
|
||||
materials = self.env['sf.production.materials'].search([], limit=1, order='id desc')
|
||||
item.material_id = materials.id
|
||||
item.material_model_id = self.env['sf.materials.model'].search(
|
||||
[('materials_id', '=', materials.id)],
|
||||
limit=1, order='id desc')
|
||||
|
||||
@api.model
|
||||
def create(self, vals):
|
||||
if vals.get('upload_model_file'):
|
||||
logging.info('create-attachment:%s' % vals['upload_model_file'][0])
|
||||
for item in vals['upload_model_file']:
|
||||
print(len(item[2]))
|
||||
if len(item[2]) > 0:
|
||||
logging.info('create-attachment:%s' % int(item[2][0]))
|
||||
attachment = self.env['ir.attachment'].sudo().search([('id', '=', int(item[2][0]))])
|
||||
base64_data = base64.b64encode(attachment.datas)
|
||||
base64_datas = base64_data.decode('utf-8')
|
||||
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||
report_path = attachment._full_path(attachment.store_fname)
|
||||
vals['model_file'] = self.transition_glb_file(report_path, model_code)
|
||||
obj = super(QuickEasyOrder, self).create(vals)
|
||||
logging.info('---------向cloud生成模型库记录-------')
|
||||
self.model_coloring(obj)
|
||||
logging.info('---------开始派单到工厂-------')
|
||||
self.distribute_to_factory(obj)
|
||||
obj.state = '待接单'
|
||||
return obj
|
||||
|
||||
# 将attach的datas内容转为glb文件
|
||||
def transition_glb_file(self, report_path, model_code):
|
||||
shapes = read_step_file(report_path)
|
||||
output_file = os.path.join('/tmp', str(model_code) + '.stl')
|
||||
write_stl_file(shapes, output_file, 'binary', 0.03, 0.5)
|
||||
# 转化为glb
|
||||
output_glb_file = os.path.join('/tmp', str(model_code) + '.glb')
|
||||
util_path = get_resource_path('sf_base', 'static/util')
|
||||
cmd = 'python3 %s/stl2gltf.py %s %s -b' % (util_path, output_file, output_glb_file)
|
||||
os.system(cmd)
|
||||
# 转base64
|
||||
with open(output_glb_file, 'rb') as fileObj:
|
||||
image_data = fileObj.read()
|
||||
base64_data = base64.b64encode(image_data)
|
||||
return base64_data
|
||||
|
||||
# return False
|
||||
|
||||
@api.onchange('upload_model_file')
|
||||
def onchange_model_file(self):
|
||||
for item in self:
|
||||
if len(item.upload_model_file) > 1:
|
||||
raise ValidationError('只允许上传一个文件')
|
||||
if item.upload_model_file:
|
||||
file_attachment_id = item.upload_model_file[0]
|
||||
# 附件路径
|
||||
report_path = file_attachment_id._full_path(file_attachment_id.store_fname)
|
||||
logging.info("模型路径: %s" % report_path)
|
||||
base64_data = base64.b64encode(file_attachment_id.datas)
|
||||
base64_datas = base64_data.decode('utf-8')
|
||||
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||
# 读取文件
|
||||
shapes = read_step_file(report_path)
|
||||
# # 第一种获取体积方式
|
||||
# props = GProp_GProps()
|
||||
# # brepgprop_VolumeProperties(shapes, props)
|
||||
# volume = props.Mass()
|
||||
# # print(volume)
|
||||
# item.model_volume = volume
|
||||
# # 长宽高/体积
|
||||
# output_file = os.path.join('C:/Users/43484/Desktop/机企猫工作文档', str(model_code) + '.stl')
|
||||
output_file = os.path.join('/tmp', str(model_code) + '.stl')
|
||||
# your_mesh = mesh.Mesh.from_file(output_file)
|
||||
# volume, cog, inertia = your_mesh.get_mass_properties()
|
||||
# xyz = (your_mesh.max_ - your_mesh.min_)
|
||||
# item.model_length = xyz[0] # 长 单位mm
|
||||
# item.model_width = xyz[1] # 宽
|
||||
# item.model_height = xyz[2] # 高
|
||||
# item.model_volume = volume
|
||||
write_stl_file(shapes, output_file, 'binary', 0.03, 0.5)
|
||||
# 转化为glb
|
||||
# output_glb_file = os.path.join('C:/Users/43484/Desktop/机企猫工作文档', str(model_code) + '.glb')
|
||||
output_glb_file = os.path.join('/tmp', str(model_code) + '.glb')
|
||||
util_path = get_resource_path('sf_base', 'static/util')
|
||||
cmd = 'python3 %s/stl2gltf.py %s %s -b' % (util_path, output_file, output_glb_file)
|
||||
os.system(cmd)
|
||||
# 转base64
|
||||
with open(output_glb_file, 'rb') as fileObj:
|
||||
image_data = fileObj.read()
|
||||
base64_data = base64.b64encode(image_data)
|
||||
item.model_file = base64_data
|
||||
else:
|
||||
item.model_length = False
|
||||
item.model_width = False
|
||||
item.model_height = False
|
||||
item.model_volume = False
|
||||
item.model_file = False
|
||||
|
||||
def distribute_to_factory(self, obj):
|
||||
"""
|
||||
派单到工厂
|
||||
:return:
|
||||
"""
|
||||
try:
|
||||
logging.info('---------派单到工厂-------')
|
||||
res = {'bfm_process_order_list': []}
|
||||
for item in obj:
|
||||
attachment = item.upload_model_file[0]
|
||||
base64_data = base64.b64encode(attachment.datas)
|
||||
base64_datas = base64_data.decode('utf-8')
|
||||
barcode = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||
# logging.info('model_file-size: %s' % len(item.model_file))
|
||||
res['bfm_process_order_list'].append({
|
||||
'model_long': item.model_length,
|
||||
'model_width': item.model_width,
|
||||
'model_height': item.model_height,
|
||||
'model_volume': item.model_volume,
|
||||
'model_machining_precision': item.machining_precision,
|
||||
'model_name': attachment.name,
|
||||
'model_data': base64_datas,
|
||||
'model_file': base64.b64encode(item.model_file).decode('utf-8'),
|
||||
'texture_code': item.material_id.materials_no,
|
||||
'texture_type_code': item.material_model_id.materials_no,
|
||||
# 'surface_process_code': self.env['jikimo.surface.process']._json_surface_process_code(item),
|
||||
'process_parameters_code': self.env[
|
||||
'sf.production.process.parameter']._json_production_process_item_code(
|
||||
item),
|
||||
'price': item.price,
|
||||
'number': item.quantity,
|
||||
'total_amount': item.price,
|
||||
'remark': '',
|
||||
'manual_quotation': True,
|
||||
'barcode': barcode
|
||||
})
|
||||
# res['bfm_process_order_list'] = json.dumps(res['bfm_process_order_list'])
|
||||
product_id = self.env.ref('sf_dlm.product_template_sf').sudo()
|
||||
self_machining_id = self.env.ref('sf_dlm.product_embryo_sf_self_machining').sudo()
|
||||
outsource_id = self.env.ref('sf_dlm.product_embryo_sf_outsource').sudo()
|
||||
purchase_id = self.env.ref('sf_dlm.product_embryo_sf_purchase').sudo()
|
||||
company_id = self.env.ref('base.main_company').sudo()
|
||||
# user_id = request.env.ref('base.user_admin').sudo()
|
||||
order_id = self.env['sale.order'].sale_order_create(company_id, 'XXXXX', 'XXXXX', 'XXXXX',
|
||||
str(datetime.now()), '现结', '支付宝')
|
||||
i = 1
|
||||
# 给sale_order的default_code字段赋值
|
||||
aa = self.env['sale.order'].sudo().search([('name', '=', order_id.name)])
|
||||
logging.info('---------aa------- %s' % aa.name)
|
||||
aa.default_code = obj.name
|
||||
for item in res['bfm_process_order_list']:
|
||||
product = self.env['product.template'].sudo().product_create(product_id, item, order_id,
|
||||
obj.name, i)
|
||||
bom_data = self.env['mrp.bom'].get_bom(product)
|
||||
logging.info('bom_data:%s' % bom_data)
|
||||
if bom_data:
|
||||
bom = self.env['mrp.bom'].bom_create(product, 'normal', False)
|
||||
bom.bom_create_line_has(bom_data)
|
||||
else:
|
||||
if product.materials_type_id.gain_way == '自加工':
|
||||
# 创建坯料
|
||||
self_machining_embryo = self.env['product.template'].sudo().no_bom_product_create(
|
||||
self_machining_id,
|
||||
item, order_id,
|
||||
'self_machining',
|
||||
i)
|
||||
# 创建坯料的bom
|
||||
self_machining_bom = self.env['mrp.bom'].bom_create(self_machining_embryo, 'normal', False)
|
||||
# 创建坯料里bom的组件
|
||||
self_machining_bom_line = self_machining_bom.bom_create_line(self_machining_embryo)
|
||||
if not self_machining_bom_line:
|
||||
self.cr.rollback()
|
||||
return UserError('该订单模型的材料型号在您分配的工厂里暂未有原材料,请先配置再进行分配')
|
||||
# 产品配置bom
|
||||
product_bom_self_machining = self.env['mrp.bom'].bom_create(product, 'normal', False)
|
||||
product_bom_self_machining.bom_create_line_has(self_machining_embryo)
|
||||
elif product.materials_type_id.gain_way == '外协':
|
||||
# 创建坯料
|
||||
outsource_embryo = self.env['product.template'].sudo().no_bom_product_create(outsource_id, item,
|
||||
order_id,
|
||||
'subcontract', i)
|
||||
if outsource_embryo == -3:
|
||||
self.cr.rollback()
|
||||
return UserError(
|
||||
'该订单模型的材料型号在您分配的工厂里暂未设置获取方式和供应商,请先配置再进行分配')
|
||||
# 创建坯料的bom
|
||||
outsource_bom = self.env['mrp.bom'].bom_create(outsource_embryo, 'subcontract', True)
|
||||
# 创建坯料的bom的组件
|
||||
outsource_bom_line = outsource_bom.with_user(
|
||||
self.env.ref("base.user_admin")).bom_create_line(outsource_embryo)
|
||||
if not outsource_bom_line:
|
||||
self.cr.rollback()
|
||||
return UserError('该订单模型的材料型号在您分配的工厂里暂未有原材料,请先配置再进行分配')
|
||||
# 产品配置bom
|
||||
product_bom_outsource = self.env['mrp.bom'].bom_create(product, 'normal', False)
|
||||
product_bom_outsource.bom_create_line_has(outsource_embryo)
|
||||
elif product.materials_type_id.gain_way == '采购':
|
||||
purchase_embryo = self.env['product.template'].sudo().no_bom_product_create(purchase_id, item,
|
||||
order_id,
|
||||
'purchase', i)
|
||||
if purchase_embryo == -3:
|
||||
self.cr.rollback()
|
||||
return UserError(
|
||||
'该订单模型的材料型号在您分配的工厂里暂未设置获取方式和供应商,请先配置再进行分配')
|
||||
# 产品配置bom
|
||||
product_bom_purchase = self.env['mrp.bom'].bom_create(product, 'normal', False)
|
||||
product_bom_purchase.bom_create_line_has(purchase_embryo)
|
||||
order_id.with_user(self.env.ref("base.user_admin")).sale_order_create_line(product, item)
|
||||
except Exception as e:
|
||||
# self.cr.rollback()
|
||||
return UserError('工厂创建销售订单和产品失败,请联系管理员')
|
||||
|
||||
# 模型上色
|
||||
|
||||
def model_coloring(self, order):
|
||||
url = '/api/library_of_models/create'
|
||||
config = self.env['res.config.settings'].get_values()
|
||||
config_header = Common.get_headers(self, config['token'], config['sf_secret_key'])
|
||||
logging.info('order: %s' % order.name)
|
||||
if order:
|
||||
attachment = order.upload_model_file[0]
|
||||
base64_data = base64.b64encode(attachment.datas)
|
||||
base64_datas = base64_data.decode('utf-8')
|
||||
model_code = hashlib.sha1(base64_datas.encode('utf-8')).hexdigest()
|
||||
logging.info('model_file-size: %s' % len(order.model_file))
|
||||
logging.info('attachment.datas-size: %s' % len(attachment.datas))
|
||||
vals = {
|
||||
'programme_way': 'manual operation',
|
||||
'model_code': model_code,
|
||||
'model_data': base64.b64decode(attachment.datas),
|
||||
'model_color_data': '',
|
||||
'model_name': attachment.name,
|
||||
'model_long': order.model_length,
|
||||
'model_width': order.model_width,
|
||||
'model_height': order.model_height,
|
||||
'model_volume': order.model_volume,
|
||||
'model_color_path': '/tmp/' + str(model_code) + ".step",
|
||||
'model_order_no': '%s-%s' % (order.name, 1),
|
||||
'remark': '订单号:%s 客户:%s' % (order.name, order.customer_id.name)
|
||||
}
|
||||
try:
|
||||
ret = requests.post((config['sf_url'] + url), json={}, data=vals, headers=config_header,
|
||||
timeout=60)
|
||||
ret = ret.json()
|
||||
# result = json.loads(ret['result'])
|
||||
if ret['status'] == 1:
|
||||
self.model_color_state = 'success'
|
||||
else:
|
||||
self.model_color_state = 'fail'
|
||||
raise UserError(ret['message'])
|
||||
except Exception as e:
|
||||
self.model_color_state = 'fail'
|
||||
raise UserError("模型上色失败")
|
||||
@@ -1,5 +1,6 @@
|
||||
import datetime
|
||||
import base64
|
||||
from odoo import Command
|
||||
from odoo import models, fields, api, _
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
@@ -84,11 +85,19 @@ class ReSaleOrder(models.Model):
|
||||
self.check_status = 'pending'
|
||||
|
||||
def get_customer(self):
|
||||
partner_tag = self.env['res.partner.category'].search([('name', '=', '业务平台')], limit=1, order='id asc')
|
||||
if not partner_tag:
|
||||
partner_tag = self.env['res.partner.category'].create({'name': '平台客户'})
|
||||
customer = self.env['res.partner'].search([('name', '=', '业务平台')], limit=1, order='id asc')
|
||||
if customer:
|
||||
if not customer.vat:
|
||||
customer.write({'name': '业务平台', 'vat': '91430103MA7BRH9K4M', 'phone': '0731-85115515',
|
||||
'email': 'jikimo@jikimo.com', 'category_id': [Command.set([partner_tag.id])]})
|
||||
return customer
|
||||
else:
|
||||
partner = self.env['res.partner'].create({'name': '业务平台'})
|
||||
partner = self.env['res.partner'].create(
|
||||
{'name': '业务平台', 'vat': '91430103MA7BRH9K4M', 'phone': '0731-85115515',
|
||||
'email': 'jikimo@jikimo.com', 'category_id': [Command.set([partner_tag.id])]})
|
||||
return partner
|
||||
|
||||
# 业务平台分配工厂时在创建完产品后再创建销售明细信息
|
||||
@@ -133,6 +142,12 @@ class ResaleOrderLine(models.Model):
|
||||
check_status = fields.Selection(related='order_id.check_status')
|
||||
|
||||
|
||||
class ProductTemplate(models.Model):
|
||||
_inherit = 'product.template'
|
||||
|
||||
manual_quotation = fields.Boolean('人工编程', default=False)
|
||||
|
||||
|
||||
class RePurchaseOrder(models.Model):
|
||||
_inherit = 'purchase.order'
|
||||
|
||||
@@ -197,6 +212,16 @@ class RePurchaseOrder(models.Model):
|
||||
order.message_subscribe([order.partner_id.id])
|
||||
return True
|
||||
|
||||
@api.onchange('order_line')
|
||||
def _onchange_order_line(self):
|
||||
for order in self:
|
||||
if order.order_line:
|
||||
line = order.order_line
|
||||
product = line.product_id
|
||||
product_id = product.ids
|
||||
if len(product_id) != len(line):
|
||||
raise ValidationError('【%s】已存在,请勿重复添加' % product[-1].name)
|
||||
|
||||
|
||||
class ResPartnerToSale(models.Model):
|
||||
_inherit = 'res.partner'
|
||||
|
||||
@@ -14,6 +14,8 @@ access_product_product_group_sale_salemanager,product_product_group_sale_saleman
|
||||
access_product_product_group_sale_director,product_product_group_sale_director,product.model_product_product,sf_base.group_sale_director,1,1,1,0
|
||||
access_product_product_group_purchase,product_product_group_purchase,product.model_product_product,sf_base.group_purchase,1,0,0,0
|
||||
access_product_product_group_purchase_director,product_product_group_purchase_director,product.model_product_product,sf_base.group_purchase_director,1,1,1,0
|
||||
access_product_product_group_plan_dispatch,product_product_group_plan_dispatch,product.model_product_product,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_product_product_group_plan_director,product_product_group_plan_director,product.model_product_product,sf_base.group_plan_director,1,1,1,0
|
||||
access_product_template_group_sale_salemanager,product_template_group_sale_salemanager,product.model_product_template,sf_base.group_sale_salemanager,1,0,0,0
|
||||
access_product_template_group_sale_director,product_template_group_sale_director,product.model_product_template,sf_base.group_sale_director,1,1,1,0
|
||||
access_product_template_group_purchase,product_template_group_purchase,product.model_product_template,sf_base.group_purchase,1,0,0,0
|
||||
@@ -90,6 +92,9 @@ access_sale_report_group_sale_director,sale_report_group_sale_director,sale.mode
|
||||
access_product_supplierinfo_group_purchase_director,product.supplierinfo group_purchase_director,product.model_product_supplierinfo,sf_base.group_purchase_director,1,1,1,0
|
||||
access_product_category_group_purchase_director,product.category group_purchase_director,product.model_product_category,sf_base.group_purchase_director,1,1,1,0
|
||||
|
||||
access_product_supplierinfo_group_plan_director,product.supplierinfo user,product.model_product_supplierinfo,sf_base.group_plan_director,1,1,1,0
|
||||
access_product_category_group_plan_director,product.category user,product.model_product_category,sf_base.group_plan_director,1,1,1,0
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -47,17 +47,8 @@
|
||||
</h1>
|
||||
<group>
|
||||
<group>
|
||||
<field name="customer_id" />
|
||||
<field name="material_id"/>
|
||||
<field name="material_model_id"/>
|
||||
<!-- <field name="process_id"/>-->
|
||||
<field name="parameter_ids" widget="many2many_tags" string="表面工艺参数"/>
|
||||
<field name="machining_precision"/>
|
||||
<field name="quantity"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="price"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="customer_id" context="{'is_customer': True }"
|
||||
options="{'no_create': True}" required="1"/>
|
||||
<field name="upload_model_file" widget="many2many_binary"/>
|
||||
<field name="model_file" widget="Viewer3D" string="模型" readonly="1" force_save="1"
|
||||
attrs="{'invisible': [('model_file', '=', False)]}"/>
|
||||
@@ -75,8 +66,18 @@
|
||||
<field name="model_height" class="o_address_zip"
|
||||
options="{'format': false}"/>
|
||||
</div>
|
||||
<field name="model_volume" attrs="{'invisible': [('model_file', '=', False)]}"/>
|
||||
<field name="model_volume" attrs="{'invisible': [('model_file', '=', False)]}"
|
||||
options="{'format': false}"/>
|
||||
<field name="material_id" options="{'no_create': True}" required="1"/>
|
||||
<field name="material_model_id" options="{'no_create': True}" required="1"/>
|
||||
<!-- <field name="process_id"/>-->
|
||||
<field name="parameter_ids" widget="many2many_tags" string="表面工艺参数"
|
||||
options="{'no_create': True}" required="1"/>
|
||||
<field name="machining_precision" required="1"/>
|
||||
<field name="processing_time"/>
|
||||
<field name="quantity" options="{'format': false}"/>
|
||||
<field name="unit_price"/>
|
||||
<field name="price" options="{'format': false}"/>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
|
||||
@@ -26,7 +26,7 @@
|
||||
</field>
|
||||
<field name="email" position="replace">
|
||||
<field name="email"
|
||||
attrs="{'required' : [('customer_rank','>', 0)],'readonly': [('id','!=', False)]}"/>
|
||||
attrs="{'readonly': [('id','!=', False)]}"/>
|
||||
</field>
|
||||
<field name="mobile" position="attributes">
|
||||
<attribute name="attrs">{'required': [('phone', '=', False)],'readonly': [('id','!=', False)]}
|
||||
@@ -37,19 +37,19 @@
|
||||
</attribute>
|
||||
</field>
|
||||
<field name="street" position="attributes">
|
||||
<attribute name="attrs">{'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]}
|
||||
<attribute name="attrs">{'readonly': [('id','!=', False)]}
|
||||
</attribute>
|
||||
</field>
|
||||
<field name="street2" position="attributes">
|
||||
<attribute name="attrs">{'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]}
|
||||
<attribute name="attrs">{'readonly': [('id','!=', False)]}
|
||||
</attribute>
|
||||
</field>
|
||||
<field name="city" position="attributes">
|
||||
<attribute name="attrs">{'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]}
|
||||
<attribute name="attrs">{'readonly': [('id','!=', False)]}
|
||||
</attribute>
|
||||
</field>
|
||||
<field name="country_id" position="attributes">
|
||||
<attribute name="attrs">{'required': [('supplier_rank','>', 0)],'readonly': [('id','!=', False)]}
|
||||
<attribute name="attrs">{'readonly': [('id','!=', False)]}
|
||||
</attribute>
|
||||
</field>
|
||||
<xpath expr="//group[@name='sale']/field[@name='user_id']" position="replace">
|
||||
|
||||
@@ -103,7 +103,7 @@
|
||||
<!-- </xpath>-->
|
||||
<field name="partner_id" position="replace">
|
||||
<field name="partner_id" widget="res_partner_many2one" context="{'is_customer': True }"
|
||||
options='{"always_reload": True}'/>
|
||||
options='{"always_reload": True,"no_create": True}'/>
|
||||
</field>
|
||||
<field name="payment_term_id" position="attributes">
|
||||
<attribute name="attrs">{'readonly': [('state', 'in', ['cancel','sale'])]}</attribute>
|
||||
|
||||
@@ -16,11 +16,13 @@
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/wizard_view.xml',
|
||||
'views/tool_base_views.xml',
|
||||
'views/functional_tool_views.xml',
|
||||
'views/mrp_workcenter_views.xml',
|
||||
'views/sf_maintenance_equipment.xml',
|
||||
'views/menu_view.xml',
|
||||
'views/tool_material_search.xml',
|
||||
'views/fixture_material_search_views.xml',
|
||||
'data/tool_data.xml',
|
||||
],
|
||||
'demo': [
|
||||
],
|
||||
|
||||
@@ -22,14 +22,14 @@ class Manufacturing_Connect(http.Controller):
|
||||
ret = json.loads(datas)
|
||||
# ret = json.loads(ret['result'])
|
||||
logging.info('DeviceId:%s' % ret)
|
||||
functional_tools = request.env['sf.functional.cutting.tool.entity'].sudo().search([])
|
||||
functional_tools = request.env['sf.tool.inventory'].sudo().search([])
|
||||
|
||||
res = {'Succeed': True, 'Datas': []}
|
||||
if functional_tools:
|
||||
for item in functional_tools:
|
||||
res['Datas'].append({
|
||||
'GroupName': item.tool_groups_id.name,
|
||||
'ToolId': item.code,
|
||||
'ToolId': item.functional_cutting_tool_model_id.name,
|
||||
'ToolName': item.name
|
||||
})
|
||||
except Exception as e:
|
||||
|
||||
@@ -1,8 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- <record model="sf.machine.table.tool.changing.apply" id="sf_create_tool_change_application">-->
|
||||
|
||||
<!-- </record>-->
|
||||
</data>
|
||||
<record model="ir.cron" id="ir_cron_sf_tool_datasync">
|
||||
<field name="name">定时同步刀具物料、功能刀具信息到cloud</field>
|
||||
<field name="model_id" ref="model_sf_tool_datasync"/>
|
||||
<field name="state">code</field>
|
||||
<field name="code">model._cron_tool_datasync_all()</field>
|
||||
<field name="interval_number">1</field>
|
||||
<field name="interval_type">days</field>
|
||||
<field name="numbercall">-1</field>
|
||||
</record>
|
||||
</odoo>
|
||||
@@ -1,4 +1,5 @@
|
||||
from . import base
|
||||
from . import functional_tool
|
||||
from . import tool_material_search
|
||||
from . import maintenance_equipment
|
||||
from . import mrp_workorder
|
||||
|
||||
@@ -1,483 +1,10 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
import json
|
||||
import requests
|
||||
import logging
|
||||
|
||||
from datetime import timedelta
|
||||
from odoo import SUPERUSER_ID
|
||||
from odoo import fields, models, api
|
||||
from odoo.exceptions import ValidationError
|
||||
from odoo.addons.sf_base.commons.common import Common
|
||||
|
||||
|
||||
class FunctionalCuttingToolEntity(models.Model):
|
||||
_name = 'sf.functional.cutting.tool.entity'
|
||||
_description = '功能刀具列表'
|
||||
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
|
||||
code = fields.Char('编码')
|
||||
rfid = fields.Char('rfid', readonly=True)
|
||||
name = fields.Char('名称')
|
||||
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具名称', readonly=True)
|
||||
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True)
|
||||
sf_cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀具型号')
|
||||
sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
|
||||
group_expand='_read_group_mrs_cutting_tool_type_id', compute_sudo=True)
|
||||
|
||||
functional_tool_diameter = fields.Integer(string='刀具直径(mm)', readonly=True)
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=True)
|
||||
coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精', readonly=True)
|
||||
new_former = fields.Selection([('0', '新'), ('1', '旧')], string='新/旧', readonly=True)
|
||||
tool_loading_length = fields.Float(string='总长度(mm)', readonly=True)
|
||||
functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True)
|
||||
effective_length = fields.Float(string='有效长(mm)', readonly=True)
|
||||
tool_room_num = fields.Integer(string='刀具房数量', readonly=True)
|
||||
line_edge_knife_library_num = fields.Integer(string='线边刀库数量', readonly=True)
|
||||
machine_knife_library_num = fields.Integer(string='机内刀库数量', readonly=True)
|
||||
max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True)
|
||||
alarm_value = fields.Integer(string='报警值(min)', readonly=True)
|
||||
used_value = fields.Integer(string='已使用值(min)', readonly=True)
|
||||
functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')],
|
||||
string='状态', store=True, default='正常')
|
||||
current_location_id = fields.Many2one('stock.location', string='当前位置', readonly=True)
|
||||
current_location = fields.Selection(
|
||||
[('组装后', '组装后'), ('刀具房', '刀具房'), ('线边刀库', '线边刀库'), ('机内刀库', '机内刀库')],
|
||||
string='位置', compute='_compute_current_location_id', store=True)
|
||||
image = fields.Binary('图片', readonly=True)
|
||||
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
|
||||
@api.depends('barcode_id.quant_ids')
|
||||
def _compute_current_location_id(self):
|
||||
for record in self:
|
||||
if record.barcode_id.quant_ids:
|
||||
for quant_id in record.barcode_id.quant_ids:
|
||||
if quant_id.inventory_quantity_auto_apply > 0:
|
||||
record.current_location_id = quant_id.location_id
|
||||
if quant_id.location_id.name == '制造前':
|
||||
record.current_location = '机内刀库'
|
||||
else:
|
||||
record.current_location = quant_id.location_id.name
|
||||
if record.current_location_id:
|
||||
record.sudo().get_location_num()
|
||||
else:
|
||||
record.current_location_id = False
|
||||
record.current_location = False
|
||||
|
||||
def get_location_num(self):
|
||||
"""
|
||||
计算库存位置数量
|
||||
"""
|
||||
for obj in self:
|
||||
if obj.current_location_id:
|
||||
obj.tool_room_num = 0
|
||||
obj.line_edge_knife_library_num = 0
|
||||
obj.machine_knife_library_num = 0
|
||||
if obj.current_location in ['刀具房']:
|
||||
obj.tool_room_num = 1
|
||||
elif "线边刀库" in obj.current_location:
|
||||
obj.line_edge_knife_library_num = 1
|
||||
elif "机内刀库" in obj.current_location:
|
||||
obj.machine_knife_library_num = 1
|
||||
|
||||
@api.model
|
||||
def _read_group_mrs_cutting_tool_type_id(self, categories, domain, order):
|
||||
mrs_cutting_tool_type_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
return categories.browse(mrs_cutting_tool_type_ids)
|
||||
|
||||
# 整体式刀具型号
|
||||
cutting_tool_integral_model_id = fields.Many2one('product.product', string='整体式刀具型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '整体式刀具')])
|
||||
# 刀片型号
|
||||
cutting_tool_blade_model_id = fields.Many2one('product.product', string='刀片型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '刀片')])
|
||||
# 刀杆型号
|
||||
cutting_tool_cutterbar_model_id = fields.Many2one('product.product', string='刀杆型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '刀杆')])
|
||||
# 刀盘型号
|
||||
cutting_tool_cutterpad_model_id = fields.Many2one('product.product', string='刀盘型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '刀盘')])
|
||||
# 刀柄型号
|
||||
cutting_tool_cutterhandle_model_id = fields.Many2one('product.product', string='刀柄型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '刀柄')])
|
||||
# 夹头型号
|
||||
cutting_tool_cutterhead_model_id = fields.Many2one('product.product', string='夹头型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '夹头')])
|
||||
|
||||
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=True)
|
||||
L_D_number = fields.Float(string='L/D值(mm)', readonly=True)
|
||||
hiding_length = fields.Float(string='避空长(mm)', readonly=True)
|
||||
cut_time = fields.Integer(string='已切削时间(min)', readonly=True)
|
||||
cut_length = fields.Float(string='已切削长度(mm)', readonly=True)
|
||||
cut_number = fields.Integer(string='已切削次数', readonly=True)
|
||||
|
||||
suitable_machining_method_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_machining_product_template_tool_entity', '适合加工方式',
|
||||
domain=[('type', '=', '加工能力')], compute='_compute_maintenance_equipment_image')
|
||||
blade_tip_characteristics_id = fields.Many2one(
|
||||
'maintenance.equipment.image', '刀尖特征',
|
||||
domain=[('type', '=', '刀尖特征')])
|
||||
handle_type_id = fields.Many2one(
|
||||
'maintenance.equipment.image', '柄部类型',
|
||||
domain=[('type', '=', '柄部类型')])
|
||||
cutting_direction_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_cutting_product_template_tool_entity', '走刀方向',
|
||||
domain=[('type', '=', '走刀方向')])
|
||||
suitable_coolant_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_coolants_product_template_tool_entity', '适合冷却方式',
|
||||
domain=[('type', '=', '冷却方式')])
|
||||
|
||||
@api.depends('cutting_tool_integral_model_id', 'cutting_tool_blade_model_id')
|
||||
def _compute_maintenance_equipment_image(self):
|
||||
for record in self:
|
||||
if record.cutting_tool_integral_model_id:
|
||||
print(record.cutting_tool_integral_model_id)
|
||||
record.sudo().suitable_machining_method_ids = record.cutting_tool_integral_model_id.suitable_machining_method_ids.ids
|
||||
record.sudo().blade_tip_characteristics_id = record.cutting_tool_integral_model_id.blade_tip_characteristics_id.id
|
||||
record.sudo().handle_type_id = record.cutting_tool_integral_model_id.handle_type_id.id
|
||||
record.sudo().cutting_direction_ids = record.cutting_tool_integral_model_id.cutting_direction_ids.ids
|
||||
record.sudo().suitable_coolant_ids = record.cutting_tool_integral_model_id.suitable_coolant_ids.ids
|
||||
print(record.cutting_tool_integral_model_id.blade_tip_characteristics_id.ids)
|
||||
elif record.cutting_tool_blade_model_id:
|
||||
record.sudo().suitable_machining_method_ids = record.cutting_tool_blade_model_id.suitable_machining_method_ids.ids
|
||||
record.sudo().blade_tip_characteristics_id = record.cutting_tool_blade_model_id.blade_tip_characteristics_id.id
|
||||
record.sudo().handle_type_id = record.cutting_tool_blade_model_id.handle_type_id.id
|
||||
record.sudo().cutting_direction_ids = record.cutting_tool_blade_model_id.cutting_direction_ids.ids
|
||||
record.sudo().suitable_coolant_ids = record.cutting_tool_blade_model_id.suitable_coolant_ids.ids
|
||||
else:
|
||||
record.sudo().suitable_machining_method_ids = []
|
||||
record.sudo().blade_tip_characteristics_id = None
|
||||
record.sudo().handle_type_id = None
|
||||
record.sudo().cutting_direction_ids = []
|
||||
record.sudo().suitable_coolant_ids = []
|
||||
|
||||
def _get_functional_tool_model_ids(self, functional_tool_model_code):
|
||||
functional_tool_model_ids = []
|
||||
for item in functional_tool_model_code:
|
||||
functional_tool_model = self.env['sf.cutting_tool.standard.library'].search([('code', '=', item)])
|
||||
functional_tool_model_ids.append(functional_tool_model.id)
|
||||
return [(6, 0, functional_tool_model_ids)]
|
||||
|
||||
def open_functional_tool_warning(self):
|
||||
action = self.env.ref('sf_tool_management.action_sf_functional_tool_warning')
|
||||
result = action.read()[0]
|
||||
result['domain'] = [('functional_tool_name_id', '=', self.functional_tool_name_id.id)]
|
||||
return result
|
||||
|
||||
def open_stock_move_line(self):
|
||||
action = self.env.ref('sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_act')
|
||||
result = action.read()[0]
|
||||
result['domain'] = [('lot_id', '=', self.barcode_id.id), ('qty_done', '>', 0)]
|
||||
return result
|
||||
|
||||
def open_safety_stock(self):
|
||||
action = self.env.ref('sf_tool_management.sf_real_time_distribution_of_functional_tools_view_act')
|
||||
result = action.read()[0]
|
||||
result['domain'] = [('name', '=', self.name), ('diameter', '=', self.functional_tool_diameter),
|
||||
('knife_tip_r_angle', '=', self.knife_tip_r_angle),
|
||||
('coarse_middle_thin', '=', self.coarse_middle_thin)]
|
||||
return result
|
||||
|
||||
def tool_inventory_displacement_out(self):
|
||||
"""
|
||||
机床当前刀库实时信息接口,功能刀具出库
|
||||
"""
|
||||
# 获取位置对象
|
||||
location_inventory_id = self.current_location_id
|
||||
stock_location_id = self.env['stock.location'].search([('name', '=', '制造前')])
|
||||
# 创建功能刀具该批次/序列号 库存移动和移动历史
|
||||
self.barcode_id.create_stock_quant(location_inventory_id, stock_location_id,
|
||||
self.functional_tool_name_id.id, '机床装刀', self.functional_tool_name_id)
|
||||
|
||||
# ==========刀具组接口==========
|
||||
# def _register_functional_tool_groups(self, obj):
|
||||
# create_url = '/AutoDeviceApi/ToolGroup'
|
||||
# sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
# token = sf_sync_config['token']
|
||||
# sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
# headers = Common.get_headers(obj, token, sf_secret_key)
|
||||
# strurl = sf_sync_config['sf_url'] + create_url
|
||||
# val = {
|
||||
# 'ToolName': obj.name,
|
||||
# 'GroupName': obj.tool_groups_id.name,
|
||||
# 'ToolId': obj.code
|
||||
# }
|
||||
# kw = json.dumps(val, ensure_ascii=False)
|
||||
# r = requests.post(strurl, json={}, data={'kw': kw, 'token': token}, headers=headers)
|
||||
# ret = r.json()
|
||||
# if r == 200:
|
||||
# return "刀具组发送成功"
|
||||
# else:
|
||||
# raise ValidationError("刀具组发送失败")
|
||||
|
||||
# @api.model_create_multi
|
||||
# def create(self, vals):
|
||||
# obj = super(FunctionalCuttingToolEntity, self).create(vals)
|
||||
# # 调用刀具组接口
|
||||
# self._register_functional_tool_groups(obj)
|
||||
# return obj
|
||||
|
||||
|
||||
class FunctionalToolWarning(models.Model):
|
||||
_name = 'sf.functional.tool.warning'
|
||||
_description = '功能刀具预警'
|
||||
|
||||
code = fields.Char('编码', related='functional_tool_name_id.code')
|
||||
rfid = fields.Char('rfid', related='functional_tool_name_id.rfid')
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
|
||||
name = fields.Char('名称', invisible=True, readonly=True, related='functional_tool_name_id.name')
|
||||
# 机床信息
|
||||
production_line_id = fields.Many2one('sf.production.line', string='生产线',
|
||||
group_expand='_read_group_machine_table_name_ids')
|
||||
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='CNC机床')
|
||||
machine_tool_code = fields.Char(string='机台号', related='maintenance_equipment_id.name')
|
||||
machine_table_type_id = fields.Many2one('maintenance.equipment.category', string='机床类型',
|
||||
related='maintenance_equipment_id.category_id')
|
||||
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号',
|
||||
domain="[('equipment_id', '=', maintenance_equipment_id)]")
|
||||
# 功能刀具信息
|
||||
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具名称')
|
||||
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', related='functional_tool_name_id.barcode_id')
|
||||
mrs_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型')
|
||||
diameter = fields.Integer(string='刀具直径(mm)')
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)')
|
||||
# 其他信息
|
||||
install_tool_time = fields.Datetime("刀具组装时间", related='functional_tool_name_id.tool_loading_time')
|
||||
on_board_time = fields.Datetime('上机装刀时间')
|
||||
max_lifetime_value = fields.Integer(string='最大寿命值(min)')
|
||||
alarm_value = fields.Integer(string='报警值(min)')
|
||||
used_value = fields.Integer(string='已使用值(min)')
|
||||
functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')], string='状态')
|
||||
alarm_time = fields.Datetime('报警时间')
|
||||
dispose_user = fields.Char('处理人')
|
||||
dispose_time = fields.Char('处理时间')
|
||||
dispose_func = fields.Char('处理方法/措施', readonly=False)
|
||||
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
|
||||
@api.model
|
||||
def _read_group_machine_table_name_ids(self, categories, domain, order):
|
||||
machine_table_name_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
return categories.browse(machine_table_name_ids)
|
||||
|
||||
def create_tool_warning_record(self, obj):
|
||||
"""
|
||||
机台换刀申请报警状态时,创建功能刀具预警记录
|
||||
"""
|
||||
if obj:
|
||||
for tool in obj.get('tool_changing_apply_id'):
|
||||
self.env['sf.functional.tool.warning'].create({
|
||||
'production_line_id': tool.production_line_id.id,
|
||||
'maintenance_equipment_id': tool.maintenance_equipment_id.id,
|
||||
'machine_tool_code': tool.machine_tool_code,
|
||||
'machine_table_type_id': tool.machine_table_type_id.id,
|
||||
'cutter_spacing_code_id': tool.cutter_spacing_code_id.id,
|
||||
'functional_tool_name_id': tool.functional_tool_name_id.id,
|
||||
'barcode_id': tool.barcode_id.id,
|
||||
'diameter': tool.diameter,
|
||||
'knife_tip_r_angle': tool.knife_tip_r_angle,
|
||||
'max_lifetime_value': tool.max_lifetime_value,
|
||||
'alarm_value': tool.alarm_value,
|
||||
'used_value': tool.used_value,
|
||||
'functional_tool_status': tool.functional_tool_status,
|
||||
'alarm_time': fields.Datetime.now(),
|
||||
})
|
||||
|
||||
|
||||
class StockMoveLine(models.Model):
|
||||
_inherit = 'stock.move.line'
|
||||
_description = '功能刀具出入库记录'
|
||||
_order = 'date desc'
|
||||
|
||||
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具名称')
|
||||
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
|
||||
group_expand='_read_group_functional_tool_type_id')
|
||||
functional_tool_name = fields.Char('刀具名称')
|
||||
diameter = fields.Integer(string='刀具直径(mm)')
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)')
|
||||
install_tool_time = fields.Datetime("刀具组装时间", default=fields.Datetime.now())
|
||||
code = fields.Char('编码')
|
||||
rfid = fields.Char('rfid')
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组')
|
||||
|
||||
@api.model
|
||||
def _read_group_functional_tool_type_id(self, categories, domain, order):
|
||||
names = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
return categories.browse(names)
|
||||
|
||||
|
||||
class RealTimeDistributionOfFunctionalTools(models.Model):
|
||||
_name = 'sf.real.time.distribution.of.functional.tools'
|
||||
_description = '功能刀具安全库存'
|
||||
|
||||
name = fields.Char('功能刀具名称', readonly=True, compute='_compute_name')
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=False, required=True)
|
||||
sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False,
|
||||
group_expand='_read_mrs_cutting_tool_type_ids', store=True)
|
||||
diameter = fields.Integer(string='刀具直径(mm)', readonly=False)
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=False)
|
||||
tool_stock_num = fields.Integer(string='刀具房数量')
|
||||
side_shelf_num = fields.Integer(string='线边刀库数量')
|
||||
on_tool_stock_num = fields.Integer(string='机内刀库数量')
|
||||
tool_stock_total = fields.Integer(string='当前库存量', readonly=True)
|
||||
min_stock_num = fields.Integer('最低库存量')
|
||||
max_stock_num = fields.Integer('最高库存量')
|
||||
batch_replenishment_num = fields.Integer('批次补货量', readonly=True, compute='_compute_batch_replenishment_num')
|
||||
unit = fields.Char('单位')
|
||||
image = fields.Binary('图片', readonly=False)
|
||||
|
||||
coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精', readonly=False)
|
||||
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=False)
|
||||
# 能力特征信息
|
||||
suitable_machining_method_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_machining_product_template_distribution', '适合加工方式',
|
||||
domain=[('type', '=', '加工能力')],
|
||||
related='sf_functional_cutting_tool_entity_ids.suitable_machining_method_ids')
|
||||
blade_tip_characteristics_id = fields.Many2one(
|
||||
'maintenance.equipment.image', '刀尖特征',
|
||||
domain=[('type', '=', '刀尖特征')],
|
||||
related='sf_functional_cutting_tool_entity_ids.blade_tip_characteristics_id')
|
||||
handle_type_id = fields.Many2one(
|
||||
'maintenance.equipment.image', '柄部类型',
|
||||
domain=[('type', '=', '柄部类型')], related='sf_functional_cutting_tool_entity_ids.handle_type_id')
|
||||
cutting_direction_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_cutting_product_template_distribution', '走刀方向',
|
||||
domain=[('type', '=', '走刀方向')], related='sf_functional_cutting_tool_entity_ids.cutting_direction_ids')
|
||||
suitable_coolant_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_coolants_product_template_distribution', '适合冷却方式',
|
||||
domain=[('type', '=', '冷却方式')], related='sf_functional_cutting_tool_entity_ids.suitable_coolant_ids')
|
||||
|
||||
sf_functional_cutting_tool_entity_ids = fields.Many2many('sf.functional.cutting.tool.entity',
|
||||
'sf_functional_cutting_tool_entity_ref',
|
||||
string='功能刀具列表信息', readonly=True)
|
||||
|
||||
sf_functional_tool_assembly_ids = fields.Many2many('sf.functional.tool.assembly', 'sf_functional_tool_assembly_ref',
|
||||
'功能刀具组装单', readonly=True)
|
||||
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
|
||||
@api.depends('tool_groups_id', 'diameter', 'knife_tip_r_angle')
|
||||
def _compute_name(self):
|
||||
for obj in self:
|
||||
if obj.tool_groups_id:
|
||||
obj.sudo().name = '%s-D%sR%s' % (obj.tool_groups_id.name, obj.diameter, obj.knife_tip_r_angle)
|
||||
else:
|
||||
obj.sudo().name = None
|
||||
|
||||
@api.constrains('min_stock_num', 'max_stock_num')
|
||||
def _check_stock_num(self):
|
||||
for obj in self:
|
||||
if obj.min_stock_num > obj.max_stock_num:
|
||||
raise ValidationError('【最低安全库存】不能高于【最高安全库存】!!!')
|
||||
|
||||
@api.model
|
||||
def _read_mrs_cutting_tool_type_ids(self, categories, domain, order):
|
||||
mrs_cutting_tool_type_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
return categories.browse(mrs_cutting_tool_type_ids)
|
||||
|
||||
@api.depends('sf_functional_cutting_tool_entity_ids', 'min_stock_num', 'max_stock_num')
|
||||
def _compute_batch_replenishment_num(self):
|
||||
for tool in self:
|
||||
if tool:
|
||||
# 判断功能刀具组装单是否已经完成
|
||||
tool.sudo().estimate_functional_tool_assembly_ids(tool)
|
||||
tool.sudo().get_stock_num(tool)
|
||||
# 计算当前库存量
|
||||
tool.sudo().tool_stock_total = tool.tool_stock_num + tool.side_shelf_num + tool.on_tool_stock_num
|
||||
# 如果当前库存量小于最低库存量,计算批次补货量
|
||||
tool.sudo().open_batch_replenishment_num(tool)
|
||||
|
||||
def open_batch_replenishment_num(self, tool):
|
||||
"""
|
||||
计算批次补货量
|
||||
"""
|
||||
if tool.tool_stock_total < tool.min_stock_num:
|
||||
tool.sudo().batch_replenishment_num = tool.max_stock_num - tool.tool_stock_total
|
||||
# 根据判断创建功能刀具组装单
|
||||
if not tool.sf_functional_tool_assembly_ids and re.match(r'^\d+$', str(tool.id)):
|
||||
for i in range(tool.batch_replenishment_num):
|
||||
tool.sudo().create_functional_tool_assembly(tool)
|
||||
print(i, ": ", tool.sf_functional_tool_assembly_ids)
|
||||
else:
|
||||
tool.sudo().batch_replenishment_num = 0
|
||||
|
||||
def create_functional_tool_assembly(self, tool):
|
||||
"""
|
||||
创建功能刀具组装单
|
||||
"""
|
||||
functional_tool_assembly = tool.env['sf.functional.tool.assembly'].sudo().create({
|
||||
'functional_tool_name': tool.name,
|
||||
'functional_tool_type_id': tool.sf_cutting_tool_type_id.id,
|
||||
'tool_groups_id': tool.tool_groups_id.id,
|
||||
'functional_tool_diameter': tool.diameter,
|
||||
'knife_tip_r_angle': tool.knife_tip_r_angle,
|
||||
'coarse_middle_thin': tool.coarse_middle_thin,
|
||||
'loading_task_source': '2',
|
||||
'use_tool_time': fields.Datetime.now() + timedelta(hours=4),
|
||||
'applicant': '系统自动',
|
||||
'apply_time': fields.Datetime.now(),
|
||||
'whether_standard_knife': tool.whether_standard_knife,
|
||||
'reason_for_applying': '安全库存',
|
||||
})
|
||||
tool.sudo().sf_functional_tool_assembly_ids = [(4, functional_tool_assembly.id)]
|
||||
|
||||
def estimate_functional_tool_assembly_ids(self, tool):
|
||||
"""
|
||||
判断功能刀具组装单是否完成,如果全部完成清空sf_functional_tool_assembly_ids的数据
|
||||
"""
|
||||
for sf_functional_tool_assembly_id in tool.sf_functional_tool_assembly_ids:
|
||||
if sf_functional_tool_assembly_id.assemble_status == '0':
|
||||
return False
|
||||
tool.sudo().sf_functional_tool_assembly_ids = []
|
||||
|
||||
def get_stock_num(self, tool):
|
||||
"""
|
||||
计算刀具房数量、线边刀库数量、机内刀库数量
|
||||
"""
|
||||
if tool:
|
||||
tool.tool_stock_num = 0
|
||||
tool.side_shelf_num = 0
|
||||
tool.on_tool_stock_num = 0
|
||||
if tool.sf_functional_cutting_tool_entity_ids:
|
||||
for cutting_tool in tool.sf_functional_cutting_tool_entity_ids:
|
||||
if cutting_tool.tool_room_num > 0:
|
||||
tool.tool_stock_num += 1
|
||||
elif cutting_tool.line_edge_knife_library_num > 0:
|
||||
tool.side_shelf_num += 1
|
||||
elif cutting_tool.machine_knife_library_num > 0:
|
||||
tool.on_tool_stock_num += 1
|
||||
|
||||
def create_or_edit_safety_stock(self, vals, sf_functional_cutting_tool_entity_ids):
|
||||
"""
|
||||
根据传入的信息新增或者更新功能刀具安全库存的信息
|
||||
"""
|
||||
# 根据功能刀具名称、刀具组、直径或尖刀R角、粗/中/精查询该功能刀具是否已经存在
|
||||
record = self.env['sf.real.time.distribution.of.functional.tools'].search(
|
||||
[('name', '=', vals['name']), ('sf_cutting_tool_type_id', '=', vals['sf_cutting_tool_type_id']),
|
||||
('diameter', '=', vals['diameter']), ('knife_tip_r_angle', '=', vals['knife_tip_r_angle']),
|
||||
('coarse_middle_thin', '=', vals['coarse_middle_thin']), ('tool_groups_id', '=', vals['tool_groups_id'])])
|
||||
if len(record) > 0:
|
||||
for obj in record:
|
||||
obj.write({'sf_functional_cutting_tool_entity_ids': [(4, sf_functional_cutting_tool_entity_ids.id)]})
|
||||
else:
|
||||
vals['sf_functional_cutting_tool_entity_ids'] = sf_functional_cutting_tool_entity_ids.ids
|
||||
self.env['sf.real.time.distribution.of.functional.tools'].create(vals)
|
||||
|
||||
status_create = fields.Boolean('是否是新增状态', default=True)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
vals['status_create'] = False
|
||||
records = super(RealTimeDistributionOfFunctionalTools, self).create(vals_list)
|
||||
return records
|
||||
|
||||
def write(self, vals):
|
||||
res = super().write(vals)
|
||||
for item in self:
|
||||
if item:
|
||||
if vals.get('min_stock_num') or vals.get('max_stock_num'):
|
||||
item.enroll_functional_tool_real_time_distribution()
|
||||
return res
|
||||
|
||||
|
||||
class MachineTableToolChangingApply(models.Model):
|
||||
@@ -502,7 +29,7 @@ class MachineTableToolChangingApply(models.Model):
|
||||
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', store=True,
|
||||
domain=[('product_id.name', '=', '功能刀具')],
|
||||
related='functional_tool_name_id.barcode_id')
|
||||
rfid = fields.Char('rfid', related='functional_tool_name_id.rfid')
|
||||
rfid = fields.Char('Rfid', related='functional_tool_name_id.rfid')
|
||||
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', domain=[('assemble_status', '=', '1')],
|
||||
string='功能刀具名称')
|
||||
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
|
||||
@@ -666,7 +193,7 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
|
||||
machine_table_name_id = fields.Many2one('maintenance.equipment', string='机床名称',
|
||||
domain="[('production_line_id', '=', production_line_id)]")
|
||||
machine_table_name = fields.Char(string='机台号', readonly=True, related='machine_table_name_id.name')
|
||||
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号', required=True,
|
||||
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号',
|
||||
domain="[('equipment_id', '=', machine_table_name_id)]")
|
||||
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True)
|
||||
need_knife_time = fields.Datetime(string='用刀时间', readonly=False)
|
||||
@@ -676,19 +203,20 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
|
||||
|
||||
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号',
|
||||
domain=[('product_id.name', '=', '功能刀具')])
|
||||
functional_tool_name = fields.Char(string='功能刀具名称', compute='_compute_functional_tool_name')
|
||||
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False)
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组')
|
||||
diameter = fields.Integer(string='刀具直径(mm)', readonly=False)
|
||||
tool_included_angle = fields.Float(string='刀尖R角(mm)', readonly=False)
|
||||
tool_loading_length = fields.Float(string='总长度(mm)', readonly=False)
|
||||
functional_tool_name = fields.Char(string='功能刀具名称', readonly=True)
|
||||
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
|
||||
compute='_compute_tool_number', store=True)
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', compute='_compute_tool_number', store=True)
|
||||
diameter = fields.Integer(string='刀具直径(mm)', compute='_compute_tool_number', store=True)
|
||||
tool_included_angle = fields.Float(string='刀尖R角(mm)', compute='_compute_tool_number', store=True)
|
||||
tool_loading_length = fields.Float(string='总长度(mm)', compute='_compute_tool_number', store=True)
|
||||
extension_length = fields.Float(string='伸出长(mm)')
|
||||
effective_length = fields.Float(string='有效长(mm)')
|
||||
new_former = fields.Selection([('0', '新'), ('1', '旧')], string='新/旧', readonly=False, default='0')
|
||||
coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], default='3',
|
||||
string='粗/中/精', readonly=False)
|
||||
L_D = fields.Float(string='L/D值', readonly=False)
|
||||
clearance_length = fields.Float(string='避空长(mm)', readonly=False)
|
||||
clearance_length = fields.Float(string='避空长(mm)', compute='_compute_tool_number', store=True)
|
||||
required_cutting_time = fields.Integer(string='需切削时长', readonly=False)
|
||||
process_type = fields.Char('加工类型')
|
||||
margin_x_y = fields.Float('余量_X/Y')
|
||||
@@ -704,15 +232,24 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
|
||||
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
|
||||
@api.depends('diameter', 'tool_included_angle', 'tool_groups_id')
|
||||
def _compute_functional_tool_name(self):
|
||||
for obj in self:
|
||||
if obj.tool_groups_id:
|
||||
obj.functional_tool_name = '%s-D%sR%s' % (
|
||||
obj.tool_groups_id.name, obj.diameter,
|
||||
obj.tool_included_angle)
|
||||
@api.depends('functional_tool_name')
|
||||
def _compute_tool_number(self):
|
||||
for item in self:
|
||||
inventory = self.env['sf.tool.inventory'].sudo().search([('name', '=', item.functional_tool_name)])
|
||||
if inventory:
|
||||
item.functional_tool_type_id = inventory.functional_cutting_tool_model_id.id
|
||||
item.tool_groups_id = inventory.tool_groups_id.id
|
||||
item.diameter = int(inventory.diameter)
|
||||
item.tool_included_angle = inventory.angle
|
||||
item.tool_loading_length = inventory.tool_length
|
||||
item.clearance_length = inventory.blade_length
|
||||
else:
|
||||
obj.functional_tool_name = None
|
||||
item.functional_tool_type_id = False
|
||||
item.tool_groups_id = False
|
||||
item.diameter = 0
|
||||
item.tool_included_angle = 0
|
||||
item.tool_loading_length = 0
|
||||
item.clearance_length = 0
|
||||
|
||||
@api.model
|
||||
def _read_group_names(self, categories, domain, order):
|
||||
@@ -786,10 +323,9 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
|
||||
根据传入的工单信息,查询是否有需要的功能刀具,如果没有则生成CAM工单程序用刀计划
|
||||
"""
|
||||
status = False
|
||||
if cnc_processing.functional_tool_type_id and cnc_processing.cutting_tool_name:
|
||||
if cnc_processing.cutting_tool_name:
|
||||
functional_tools = self.env['sf.real.time.distribution.of.functional.tools'].sudo().search(
|
||||
[('sf_cutting_tool_type_id', '=', cnc_processing.functional_tool_type_id.id),
|
||||
('name', '=', cnc_processing.cutting_tool_name)])
|
||||
[('name', '=', cnc_processing.cutting_tool_name)])
|
||||
if functional_tools:
|
||||
for functional_tool in functional_tools:
|
||||
if functional_tool.on_tool_stock_num == 0:
|
||||
@@ -802,7 +338,6 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
|
||||
'name': cnc_processing.workorder_id.production_id.name,
|
||||
'cam_procedure_code': cnc_processing.program_name,
|
||||
'filename': cnc_processing.cnc_id.name,
|
||||
'functional_tool_type_id': cnc_processing.functional_tool_type_id.id,
|
||||
'functional_tool_name': cnc_processing.cutting_tool_name,
|
||||
'cam_cutter_spacing_code': cnc_processing.cutting_tool_no,
|
||||
'process_type': cnc_processing.processing_type,
|
||||
@@ -813,8 +348,11 @@ class CAMWorkOrderProgramKnifePlan(models.Model):
|
||||
'shank_model': cnc_processing.cutting_tool_handle_type,
|
||||
'estimated_processing_time': cnc_processing.estimated_processing_time,
|
||||
})
|
||||
logging.info('CAM工单程序用刀计划创建成功!!!')
|
||||
# 创建装刀请求
|
||||
knife_plan.apply_for_tooling()
|
||||
else:
|
||||
logging.info('功能刀具【%s】满足CNC用刀需求!!!')
|
||||
|
||||
|
||||
class FunctionalToolAssembly(models.Model):
|
||||
@@ -825,10 +363,10 @@ class FunctionalToolAssembly(models.Model):
|
||||
@api.depends('functional_tool_name')
|
||||
def _compute_name(self):
|
||||
for obj in self:
|
||||
obj.name = obj.after_assembly_functional_tool_name
|
||||
obj.name = obj.assembly_order_code
|
||||
|
||||
code = fields.Char('功能刀具编码', readonly=True)
|
||||
rfid = fields.Char('rfid', readonly=True)
|
||||
rfid = fields.Char('Rfid', readonly=True)
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=True)
|
||||
name = fields.Char(string='名称', readonly=True, compute='_compute_name')
|
||||
assembly_order_code = fields.Char(string='组装单编码', readonly=True)
|
||||
@@ -870,56 +408,141 @@ class FunctionalToolAssembly(models.Model):
|
||||
return categories.browse(functional_tool_type_ids)
|
||||
|
||||
# 刀具物料信息
|
||||
# 整体式刀具型号
|
||||
integral_code_id = fields.Many2one('stock.lot', string='整体式刀具序列号', readonly=True)
|
||||
# ==============整体式刀具型号============
|
||||
integral_freight_barcode = fields.Char('整体式刀具货位')
|
||||
integral_product_id = fields.Many2one('product.product', string='整体式刀具名称',
|
||||
compute='_compute_integral_product_id', store=True)
|
||||
cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号',
|
||||
related='integral_code_id.product_id.cutting_tool_model_id')
|
||||
integral_name = fields.Char('整体式刀具名称', related='integral_code_id.product_id.name')
|
||||
related='integral_product_id.cutting_tool_model_id')
|
||||
integral_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='整体式刀具规格',
|
||||
related='integral_code_id.product_id.specification_id')
|
||||
related='integral_product_id.specification_id')
|
||||
sf_tool_brand_id_1 = fields.Many2one('sf.machine.brand', string='整体式刀具品牌',
|
||||
related='integral_code_id.product_id.brand_id')
|
||||
# 刀片型号
|
||||
blade_code_id = fields.Many2one('stock.lot', '刀片序列号', readonly=True)
|
||||
cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号',
|
||||
related='blade_code_id.product_id.cutting_tool_model_id')
|
||||
blade_name = fields.Char('刀片名称', related='blade_code_id.product_id.name')
|
||||
blade_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀片规格',
|
||||
related='blade_code_id.product_id.specification_id')
|
||||
sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_code_id.product_id.brand_id')
|
||||
# 刀杆型号
|
||||
bar_code_id = fields.Many2one('stock.lot', '刀杆序列号', readonly=True)
|
||||
cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
|
||||
related='bar_code_id.product_id.cutting_tool_model_id')
|
||||
bar_name = fields.Char('刀杆名称', related='bar_code_id.product_id.name')
|
||||
bar_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀杆规格',
|
||||
related='bar_code_id.product_id.specification_id')
|
||||
sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_code_id.product_id.brand_id')
|
||||
# 刀盘型号
|
||||
pad_code_id = fields.Many2one('stock.lot', '刀盘序列号', readonly=True)
|
||||
cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
|
||||
related='pad_code_id.product_id.cutting_tool_model_id')
|
||||
pad_name = fields.Char('刀盘名称', related='pad_code_id.product_id.name')
|
||||
pad_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀盘规格',
|
||||
related='pad_code_id.product_id.specification_id')
|
||||
sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_code_id.product_id.brand_id')
|
||||
# 刀柄型号
|
||||
handle_code_id = fields.Many2one('stock.lot', '刀柄序列号', readonly=True)
|
||||
cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号',
|
||||
related='handle_code_id.product_id.cutting_tool_model_id')
|
||||
handle_name = fields.Char('刀柄名称', related='handle_code_id.product_id.name')
|
||||
handle_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀柄规格',
|
||||
related='handle_code_id.product_id.specification_id')
|
||||
sf_tool_brand_id_5 = fields.Many2one('sf.machine.brand', '刀柄品牌', related='handle_code_id.product_id.brand_id')
|
||||
# 夹头型号
|
||||
chuck_code_id = fields.Many2one('stock.lot', '夹头序列号', readonly=True)
|
||||
cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
|
||||
related='chuck_code_id.product_id.cutting_tool_model_id')
|
||||
chuck_name = fields.Char('夹头名称', related='chuck_code_id.product_id.name')
|
||||
chuck_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='夹头规格',
|
||||
related='chuck_code_id.product_id.specification_id')
|
||||
sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_code_id.product_id.brand_id')
|
||||
related='integral_product_id.brand_id')
|
||||
|
||||
@api.depends('integral_freight_barcode')
|
||||
def _compute_integral_product_id(self):
|
||||
for item in self:
|
||||
if item.integral_freight_barcode:
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.integral_freight_barcode)])
|
||||
if location:
|
||||
item.integral_product_id = location.product_id.id
|
||||
else:
|
||||
item.integral_product_id = False
|
||||
|
||||
# =================刀片型号=============
|
||||
blade_freight_barcode = fields.Char('刀片货位')
|
||||
blade_product_id = fields.Many2one('product.product', string='刀片名称', compute='_compute_blade_product_id',
|
||||
store=True)
|
||||
cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号',
|
||||
related='blade_product_id.cutting_tool_model_id')
|
||||
blade_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀片规格',
|
||||
related='blade_product_id.specification_id')
|
||||
sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id')
|
||||
|
||||
@api.depends('blade_freight_barcode')
|
||||
def _compute_blade_product_id(self):
|
||||
for item in self:
|
||||
if item.integral_freight_barcode:
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.blade_freight_barcode)])
|
||||
if location:
|
||||
item.blade_product_id = location.product_id.id
|
||||
else:
|
||||
item.blade_product_id = False
|
||||
|
||||
# ==============刀杆型号================
|
||||
bar_freight_barcode = fields.Char('刀杆货位')
|
||||
bar_product_id = fields.Many2one('product.product', string='刀杆名称', compute='_compute_bar_product_id',
|
||||
store=True)
|
||||
cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
|
||||
related='bar_product_id.cutting_tool_model_id')
|
||||
bar_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀杆规格',
|
||||
related='bar_product_id.specification_id')
|
||||
sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id')
|
||||
|
||||
@api.depends('bar_freight_barcode')
|
||||
def _compute_bar_product_id(self):
|
||||
for item in self:
|
||||
if item.integral_freight_barcode:
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.bar_freight_barcode)])
|
||||
if location:
|
||||
item.bar_product_id = location.product_id.id
|
||||
else:
|
||||
item.bar_product_id = False
|
||||
|
||||
# =============刀盘型号================
|
||||
pad_freight_barcode = fields.Char('刀盘货位')
|
||||
pad_product_id = fields.Many2one('product.product', string='刀盘名称', compute='_compute_pad_product_id',
|
||||
store=True)
|
||||
cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
|
||||
related='pad_product_id.cutting_tool_model_id')
|
||||
pad_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀盘规格',
|
||||
related='pad_product_id.specification_id')
|
||||
sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_product_id.brand_id')
|
||||
|
||||
@api.depends('pad_freight_barcode')
|
||||
def _compute_pad_product_id(self):
|
||||
for item in self:
|
||||
if item.integral_freight_barcode:
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.pad_freight_barcode)])
|
||||
if location:
|
||||
item.pad_product_id = location.product_id.id
|
||||
else:
|
||||
item.pad_product_id = False
|
||||
|
||||
# ==============刀柄型号==============
|
||||
handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_handle_product_id', store=True)
|
||||
handle_code_id = fields.Many2one('stock.lot', '刀柄序列号')
|
||||
handle_product_id = fields.Many2one('product.product', string='刀柄名称', compute='_compute_handle_product_id',
|
||||
store=True)
|
||||
cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号',
|
||||
related='handle_product_id.cutting_tool_model_id')
|
||||
handle_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀柄规格',
|
||||
related='handle_product_id.specification_id')
|
||||
sf_tool_brand_id_5 = fields.Many2one('sf.machine.brand', '刀柄品牌', related='handle_product_id.brand_id')
|
||||
|
||||
@api.depends('handle_code_id')
|
||||
def _compute_handle_product_id(self):
|
||||
for item in self:
|
||||
if item.handle_code_id:
|
||||
item.handle_product_id = item.handle_code_id.product_id.id
|
||||
item.handle_freight_rfid = item.handle_code_id.rfid
|
||||
else:
|
||||
item.handle_product_id = False
|
||||
item.handle_freight_rfid = False
|
||||
|
||||
# ==============夹头型号==============
|
||||
chuck_freight_barcode = fields.Char('夹头货位')
|
||||
chuck_product_id = fields.Many2one('product.product', string='夹头名称', compute='_compute_chuck_product_id',
|
||||
store=True)
|
||||
cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
|
||||
related='chuck_product_id.cutting_tool_model_id')
|
||||
chuck_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='夹头规格',
|
||||
related='chuck_product_id.specification_id')
|
||||
sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_product_id.brand_id')
|
||||
|
||||
@api.depends('chuck_freight_barcode')
|
||||
def _compute_chuck_product_id(self):
|
||||
for item in self:
|
||||
if item.integral_freight_barcode:
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', item.chuck_freight_barcode)])
|
||||
if location:
|
||||
item.chuck_product_id = location.product_id.id
|
||||
else:
|
||||
item.chuck_product_id = False
|
||||
|
||||
# ==================待删除字段==================
|
||||
blade_name = fields.Char('')
|
||||
integral_name = fields.Char('')
|
||||
blade_code_id = fields.Many2one('stock.lot', '刀片序列号')
|
||||
integral_code_id = fields.Many2one('stock.lot', '整体式刀具序列号')
|
||||
bar_code_id = fields.Many2one('stock.lot', '刀杆序列号')
|
||||
bar_name = fields.Char('')
|
||||
pad_code_id = fields.Many2one('stock.lot', '刀盘序列号')
|
||||
pad_name = fields.Char('')
|
||||
handle_name = fields.Char('')
|
||||
chuck_code_id = fields.Many2one('stock.lot', '夹头序列号')
|
||||
chuck_name = fields.Char('')
|
||||
# ==============================================
|
||||
# 组装功能刀具参数信息
|
||||
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True)
|
||||
after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', readonly=True)
|
||||
|
||||
481
sf_tool_management/models/functional_tool.py
Normal file
481
sf_tool_management/models/functional_tool.py
Normal file
@@ -0,0 +1,481 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
from datetime import timedelta
|
||||
from odoo import SUPERUSER_ID
|
||||
from odoo import fields, models, api
|
||||
from odoo.exceptions import ValidationError
|
||||
|
||||
|
||||
class FunctionalCuttingToolEntity(models.Model):
|
||||
_name = 'sf.functional.cutting.tool.entity'
|
||||
_description = '功能刀具列表'
|
||||
|
||||
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具组装单', readonly=True)
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
|
||||
code = fields.Char('编码')
|
||||
rfid = fields.Char('Rfid', readonly=True)
|
||||
name = fields.Char('名称')
|
||||
tool_name_id = fields.Many2one('sf.tool.inventory', '功能刀具名称')
|
||||
sf_cutting_tool_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀具型号')
|
||||
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', readonly=True)
|
||||
sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型',
|
||||
group_expand='_read_group_mrs_cutting_tool_type_id', compute_sudo=True)
|
||||
|
||||
functional_tool_diameter = fields.Integer(string='刀具直径(mm)', readonly=True)
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=True)
|
||||
coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精', readonly=True)
|
||||
new_former = fields.Selection([('0', '新'), ('1', '旧')], string='新/旧', readonly=True)
|
||||
tool_loading_length = fields.Float(string='总长度(mm)', readonly=True)
|
||||
functional_tool_length = fields.Float(string='伸出长(mm)', readonly=True)
|
||||
effective_length = fields.Float(string='有效长(mm)', readonly=True)
|
||||
tool_room_num = fields.Integer(string='刀具房数量', readonly=True)
|
||||
line_edge_knife_library_num = fields.Integer(string='线边刀库数量', readonly=True)
|
||||
machine_knife_library_num = fields.Integer(string='机内刀库数量', readonly=True)
|
||||
max_lifetime_value = fields.Integer(string='最大寿命值(min)', readonly=True)
|
||||
alarm_value = fields.Integer(string='报警值(min)', readonly=True)
|
||||
used_value = fields.Integer(string='已使用值(min)', readonly=True)
|
||||
functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')],
|
||||
string='状态', store=True, default='正常')
|
||||
current_location_id = fields.Many2one('stock.location', string='当前位置', readonly=True)
|
||||
current_location = fields.Selection(
|
||||
[('组装后', '组装后'), ('刀具房', '刀具房'), ('线边刀库', '线边刀库'), ('机内刀库', '机内刀库')],
|
||||
string='位置', compute='_compute_current_location_id', store=True)
|
||||
image = fields.Binary('图片', readonly=True)
|
||||
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
|
||||
@api.depends('barcode_id.quant_ids')
|
||||
def _compute_current_location_id(self):
|
||||
for record in self:
|
||||
if record.barcode_id.quant_ids:
|
||||
for quant_id in record.barcode_id.quant_ids:
|
||||
if quant_id.inventory_quantity_auto_apply > 0:
|
||||
record.current_location_id = quant_id.location_id
|
||||
if quant_id.location_id.name == '制造前':
|
||||
record.current_location = '机内刀库'
|
||||
else:
|
||||
record.current_location = quant_id.location_id.name
|
||||
if record.current_location_id:
|
||||
record.sudo().get_location_num()
|
||||
else:
|
||||
record.current_location_id = False
|
||||
record.current_location = False
|
||||
|
||||
def get_location_num(self):
|
||||
"""
|
||||
计算库存位置数量
|
||||
"""
|
||||
for obj in self:
|
||||
if obj.current_location_id:
|
||||
obj.tool_room_num = 0
|
||||
obj.line_edge_knife_library_num = 0
|
||||
obj.machine_knife_library_num = 0
|
||||
if obj.current_location in ['刀具房']:
|
||||
obj.tool_room_num = 1
|
||||
elif "线边刀库" in obj.current_location:
|
||||
obj.line_edge_knife_library_num = 1
|
||||
elif "机内刀库" in obj.current_location:
|
||||
obj.machine_knife_library_num = 1
|
||||
|
||||
@api.model
|
||||
def _read_group_mrs_cutting_tool_type_id(self, categories, domain, order):
|
||||
mrs_cutting_tool_type_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
return categories.browse(mrs_cutting_tool_type_ids)
|
||||
|
||||
# 整体式刀具型号
|
||||
cutting_tool_integral_model_id = fields.Many2one('product.product', string='整体式刀具型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '整体式刀具')])
|
||||
# 刀片型号
|
||||
cutting_tool_blade_model_id = fields.Many2one('product.product', string='刀片型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '刀片')])
|
||||
# 刀杆型号
|
||||
cutting_tool_cutterbar_model_id = fields.Many2one('product.product', string='刀杆型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '刀杆')])
|
||||
# 刀盘型号
|
||||
cutting_tool_cutterpad_model_id = fields.Many2one('product.product', string='刀盘型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '刀盘')])
|
||||
# 刀柄型号
|
||||
cutting_tool_cutterhandle_model_id = fields.Many2one('product.product', string='刀柄型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '刀柄')])
|
||||
# 夹头型号
|
||||
cutting_tool_cutterhead_model_id = fields.Many2one('product.product', string='夹头型号', readonly=True,
|
||||
domain=[('cutting_tool_material_id', '=', '夹头')])
|
||||
|
||||
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=True)
|
||||
L_D_number = fields.Float(string='L/D值(mm)', readonly=True)
|
||||
hiding_length = fields.Float(string='避空长(mm)', readonly=True)
|
||||
cut_time = fields.Integer(string='已切削时间(min)', readonly=True)
|
||||
cut_length = fields.Float(string='已切削长度(mm)', readonly=True)
|
||||
cut_number = fields.Integer(string='已切削次数', readonly=True)
|
||||
|
||||
suitable_machining_method_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_machining_product_template_tool_entity', '适合加工方式',
|
||||
domain=[('type', '=', '加工能力')], compute='_compute_maintenance_equipment_image')
|
||||
blade_tip_characteristics_id = fields.Many2one(
|
||||
'maintenance.equipment.image', '刀尖特征',
|
||||
domain=[('type', '=', '刀尖特征')])
|
||||
handle_type_id = fields.Many2one(
|
||||
'maintenance.equipment.image', '柄部类型',
|
||||
domain=[('type', '=', '柄部类型')])
|
||||
cutting_direction_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_cutting_product_template_tool_entity', '走刀方向',
|
||||
domain=[('type', '=', '走刀方向')])
|
||||
suitable_coolant_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_coolants_product_template_tool_entity', '适合冷却方式',
|
||||
domain=[('type', '=', '冷却方式')])
|
||||
|
||||
@api.depends('cutting_tool_integral_model_id', 'cutting_tool_blade_model_id')
|
||||
def _compute_maintenance_equipment_image(self):
|
||||
for record in self:
|
||||
if record.cutting_tool_integral_model_id:
|
||||
print(record.cutting_tool_integral_model_id)
|
||||
record.sudo().suitable_machining_method_ids = record.cutting_tool_integral_model_id.suitable_machining_method_ids.ids
|
||||
record.sudo().blade_tip_characteristics_id = record.cutting_tool_integral_model_id.blade_tip_characteristics_id.id
|
||||
record.sudo().handle_type_id = record.cutting_tool_integral_model_id.handle_type_id.id
|
||||
record.sudo().cutting_direction_ids = record.cutting_tool_integral_model_id.cutting_direction_ids.ids
|
||||
record.sudo().suitable_coolant_ids = record.cutting_tool_integral_model_id.suitable_coolant_ids.ids
|
||||
print(record.cutting_tool_integral_model_id.blade_tip_characteristics_id.ids)
|
||||
elif record.cutting_tool_blade_model_id:
|
||||
record.sudo().suitable_machining_method_ids = record.cutting_tool_blade_model_id.suitable_machining_method_ids.ids
|
||||
record.sudo().blade_tip_characteristics_id = record.cutting_tool_blade_model_id.blade_tip_characteristics_id.id
|
||||
record.sudo().handle_type_id = record.cutting_tool_blade_model_id.handle_type_id.id
|
||||
record.sudo().cutting_direction_ids = record.cutting_tool_blade_model_id.cutting_direction_ids.ids
|
||||
record.sudo().suitable_coolant_ids = record.cutting_tool_blade_model_id.suitable_coolant_ids.ids
|
||||
else:
|
||||
record.sudo().suitable_machining_method_ids = []
|
||||
record.sudo().blade_tip_characteristics_id = None
|
||||
record.sudo().handle_type_id = None
|
||||
record.sudo().cutting_direction_ids = []
|
||||
record.sudo().suitable_coolant_ids = []
|
||||
|
||||
def _get_functional_tool_model_ids(self, functional_tool_model_code):
|
||||
functional_tool_model_ids = []
|
||||
for item in functional_tool_model_code:
|
||||
functional_tool_model = self.env['sf.cutting_tool.standard.library'].search([('code', '=', item)])
|
||||
functional_tool_model_ids.append(functional_tool_model.id)
|
||||
return [(6, 0, functional_tool_model_ids)]
|
||||
|
||||
def open_functional_tool_warning(self):
|
||||
action = self.env.ref('sf_tool_management.action_sf_functional_tool_warning')
|
||||
result = action.read()[0]
|
||||
result['domain'] = [('functional_tool_name_id', '=', self.functional_tool_name_id.id)]
|
||||
return result
|
||||
|
||||
def open_stock_move_line(self):
|
||||
action = self.env.ref('sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_act')
|
||||
result = action.read()[0]
|
||||
result['domain'] = [('lot_id', '=', self.barcode_id.id), ('qty_done', '>', 0)]
|
||||
return result
|
||||
|
||||
def open_safety_stock(self):
|
||||
action = self.env.ref('sf_tool_management.sf_real_time_distribution_of_functional_tools_view_act')
|
||||
result = action.read()[0]
|
||||
result['domain'] = [('name', '=', self.name), ('diameter', '=', self.functional_tool_diameter),
|
||||
('knife_tip_r_angle', '=', self.knife_tip_r_angle),
|
||||
('coarse_middle_thin', '=', self.coarse_middle_thin)]
|
||||
return result
|
||||
|
||||
def tool_inventory_displacement_out(self):
|
||||
"""
|
||||
机床当前刀库实时信息接口,功能刀具出库
|
||||
"""
|
||||
# 获取位置对象
|
||||
location_inventory_id = self.current_location_id
|
||||
stock_location_id = self.env['stock.location'].search([('name', '=', '制造前')])
|
||||
# 创建功能刀具该批次/序列号 库存移动和移动历史
|
||||
self.barcode_id.create_stock_quant(location_inventory_id, stock_location_id,
|
||||
self.functional_tool_name_id.id, '机床装刀', self.functional_tool_name_id)
|
||||
|
||||
# ==========刀具组接口==========
|
||||
# def _register_functional_tool_groups(self, obj):
|
||||
# create_url = '/AutoDeviceApi/ToolGroup'
|
||||
# sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
# token = sf_sync_config['token']
|
||||
# sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
# headers = Common.get_headers(obj, token, sf_secret_key)
|
||||
# strurl = sf_sync_config['sf_url'] + create_url
|
||||
# val = {
|
||||
# 'ToolName': obj.name,
|
||||
# 'GroupName': obj.tool_groups_id.name,
|
||||
# 'ToolId': obj.code
|
||||
# }
|
||||
# kw = json.dumps(val, ensure_ascii=False)
|
||||
# r = requests.post(strurl, json={}, data={'kw': kw, 'token': token}, headers=headers)
|
||||
# ret = r.json()
|
||||
# if r == 200:
|
||||
# return "刀具组发送成功"
|
||||
# else:
|
||||
# raise ValidationError("刀具组发送失败")
|
||||
|
||||
# @api.model_create_multi
|
||||
# def create(self, vals):
|
||||
# obj = super(FunctionalCuttingToolEntity, self).create(vals)
|
||||
# # 调用刀具组接口
|
||||
# self._register_functional_tool_groups(obj)
|
||||
# return obj
|
||||
|
||||
|
||||
class FunctionalToolWarning(models.Model):
|
||||
_name = 'sf.functional.tool.warning'
|
||||
_description = '功能刀具预警'
|
||||
|
||||
code = fields.Char('编码', related='functional_tool_name_id.code')
|
||||
rfid = fields.Char('Rfid', related='functional_tool_name_id.rfid')
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', related='functional_tool_name_id.tool_groups_id')
|
||||
name = fields.Char('名称', invisible=True, readonly=True, related='functional_tool_name_id.name')
|
||||
# 机床信息
|
||||
production_line_id = fields.Many2one('sf.production.line', string='生产线',
|
||||
group_expand='_read_group_machine_table_name_ids')
|
||||
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='CNC机床')
|
||||
machine_tool_code = fields.Char(string='机台号', related='maintenance_equipment_id.name')
|
||||
machine_table_type_id = fields.Many2one('maintenance.equipment.category', string='机床类型',
|
||||
related='maintenance_equipment_id.category_id')
|
||||
cutter_spacing_code_id = fields.Many2one('maintenance.equipment.tool', string='刀位号',
|
||||
domain="[('equipment_id', '=', maintenance_equipment_id)]")
|
||||
# 功能刀具信息
|
||||
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具名称')
|
||||
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号', related='functional_tool_name_id.barcode_id')
|
||||
mrs_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型')
|
||||
diameter = fields.Integer(string='刀具直径(mm)')
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)')
|
||||
# 其他信息
|
||||
install_tool_time = fields.Datetime("刀具组装时间", related='functional_tool_name_id.tool_loading_time')
|
||||
on_board_time = fields.Datetime('上机装刀时间')
|
||||
max_lifetime_value = fields.Integer(string='最大寿命值(min)')
|
||||
alarm_value = fields.Integer(string='报警值(min)')
|
||||
used_value = fields.Integer(string='已使用值(min)')
|
||||
functional_tool_status = fields.Selection([('正常', '正常'), ('报警', '报警'), ('已拆除', '已拆除')], string='状态')
|
||||
alarm_time = fields.Datetime('报警时间')
|
||||
dispose_user = fields.Char('处理人')
|
||||
dispose_time = fields.Char('处理时间')
|
||||
dispose_func = fields.Char('处理方法/措施', readonly=False)
|
||||
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
|
||||
@api.model
|
||||
def _read_group_machine_table_name_ids(self, categories, domain, order):
|
||||
machine_table_name_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
return categories.browse(machine_table_name_ids)
|
||||
|
||||
def create_tool_warning_record(self, obj):
|
||||
"""
|
||||
机台换刀申请报警状态时,创建功能刀具预警记录
|
||||
"""
|
||||
if obj:
|
||||
for tool in obj.get('tool_changing_apply_id'):
|
||||
self.env['sf.functional.tool.warning'].create({
|
||||
'production_line_id': tool.production_line_id.id,
|
||||
'maintenance_equipment_id': tool.maintenance_equipment_id.id,
|
||||
'machine_tool_code': tool.machine_tool_code,
|
||||
'machine_table_type_id': tool.machine_table_type_id.id,
|
||||
'cutter_spacing_code_id': tool.cutter_spacing_code_id.id,
|
||||
'functional_tool_name_id': tool.functional_tool_name_id.id,
|
||||
'barcode_id': tool.barcode_id.id,
|
||||
'diameter': tool.diameter,
|
||||
'knife_tip_r_angle': tool.knife_tip_r_angle,
|
||||
'max_lifetime_value': tool.max_lifetime_value,
|
||||
'alarm_value': tool.alarm_value,
|
||||
'used_value': tool.used_value,
|
||||
'functional_tool_status': tool.functional_tool_status,
|
||||
'alarm_time': fields.Datetime.now(),
|
||||
})
|
||||
|
||||
|
||||
class StockMoveLine(models.Model):
|
||||
_inherit = 'stock.move.line'
|
||||
_description = '功能刀具出入库记录'
|
||||
_order = 'date desc'
|
||||
|
||||
functional_tool_name_id = fields.Many2one('sf.functional.tool.assembly', string='功能刀具组装单')
|
||||
functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', store=True,
|
||||
group_expand='_read_group_functional_tool_type_id')
|
||||
functional_tool_name = fields.Char('刀具名称')
|
||||
diameter = fields.Integer(string='刀具直径(mm)')
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)')
|
||||
install_tool_time = fields.Datetime("刀具组装时间", default=fields.Datetime.now())
|
||||
code = fields.Char('编码')
|
||||
rfid = fields.Char('Rfid')
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组')
|
||||
|
||||
@api.model
|
||||
def _read_group_functional_tool_type_id(self, categories, domain, order):
|
||||
names = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
return categories.browse(names)
|
||||
|
||||
|
||||
class RealTimeDistributionOfFunctionalTools(models.Model):
|
||||
_name = 'sf.real.time.distribution.of.functional.tools'
|
||||
_description = '功能刀具安全库存'
|
||||
|
||||
name = fields.Char('名称', readonly=True, compute='_compute_name', store=True)
|
||||
functional_name_id = fields.Many2one('sf.tool.inventory', string='功能刀具名称', required=True)
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=False, required=True)
|
||||
sf_cutting_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model', string='功能刀具类型', readonly=False,
|
||||
group_expand='_read_mrs_cutting_tool_type_ids', store=True)
|
||||
diameter = fields.Integer(string='刀具直径(mm)', readonly=False)
|
||||
knife_tip_r_angle = fields.Float(string='刀尖R角(mm)', readonly=False)
|
||||
tool_stock_num = fields.Integer(string='刀具房数量')
|
||||
side_shelf_num = fields.Integer(string='线边刀库数量')
|
||||
on_tool_stock_num = fields.Integer(string='机内刀库数量')
|
||||
tool_stock_total = fields.Integer(string='当前库存量', readonly=True)
|
||||
min_stock_num = fields.Integer('最低库存量')
|
||||
max_stock_num = fields.Integer('最高库存量')
|
||||
batch_replenishment_num = fields.Integer('批次补货量', readonly=True, compute='_compute_batch_replenishment_num')
|
||||
unit = fields.Char('单位')
|
||||
image = fields.Binary('图片', readonly=False)
|
||||
|
||||
coarse_middle_thin = fields.Selection([("1", "粗"), ('2', '中'), ('3', '精')], string='粗/中/精', readonly=False)
|
||||
whether_standard_knife = fields.Boolean(string='是否标准刀', default=True, readonly=False)
|
||||
# 能力特征信息
|
||||
suitable_machining_method_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_machining_product_template_distribution', '适合加工方式',
|
||||
domain=[('type', '=', '加工能力')],
|
||||
related='sf_functional_cutting_tool_entity_ids.suitable_machining_method_ids')
|
||||
blade_tip_characteristics_id = fields.Many2one(
|
||||
'maintenance.equipment.image', '刀尖特征',
|
||||
domain=[('type', '=', '刀尖特征')],
|
||||
related='sf_functional_cutting_tool_entity_ids.blade_tip_characteristics_id')
|
||||
handle_type_id = fields.Many2one(
|
||||
'maintenance.equipment.image', '柄部类型',
|
||||
domain=[('type', '=', '柄部类型')], related='sf_functional_cutting_tool_entity_ids.handle_type_id')
|
||||
cutting_direction_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_cutting_product_template_distribution', '走刀方向',
|
||||
domain=[('type', '=', '走刀方向')], related='sf_functional_cutting_tool_entity_ids.cutting_direction_ids')
|
||||
suitable_coolant_ids = fields.Many2many(
|
||||
'maintenance.equipment.image', 'rel_coolants_product_template_distribution', '适合冷却方式',
|
||||
domain=[('type', '=', '冷却方式')], related='sf_functional_cutting_tool_entity_ids.suitable_coolant_ids')
|
||||
|
||||
sf_functional_cutting_tool_entity_ids = fields.Many2many('sf.functional.cutting.tool.entity',
|
||||
'sf_functional_cutting_tool_entity_ref',
|
||||
string='功能刀具列表信息', readonly=True)
|
||||
|
||||
sf_functional_tool_assembly_ids = fields.Many2many('sf.functional.tool.assembly', 'sf_functional_tool_assembly_ref',
|
||||
'功能刀具组装单', readonly=True)
|
||||
|
||||
active = fields.Boolean(string='已归档', default=True)
|
||||
|
||||
@api.onchange('functional_name_id')
|
||||
def _onchange_num(self):
|
||||
for item in self:
|
||||
if item.functional_name_id:
|
||||
item.tool_groups_id = item.functional_name_id.tool_groups_id.id
|
||||
item.sf_cutting_tool_type_id = item.functional_name_id.functional_cutting_tool_model_id.id
|
||||
item.diameter = item.functional_name_id.diameter
|
||||
item.knife_tip_r_angle = item.functional_name_id.angle
|
||||
|
||||
@api.depends('functional_name_id')
|
||||
def _compute_name(self):
|
||||
for obj in self:
|
||||
if obj.tool_groups_id:
|
||||
obj.name = obj.functional_name_id.name
|
||||
else:
|
||||
obj.sudo().name = ''
|
||||
|
||||
@api.constrains('min_stock_num', 'max_stock_num')
|
||||
def _check_stock_num(self):
|
||||
for obj in self:
|
||||
if obj.min_stock_num > obj.max_stock_num:
|
||||
raise ValidationError('【最低安全库存】不能高于【最高安全库存】!!!')
|
||||
|
||||
@api.model
|
||||
def _read_mrs_cutting_tool_type_ids(self, categories, domain, order):
|
||||
mrs_cutting_tool_type_ids = categories._search([], order=order, access_rights_uid=SUPERUSER_ID)
|
||||
return categories.browse(mrs_cutting_tool_type_ids)
|
||||
|
||||
@api.depends('sf_functional_cutting_tool_entity_ids', 'min_stock_num', 'max_stock_num')
|
||||
def _compute_batch_replenishment_num(self):
|
||||
for tool in self:
|
||||
if tool:
|
||||
# 判断功能刀具组装单是否已经完成
|
||||
tool.sudo().estimate_functional_tool_assembly_ids(tool)
|
||||
tool.sudo().get_stock_num(tool)
|
||||
# 计算当前库存量
|
||||
tool.sudo().tool_stock_total = tool.tool_stock_num + tool.side_shelf_num + tool.on_tool_stock_num
|
||||
# 如果当前库存量小于最低库存量,计算批次补货量
|
||||
tool.sudo().open_batch_replenishment_num(tool)
|
||||
|
||||
def open_batch_replenishment_num(self, tool):
|
||||
"""
|
||||
计算批次补货量
|
||||
"""
|
||||
if tool.tool_stock_total < tool.min_stock_num:
|
||||
tool.sudo().batch_replenishment_num = tool.max_stock_num - tool.tool_stock_total
|
||||
# 根据判断创建功能刀具组装单
|
||||
if not tool.sf_functional_tool_assembly_ids and re.match(r'^\d+$', str(tool.id)):
|
||||
for i in range(tool.batch_replenishment_num):
|
||||
tool.sudo().create_functional_tool_assembly(tool)
|
||||
print(i, ": ", tool.sf_functional_tool_assembly_ids)
|
||||
else:
|
||||
tool.sudo().batch_replenishment_num = 0
|
||||
|
||||
def create_functional_tool_assembly(self, tool):
|
||||
"""
|
||||
创建功能刀具组装单
|
||||
"""
|
||||
functional_tool_assembly = tool.env['sf.functional.tool.assembly'].sudo().create({
|
||||
'functional_tool_name': tool.name,
|
||||
'functional_tool_type_id': tool.sf_cutting_tool_type_id.id,
|
||||
'tool_groups_id': tool.tool_groups_id.id,
|
||||
'functional_tool_diameter': tool.diameter,
|
||||
'knife_tip_r_angle': tool.knife_tip_r_angle,
|
||||
'coarse_middle_thin': tool.coarse_middle_thin,
|
||||
'loading_task_source': '2',
|
||||
'use_tool_time': fields.Datetime.now() + timedelta(hours=4),
|
||||
'applicant': '系统自动',
|
||||
'apply_time': fields.Datetime.now(),
|
||||
'whether_standard_knife': tool.whether_standard_knife,
|
||||
'reason_for_applying': '安全库存',
|
||||
})
|
||||
tool.sudo().sf_functional_tool_assembly_ids = [(4, functional_tool_assembly.id)]
|
||||
|
||||
def estimate_functional_tool_assembly_ids(self, tool):
|
||||
"""
|
||||
判断功能刀具组装单是否完成,如果全部完成清空sf_functional_tool_assembly_ids的数据
|
||||
"""
|
||||
for sf_functional_tool_assembly_id in tool.sf_functional_tool_assembly_ids:
|
||||
if sf_functional_tool_assembly_id.assemble_status == '0':
|
||||
return False
|
||||
tool.sudo().sf_functional_tool_assembly_ids = []
|
||||
|
||||
def get_stock_num(self, tool):
|
||||
"""
|
||||
计算刀具房数量、线边刀库数量、机内刀库数量
|
||||
"""
|
||||
if tool:
|
||||
tool.tool_stock_num = 0
|
||||
tool.side_shelf_num = 0
|
||||
tool.on_tool_stock_num = 0
|
||||
if tool.sf_functional_cutting_tool_entity_ids:
|
||||
for cutting_tool in tool.sf_functional_cutting_tool_entity_ids:
|
||||
if cutting_tool.tool_room_num > 0:
|
||||
tool.tool_stock_num += 1
|
||||
elif cutting_tool.line_edge_knife_library_num > 0:
|
||||
tool.side_shelf_num += 1
|
||||
elif cutting_tool.machine_knife_library_num > 0:
|
||||
tool.on_tool_stock_num += 1
|
||||
|
||||
def create_or_edit_safety_stock(self, vals, sf_functional_cutting_tool_entity_ids):
|
||||
"""
|
||||
根据传入的信息新增或者更新功能刀具安全库存的信息
|
||||
"""
|
||||
# 根据功能刀具名称、刀具组、直径或尖刀R角、粗/中/精查询该功能刀具是否已经存在
|
||||
record = self.env['sf.real.time.distribution.of.functional.tools'].search(
|
||||
[('functional_name_id', '=', vals['functional_name_id']),
|
||||
('sf_cutting_tool_type_id', '=', vals['sf_cutting_tool_type_id']),
|
||||
('diameter', '=', vals['diameter']), ('knife_tip_r_angle', '=', vals['knife_tip_r_angle']),
|
||||
('coarse_middle_thin', '=', vals['coarse_middle_thin']), ('tool_groups_id', '=', vals['tool_groups_id'])])
|
||||
if len(record) > 0:
|
||||
for obj in record:
|
||||
obj.write({'sf_functional_cutting_tool_entity_ids': [(4, sf_functional_cutting_tool_entity_ids.id)]})
|
||||
else:
|
||||
vals['sf_functional_cutting_tool_entity_ids'] = sf_functional_cutting_tool_entity_ids.ids
|
||||
self.env['sf.real.time.distribution.of.functional.tools'].create(vals)
|
||||
|
||||
status_create = fields.Boolean('是否是新增状态', default=True)
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
for vals in vals_list:
|
||||
vals['status_create'] = False
|
||||
records = super(RealTimeDistributionOfFunctionalTools, self).create(vals_list)
|
||||
return records
|
||||
@@ -1,9 +1,10 @@
|
||||
import json
|
||||
import base64
|
||||
import requests
|
||||
import logging
|
||||
from odoo import models, api
|
||||
from odoo.addons.sf_base.commons.common import Common
|
||||
from odoo.exceptions import UserError
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
|
||||
def get_suitable_machining_method_names(item):
|
||||
@@ -30,6 +31,30 @@ def get_suitable_coolant_names(item):
|
||||
return suitable_coolant_names
|
||||
|
||||
|
||||
class ToolDatasync(models.Model):
|
||||
_name = 'sf.tool.datasync'
|
||||
_description = '定时同步所有刀具'
|
||||
|
||||
def _cron_tool_datasync_all(self):
|
||||
try:
|
||||
self.env['stock.lot'].sudo().sync_enroll_tool_material_stock_all()
|
||||
logging.info("刀具物料序列号每日同步成功")
|
||||
self.env['sf.tool.material.search'].sudo().sync_enroll_tool_material_all()
|
||||
logging.info("刀具物料每日同步成功")
|
||||
self.env['sf.functional.cutting.tool.entity'].sudo().esync_enroll_functional_tool_entity_all()
|
||||
logging.info("功能刀具列表每日同步成功")
|
||||
self.env['sf.functional.tool.warning'].sudo().sync_enroll_functional_tool_warning_all()
|
||||
logging.info("功能刀具预警每日同步成功")
|
||||
self.env['stock.move.line'].sudo().sync_enroll_functional_tool_move_all()
|
||||
logging.info("功能刀具出入库记录每日同步成功")
|
||||
self.env[
|
||||
'sf.real.time.distribution.of.functional.tools'].sudo().sync_enroll_functional_tool_real_time_distribution_all()
|
||||
logging.info("功能刀具安全库存每日同步成功")
|
||||
except Exception as e:
|
||||
logging.info("捕获错误信息:%s" % e)
|
||||
raise ValidationError("数据错误导致同步失败,请联系管理员")
|
||||
|
||||
|
||||
class StockLot(models.Model):
|
||||
_inherit = 'stock.lot'
|
||||
_description = '刀具物料序列号注册'
|
||||
@@ -40,7 +65,19 @@ class StockLot(models.Model):
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create"
|
||||
objs_all = self.env['stock.lot'].search([('id', '=', self.id)])
|
||||
objs_all = self.env['stock.lot'].search([('id', '=', self.id), ('active', 'in', [True, False])])
|
||||
self._get_sync_stock_lot(objs_all, str_url, token, headers)
|
||||
|
||||
def sync_enroll_tool_material_stock_all(self):
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + "/api/tool_material_stock/create"
|
||||
objs_all = self.env['stock.lot'].search([('rfid', '!=', False)])
|
||||
self._get_sync_stock_lot(objs_all, str_url, token, headers)
|
||||
|
||||
def _get_sync_stock_lot(self, objs_all, str_url, token, headers):
|
||||
tool_material_stock_list = []
|
||||
if objs_all:
|
||||
for item in objs_all:
|
||||
@@ -57,7 +94,7 @@ class StockLot(models.Model):
|
||||
if ret.get('code') == 200:
|
||||
return '刀具物料序列号注册成功'
|
||||
else:
|
||||
raise UserError("没有注册刀具物料序列号信息")
|
||||
logging.info("没有注册刀具物料序列号信息")
|
||||
|
||||
|
||||
class ToolMaterial(models.Model):
|
||||
@@ -73,6 +110,18 @@ class ToolMaterial(models.Model):
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.search([('id', '=', self.id)])
|
||||
self._get_sync_tool_material_search(objs_all, str_url, token, headers)
|
||||
|
||||
def sync_enroll_tool_material_all(self):
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.search([])
|
||||
self._get_sync_tool_material_search(objs_all, str_url, token, headers)
|
||||
|
||||
def _get_sync_tool_material_search(self, objs_all, str_url, token, headers):
|
||||
tool_material_list = []
|
||||
if objs_all:
|
||||
for item in objs_all:
|
||||
@@ -95,7 +144,7 @@ class ToolMaterial(models.Model):
|
||||
if ret.get('code') == 200:
|
||||
return '刀具物料注册成功'
|
||||
else:
|
||||
raise UserError("没有注册刀具物料信息")
|
||||
logging.info('没有注册刀具物料信息')
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
@@ -120,6 +169,18 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.env['sf.functional.cutting.tool.entity'].search([('id', '=', self.id)])
|
||||
self._get_sync_functional_cutting_tool_entity(objs_all, str_url, token, headers)
|
||||
|
||||
def esync_enroll_functional_tool_entity_all(self):
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.env['sf.functional.cutting.tool.entity'].search([])
|
||||
self._get_sync_functional_cutting_tool_entity(objs_all, str_url, token, headers)
|
||||
|
||||
def _get_sync_functional_cutting_tool_entity(self, objs_all, str_url, token, headers):
|
||||
functional_tool_list = []
|
||||
if objs_all:
|
||||
for item in objs_all:
|
||||
@@ -170,7 +231,7 @@ class FunctionalCuttingToolEntity(models.Model):
|
||||
if ret.get('code') == 200:
|
||||
return "功能刀具注册成功"
|
||||
else:
|
||||
raise UserError("没有注册功能刀具信息")
|
||||
logging.info('没有注册功能刀具信息')
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
@@ -201,6 +262,18 @@ class FunctionalToolWarning(models.Model):
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.env['sf.functional.tool.warning'].search([('id', '=', self.id)])
|
||||
self.get_sync_functional_tool_warning(objs_all, str_url, token, headers)
|
||||
|
||||
def sync_enroll_functional_tool_warning_all(self):
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.env['sf.functional.tool.warning'].search([])
|
||||
self.get_sync_functional_tool_warning(objs_all, str_url, token, headers)
|
||||
|
||||
def get_sync_functional_tool_warning(self, objs_all, str_url, token, headers):
|
||||
tool_warning_list = []
|
||||
if objs_all:
|
||||
for item in objs_all:
|
||||
@@ -237,7 +310,7 @@ class FunctionalToolWarning(models.Model):
|
||||
if ret.get('code') == 200:
|
||||
return "功能刀具预警注册成功"
|
||||
else:
|
||||
raise UserError("没有注册功能刀具预警信息")
|
||||
logging.info('没有注册功能刀具预警信息')
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
@@ -262,6 +335,18 @@ class StockMoveLine(models.Model):
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.env['stock.move.line'].search([('id', '=', self.id), ('functional_tool_name_id', '!=', False)])
|
||||
self.get_sync_stock_move_line(objs_all, str_url, token, headers)
|
||||
|
||||
def sync_enroll_functional_tool_move_all(self):
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.env['stock.move.line'].search([('functional_tool_name_id', '!=', False)])
|
||||
self.get_sync_stock_move_line(objs_all, str_url, token, headers)
|
||||
|
||||
def get_sync_stock_move_line(self, objs_all, str_url, token, headers):
|
||||
tool_stock_list = []
|
||||
if objs_all:
|
||||
for item in objs_all:
|
||||
@@ -289,7 +374,7 @@ class StockMoveLine(models.Model):
|
||||
if ret.get('code') == 200:
|
||||
return "功能刀具出入库记录注册成功"
|
||||
else:
|
||||
raise UserError("没有注册功能刀具出入库记录信息")
|
||||
logging.info('没有注册功能刀具出入库记录信息')
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
@@ -314,6 +399,18 @@ class RealTimeDistributionFunctionalTools(models.Model):
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([('id', '=', self.id)])
|
||||
self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers)
|
||||
|
||||
def sync_enroll_functional_tool_real_time_distribution_all(self):
|
||||
sf_sync_config = self.env['res.config.settings'].get_values()
|
||||
token = sf_sync_config['token']
|
||||
sf_secret_key = sf_sync_config['sf_secret_key']
|
||||
headers = Common.get_headers(self, token, sf_secret_key)
|
||||
str_url = sf_sync_config['sf_url'] + self.crea_url
|
||||
objs_all = self.env['sf.real.time.distribution.of.functional.tools'].search([])
|
||||
self.get_sync_real_time_distribution_functional_tools(objs_all, str_url, token, headers)
|
||||
|
||||
def get_sync_real_time_distribution_functional_tools(self, objs_all, str_url, token, headers):
|
||||
tool_distribution_list = []
|
||||
if objs_all:
|
||||
for item in objs_all:
|
||||
@@ -353,7 +450,7 @@ class RealTimeDistributionFunctionalTools(models.Model):
|
||||
if ret.get('code') == 200:
|
||||
return "功能刀具出入库记录注册成功"
|
||||
else:
|
||||
raise UserError("没有注册功能刀具出入库记录信息")
|
||||
logging.info('没有注册功能刀具出入库记录信息')
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
@@ -362,3 +459,9 @@ class RealTimeDistributionFunctionalTools(models.Model):
|
||||
if record:
|
||||
record.enroll_functional_tool_real_time_distribution()
|
||||
return records
|
||||
|
||||
def write(self, vals):
|
||||
res = super().write(vals)
|
||||
if vals.get('sf_functional_cutting_tool_entity_ids') or vals.get('min_stock_num') or vals.get('max_stock_num'):
|
||||
self.enroll_functional_tool_real_time_distribution()
|
||||
return res
|
||||
|
||||
@@ -36,6 +36,7 @@ class CNCprocessing(models.Model):
|
||||
obj = super(CNCprocessing, self).create(vals)
|
||||
# 调用CAM工单程序用刀计划创建方法
|
||||
self.env['sf.cam.work.order.program.knife.plan'].create_cam_work_plan(obj)
|
||||
logging.info('成功调用CAM工单程序用刀计划创建方法!!!')
|
||||
return obj
|
||||
|
||||
|
||||
|
||||
@@ -20,35 +20,35 @@ class ToolMaterial(models.Model):
|
||||
specification_id = fields.Many2one('sf.tool.materials.basic.parameters', '规格',
|
||||
related='product_id.specification_id')
|
||||
image = fields.Binary('图片', related='product_id.image_1920')
|
||||
number = fields.Integer('总数量', compute='_compute_number')
|
||||
usable_num = fields.Integer('可用数量', compute='_compute_number')
|
||||
have_been_used_num = fields.Integer('在用数量', compute='_compute_number')
|
||||
scrap_num = fields.Integer('报废数量', compute='_compute_number')
|
||||
number = fields.Integer('总数量', compute='_compute_number', store=True)
|
||||
usable_num = fields.Integer('可用数量', compute='_compute_number', store=True)
|
||||
have_been_used_num = fields.Integer('在用数量', compute='_compute_number', store=True)
|
||||
scrap_num = fields.Integer('报废数量', compute='_compute_number', store=True)
|
||||
|
||||
barcode_ids = fields.One2many('stock.lot', 'tool_material_search_id', string='序列号', readonly=True)
|
||||
|
||||
@api.depends('barcode_ids')
|
||||
@api.depends('product_id.stock_quant_ids.quantity')
|
||||
def _compute_number(self):
|
||||
for record in self:
|
||||
usable_num = 0
|
||||
have_been_used_num = 0
|
||||
scrap_num = 0
|
||||
if record.barcode_ids:
|
||||
record.number = len(record.barcode_ids)
|
||||
for barcode_id in record.barcode_ids:
|
||||
if barcode_id.quant_ids:
|
||||
if barcode_id.quant_ids[-1].location_id.name == '刀具组装位置':
|
||||
have_been_used_num = have_been_used_num + 1
|
||||
else:
|
||||
usable_num = usable_num + 1
|
||||
record.usable_num = usable_num
|
||||
record.have_been_used_num = have_been_used_num
|
||||
record.scrap_num = scrap_num
|
||||
else:
|
||||
record.number = 0
|
||||
record.usable_num = 0
|
||||
record.have_been_used_num = 0
|
||||
record.scrap_num = 0
|
||||
for quant in record.product_id.stock_quant_ids:
|
||||
location = quant.location_id.name
|
||||
if location == '刀具房':
|
||||
usable_num += quant.quantity
|
||||
elif location == '刀具组装位置':
|
||||
have_been_used_num += quant.quantity
|
||||
elif location == '进货':
|
||||
pass
|
||||
elif location != 'Vendors':
|
||||
scrap_num += quant.quantity
|
||||
record.usable_num = usable_num
|
||||
record.have_been_used_num = have_been_used_num
|
||||
record.scrap_num = scrap_num
|
||||
record.number = usable_num + have_been_used_num + scrap_num
|
||||
# 更新数据到cloud的动态数据
|
||||
record.enroll_tool_material()
|
||||
|
||||
@api.model
|
||||
def _read_group_cutting_tool_material_id(self, categories, domain, order):
|
||||
|
||||
@@ -1,33 +1,33 @@
|
||||
id,name,model_id:id,group_id:id,perm_read,perm_write,perm_create,perm_unlink
|
||||
access_sf_functional_cutting_tool_entity,sf.functional.cutting.tool.entity,model_sf_functional_cutting_tool_entity,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_functional_tool_warning,sf.functional.tool.warning,model_sf_functional_tool_warning,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_real_time_distribution_of_functional_tools,sf.real.time.distribution.of.functional.tools,model_sf_real_time_distribution_of_functional_tools,sf_base.group_sf_tool_user,1,1,1,0
|
||||
|
||||
access_sf_cam_work_order_program_knife_plan,sf.cam.work.order.program.knife.plan,model_sf_cam_work_order_program_knife_plan,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_machine_table_tool_changing_apply,sf.machine.table.tool.changing.apply,model_sf_machine_table_tool_changing_apply,sf_base.group_sf_tool_user,1,1,1,0
|
||||
|
||||
|
||||
access_sf_tool_change_requirement_information,sf.tool.change.requirement.information,model_sf_tool_change_requirement_information,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_tool_transfer_request_information,sf.tool.transfer.request.information,model_sf_tool_transfer_request_information,sf_base.group_sf_tool_user,1,1,1,0
|
||||
|
||||
access_sf_functional_tool_assembly,sf.functional.tool.assembly,model_sf_functional_tool_assembly,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_functional_tool_assembly_order,sf.functional.tool.assembly.order,model_sf_functional_tool_assembly_order,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_tool_material_search,sf.tool.material.search,model_sf_tool_material_search,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_fixture_material_search,sf.fixture.material.search,model_sf_fixture_material_search,sf_base.group_sf_tool_user,1,1,1,0
|
||||
|
||||
|
||||
access_sf_functional_cutting_tool_entity_group_plan_dispatch,sf.functional.cutting.tool.entity,model_sf_functional_cutting_tool_entity,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_functional_tool_warning,sf.functional.tool.warning,model_sf_functional_tool_warning,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_functional_tool_warning_group_plan_dispatch,sf.functional.tool.warning,model_sf_functional_tool_warning,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_real_time_distribution_of_functional_tools,sf.real.time.distribution.of.functional.tools,model_sf_real_time_distribution_of_functional_tools,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_real_time_distribution_of_functional_tools_group_plan_dispatch,sf.real.time.distribution.of.functional.tools,model_sf_real_time_distribution_of_functional_tools,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_cam_work_order_program_knife_plan,sf.cam.work.order.program.knife.plan,model_sf_cam_work_order_program_knife_plan,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_cam_work_order_program_knife_plan_group_plan_dispatch,sf.cam.work.order.program.knife.plan,model_sf_cam_work_order_program_knife_plan,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_machine_table_tool_changing_apply,sf.machine.table.tool.changing.apply,model_sf_machine_table_tool_changing_apply,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_machine_table_tool_changing_apply_group_plan_dispatch,sf.machine.table.tool.changing.apply,model_sf_machine_table_tool_changing_apply,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
|
||||
access_sf_tool_change_requirement_information,sf.tool.change.requirement.information,model_sf_tool_change_requirement_information,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_tool_change_requirement_information_group_plan_dispatch,sf.tool.change.requirement.information,model_sf_tool_change_requirement_information,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_tool_transfer_request_information,sf.tool.transfer.request.information,model_sf_tool_transfer_request_information,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_tool_transfer_request_information_group_plan_dispatch,sf.tool.transfer.request.information,model_sf_tool_transfer_request_information,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_functional_tool_assembly,sf.functional.tool.assembly,model_sf_functional_tool_assembly,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_functional_tool_assembly_group_plan_dispatch,sf.functional.tool.assembly,model_sf_functional_tool_assembly,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_functional_tool_assembly_order,sf.functional.tool.assembly.order,model_sf_functional_tool_assembly_order,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_functional_tool_assembly_order_group_plan_dispatch,sf.functional.tool.assembly.order,model_sf_functional_tool_assembly_order,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_tool_material_search,sf.tool.material.search,model_sf_tool_material_search,sf_base.group_sf_tool_user,1,1,1,0
|
||||
access_sf_tool_material_search_group_plan_dispatch,sf.tool.material.search,model_sf_tool_material_search,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
||||
access_sf_fixture_material_search,sf.fixture.material.search,model_sf_fixture_material_search,sf_base.group_sf_order_user,1,0,0,0
|
||||
access_sf_fixture_material_search_group_plan_dispatch,sf.fixture.material.search,model_sf_fixture_material_search,sf_base.group_plan_dispatch,1,0,0,0
|
||||
|
@@ -100,6 +100,6 @@
|
||||
name="夹具物料查询"
|
||||
id="menu_sf_fixture_material_search"
|
||||
action="action_sf_fixture_material_search"
|
||||
parent="menu_sf_tool_manage"
|
||||
parent="menu_sf_fixture"
|
||||
/>
|
||||
</odoo>
|
||||
514
sf_tool_management/views/functional_tool_views.xml
Normal file
514
sf_tool_management/views/functional_tool_views.xml
Normal file
@@ -0,0 +1,514 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!--========================================功能刀具列表========================================-->
|
||||
<record id="view_functional_cutting_tool_list_tree" model="ir.ui.view">
|
||||
<field name="name">sf.functional.cutting.tool.entity.list.tree</field>
|
||||
<field name="model">sf.functional.cutting.tool.entity</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具列表" create="0" edit="0" delete="0">
|
||||
<field name="barcode_id" invisible="1"/>
|
||||
<field name="rfid"/>
|
||||
<field name="tool_name_id"/>
|
||||
<field name="image" widget='image'/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="functional_tool_diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="coarse_middle_thin" optional="hide"/>
|
||||
<field name="new_former" optional="hide"/>
|
||||
<field name="tool_loading_length" optional="hide"/>
|
||||
<field name="functional_tool_length" optional="hide"/>
|
||||
<field name="effective_length" optional="hide"/>
|
||||
<field name="tool_room_num"/>
|
||||
<field name="line_edge_knife_library_num"/>
|
||||
<field name="machine_knife_library_num"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status"/>
|
||||
|
||||
<field name="current_location_id" optional="hide"/>
|
||||
<field name="current_location" optional="hide"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_functional_cutting_tool_list_form" model="ir.ui.view">
|
||||
<field name="name">sf.functional.cutting.tool.entity.list.form</field>
|
||||
<field name="model">sf.functional.cutting.tool.entity</field>
|
||||
<field name="arch" type="xml">
|
||||
<form create="0" edit="0" delete="0">
|
||||
<header>
|
||||
<!-- <button name="enroll_functional_tool_entity" string="功能刀具注册" type="object"-->
|
||||
<!-- class="btn-primary"/>-->
|
||||
<field name="functional_tool_status" widget="statusbar" statusbar_visible="正常,报警,已拆除"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
|
||||
name="open_functional_tool_warning"
|
||||
icon="fa-list-ul"
|
||||
type="object">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span>
|
||||
预警记录
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
|
||||
name="open_stock_move_line"
|
||||
icon="fa-list-ul"
|
||||
type="object">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span>
|
||||
出库入库记录
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
|
||||
name="open_safety_stock"
|
||||
icon="fa-list-ul"
|
||||
type="object">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span>
|
||||
安全库存
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="code" readonly="1" nolabel="True"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="barcode_id" invisible="1"/>
|
||||
<field name="rfid" readonly="1"/>
|
||||
<field name="tool_name_id" invisible="0"
|
||||
placeholder="请输入20字以内的名称"/>
|
||||
<field name="sf_cutting_tool_type_id"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="cutting_tool_integral_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"
|
||||
attrs="{'invisible': [('cutting_tool_blade_model_id', '!=', False)]}"
|
||||
/>
|
||||
<field name="cutting_tool_blade_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"
|
||||
attrs="{'invisible': [('cutting_tool_integral_model_id', '!=', False)]}"
|
||||
/>
|
||||
<field name="cutting_tool_cutterbar_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"
|
||||
attrs="{'invisible': ['|',('cutting_tool_cutterpad_model_id','!=',False),('cutting_tool_blade_model_id', '=', False)]}"
|
||||
/>
|
||||
<field name="cutting_tool_cutterpad_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"
|
||||
attrs="{'invisible': ['|',('cutting_tool_cutterbar_model_id','!=',False),('cutting_tool_blade_model_id', '=', False)]}"
|
||||
/>
|
||||
<field name="cutting_tool_cutterhandle_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="cutting_tool_cutterhead_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="image" nolabel="1" widget="image"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1">
|
||||
<group string="适合加工方式">
|
||||
<field name="suitable_machining_method_ids" string=""
|
||||
widget="custom_many2many_checkboxes"
|
||||
domain="[('id','in',suitable_machining_method_ids)]"/>
|
||||
</group>
|
||||
<group>
|
||||
<group string="刀尖特征">
|
||||
<field name="blade_tip_characteristics_id" string=""
|
||||
widget="many2one_radio"
|
||||
domain="[('id','=',blade_tip_characteristics_id)]"/>
|
||||
</group>
|
||||
<group string="柄部类型">
|
||||
<field name="handle_type_id" string="" widget="many2one_radio"
|
||||
domain="[('id','=',handle_type_id)]"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="走刀方向">
|
||||
<field name="cutting_direction_ids" string="" widget="custom_many2many_checkboxes"
|
||||
domain="[('id','in',cutting_direction_ids)]"/>
|
||||
</group>
|
||||
<group string="适合冷却方式">
|
||||
<field name="suitable_coolant_ids" string="" widget="custom_many2many_checkboxes"
|
||||
domain="[('id','in',suitable_coolant_ids)]"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string='参数'>
|
||||
<group>
|
||||
<group>
|
||||
<field name="functional_tool_diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="whether_standard_knife"/>
|
||||
<field name="coarse_middle_thin"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="current_location_id" invisible="1"/>
|
||||
<field name="current_location"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="tool_loading_length"/>
|
||||
<field name="functional_tool_length"/>
|
||||
<field name="effective_length"/>
|
||||
<field name="L_D_number"/>
|
||||
<field name="hiding_length"/>
|
||||
<field name="new_former"/>
|
||||
<field name="cut_time" attrs="{'invisible': [('new_former','=','0')]}"/>
|
||||
<field name="cut_length" attrs="{'invisible': [('new_former','=','0')]}"/>
|
||||
<field name="cut_number" attrs="{'invisible': [('new_former','=','0')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_functional_cutting_tool_list_search" model="ir.ui.view">
|
||||
<field name="name">sf.functional.cutting.tool.entity.list.tree</field>
|
||||
<field name="model">sf.functional.cutting.tool.entity</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="barcode_id"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id"/>
|
||||
<field name="image" widget='image'/>
|
||||
<field name="functional_tool_diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="coarse_middle_thin" optional="hide"/>
|
||||
<field name="new_former" optional="hide"/>
|
||||
<field name="tool_loading_length" optional="hide"/>
|
||||
<field name="functional_tool_length" optional="hide"/>
|
||||
<field name="effective_length" optional="hide"/>
|
||||
<field name="tool_room_num"/>
|
||||
<field name="line_edge_knife_library_num"/>
|
||||
<field name="machine_knife_library_num"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status" optional="hide"/>
|
||||
|
||||
<field name="current_location_id" invisible="True"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
|
||||
<searchpanel>
|
||||
<field name="sf_cutting_tool_type_id" icon="fa-building" enable_counters="1"/>
|
||||
<field name="current_location" icon="fa-building" enable_counters="1"/>
|
||||
<field name="functional_tool_status" icon="fa-building" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_function_tool_entry_list_view_act" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具列表</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.functional.cutting.tool.entity</field>
|
||||
<field name="view_mode">tree,form,search</field>
|
||||
<field name="view_id" ref="view_functional_cutting_tool_list_tree"/>
|
||||
</record>
|
||||
|
||||
<!-- ======================================== 功能刀具预警========================================-->
|
||||
<record id="view_sf_functional_tool_warning_tree" model="ir.ui.view">
|
||||
<field name="name">sf.functional.tool.warning.tree</field>
|
||||
<field name="model">sf.functional.tool.warning</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具预警" create="0" edit="0" delete="0" editable="bottom">
|
||||
<field name="production_line_id" optional="hide"/>
|
||||
<field name="maintenance_equipment_id" optional="hide"/>
|
||||
<field name="machine_tool_code"/>
|
||||
<field name="cutter_spacing_code_id"/>
|
||||
<field name="barcode_id" invisible="1"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="install_tool_time" optional="hide"/>
|
||||
<field name="on_board_time" optional="hide"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status"/>
|
||||
<field name="alarm_time"/>
|
||||
<field name="dispose_user"/>
|
||||
<field name="dispose_time"/>
|
||||
<field name="dispose_func"/>
|
||||
<!-- <button name="enroll_functional_tool_warning" string="刀具预警注册" type="object"-->
|
||||
<!-- class="btn-primary"/>-->
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_sf_functional_tool_warning_search" model="ir.ui.view">
|
||||
<field name="name">sf.functional.tool.warning.search</field>
|
||||
<field name="model">sf.functional.tool.warning</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="功能刀具预警">
|
||||
<field name="machine_tool_code"/>
|
||||
<field name="cutter_spacing_code_id"/>
|
||||
<field name="barcode_id"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="install_tool_time" optional="hide"/>
|
||||
<field name="on_board_time" optional="hide"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status"/>
|
||||
<field name="alarm_time"/>
|
||||
<field name="dispose_user"/>
|
||||
<field name="dispose_time"/>
|
||||
<field name="dispose_func"/>
|
||||
<field name="production_line_id" invisible="True"/>
|
||||
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
|
||||
<searchpanel>
|
||||
<field name="production_line_id" icon="fa-building" enable_counters="1"/>
|
||||
<field name="maintenance_equipment_id" icon="fa-building" enable_counters="1"/>
|
||||
<field name="cutter_spacing_code_id" icon="fa-building" enable_counters="1"/>
|
||||
<field name="functional_tool_status" icon="fa-building" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_sf_functional_tool_warning" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具预警</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.functional.tool.warning</field>
|
||||
<field name="view_mode">tree,search</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- =====================================功能刀具安全库存=================================================== -->
|
||||
<record id="sf_real_time_distribution_of_functional_tools_view_tree" model="ir.ui.view">
|
||||
<field name="name">功能刀具安全库存</field>
|
||||
<field name="model">sf.real.time.distribution.of.functional.tools</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="name" invisible="1"/>
|
||||
<field name="functional_name_id"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="coarse_middle_thin"/>
|
||||
<field name="tool_stock_num"/>
|
||||
<field name="side_shelf_num"/>
|
||||
<field name="on_tool_stock_num"/>
|
||||
<field name="tool_stock_total"/>
|
||||
<field name="min_stock_num"/>
|
||||
<field name="max_stock_num"/>
|
||||
<field name="batch_replenishment_num"/>
|
||||
<field name="unit"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_real_time_distribution_of_functional_tools_view_form" model="ir.ui.view">
|
||||
<field name="name">功能刀具安全库存</field>
|
||||
<field name="model">sf.real.time.distribution.of.functional.tools</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<!-- <header>-->
|
||||
<!-- <button name="enroll_functional_tool_real_time_distribution" string="安全库存注册" type="object"-->
|
||||
<!-- class="btn-primary"/>-->
|
||||
<!-- </header>-->
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="functional_name_id" placeholder="请选择"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
</h1>
|
||||
</div>
|
||||
<field name="name" invisible="1"/>
|
||||
<field name="status_create" invisible="1"/>
|
||||
<group>
|
||||
<group>
|
||||
<group>
|
||||
<field name="sf_cutting_tool_type_id" class="custom_required"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="tool_groups_id" class="custom_required" options="{'no_create': True}"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="diameter" class="custom_required"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="knife_tip_r_angle" class="custom_required"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="coarse_middle_thin"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="whether_standard_knife"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="min_stock_num" class="custom_required"/>
|
||||
<field name="max_stock_num" class="custom_required"/>
|
||||
<field name="batch_replenishment_num"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="image" widget='image'
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1">
|
||||
<group string="适合加工方式">
|
||||
<field name="suitable_machining_method_ids" string=""
|
||||
widget="custom_many2many_checkboxes" readonly="1"
|
||||
domain="[('id','in',suitable_machining_method_ids)]"/>
|
||||
</group>
|
||||
<group>
|
||||
<group string="刀尖特征">
|
||||
<field name="blade_tip_characteristics_id" string=""
|
||||
widget="many2one_radio" readonly="1"
|
||||
domain="[('id','=',blade_tip_characteristics_id)]"/>
|
||||
</group>
|
||||
<group string="柄部类型">
|
||||
<field name="handle_type_id" string=""
|
||||
widget="many2one_radio" readonly="1"
|
||||
domain="[('id','=',handle_type_id)]"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="走刀方向">
|
||||
<field name="cutting_direction_ids" string="" widget="custom_many2many_checkboxes"
|
||||
readonly="1"
|
||||
domain="[('id','in',cutting_direction_ids)]"/>
|
||||
</group>
|
||||
<group string="适合冷却方式">
|
||||
<field name="suitable_coolant_ids" string="" widget="custom_many2many_checkboxes"
|
||||
readonly="1"
|
||||
domain="[('id','in',suitable_coolant_ids)]"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="刀具信息">
|
||||
<field name="sf_functional_cutting_tool_entity_ids" widget="many2many">
|
||||
<tree edit="0" create="0" delete="0">
|
||||
<field name="rfid"/>
|
||||
<field name="tool_name_id"/>
|
||||
<field name="new_former"/>
|
||||
<field name="tool_loading_length" string="总长度(mm)"/>
|
||||
<field name="functional_tool_length"/>
|
||||
<field name="effective_length"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_real_time_distribution_of_functional_tools_view_search" model="ir.ui.view">
|
||||
<field name="name">功能刀具安全库存</field>
|
||||
<field name="model">sf.real.time.distribution.of.functional.tools</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="tool_stock_num"/>
|
||||
<field name="side_shelf_num"/>
|
||||
<field name="on_tool_stock_num"/>
|
||||
<field name="tool_stock_total"/>
|
||||
<field name="min_stock_num"/>
|
||||
<field name="max_stock_num"/>
|
||||
<field name="batch_replenishment_num"/>
|
||||
<field name="unit"/>
|
||||
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
|
||||
<searchpanel>
|
||||
<field name="sf_cutting_tool_type_id" enable_counters="1" icon="fa-building"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_real_time_distribution_of_functional_tools_view_act" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具安全库存</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.real.time.distribution.of.functional.tools</field>
|
||||
<field name="view_mode">tree,form,search</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- ========================================功能刀具出入库记录================================================================== -->
|
||||
|
||||
<record id="sf_inbound_and_outbound_records_of_functional_tools_view_tree" model="ir.ui.view">
|
||||
<field name="name">功能刀具出入库记录</field>
|
||||
<field name="model">stock.move.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具出入库记录" create="0" edit="0" delete="0">
|
||||
<field name="reference" string="单据号"/>
|
||||
<field name="lot_id" invisible="1"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id" optional="hide"/>
|
||||
<field name="functional_tool_name" string="功能刀具名称"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="install_tool_time"/>
|
||||
<field name="location_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="date"/>
|
||||
<field name="qty_done" string="数量"/>
|
||||
<field name="functional_tool_type_id" invisible="True"/>
|
||||
<!-- <button name="enroll_functional_tool_move" string="安全库存注册" type="object" class="btn-primary"/>-->
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="sf_inbound_and_outbound_records_of_functional_tools_view_search" model="ir.ui.view">
|
||||
<field name="name">功能刀具出入库记录</field>
|
||||
<field name="model">stock.move.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="reference"/>
|
||||
<field name="lot_id"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="install_tool_time"/>
|
||||
<field name="location_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="date"/>
|
||||
<field name="qty_done"/>
|
||||
<field name="functional_tool_type_id" invisible="True"/>
|
||||
<searchpanel>
|
||||
<field name="functional_tool_type_id" enable_counters="1" icon="fa-building"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_inbound_and_outbound_records_of_functional_tools_view_act" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具出入库记录</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">stock.move.line</field>
|
||||
<field name="view_mode">tree,search</field>
|
||||
<field name="view_id"
|
||||
ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_tree"/>
|
||||
<field name="search_view_id"
|
||||
ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_search"/>
|
||||
<field name="domain">[('functional_tool_name_id', '!=', False)]</field>
|
||||
</record>
|
||||
|
||||
</data>
|
||||
</odoo>
|
||||
@@ -7,6 +7,13 @@
|
||||
groups="mrp.group_mrp_routings"
|
||||
parent="mrp.menu_mrp_root"
|
||||
sequence="20"/>
|
||||
|
||||
<menuitem id="menu_sf_fixture"
|
||||
name="夹具管理"
|
||||
groups="sf_base.group_sf_order_user"
|
||||
parent="mrp.menu_mrp_root"
|
||||
sequence="20"/>
|
||||
|
||||
<menuitem
|
||||
id="menu_sf_functional_cutting_tool"
|
||||
parent="menu_sf_tool_manage"
|
||||
|
||||
@@ -1,510 +1,6 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!--========================================功能刀具列表========================================-->
|
||||
<record id="view_functional_cutting_tool_list_tree" model="ir.ui.view">
|
||||
<field name="name">sf.functional.cutting.tool.entity.list.tree</field>
|
||||
<field name="model">sf.functional.cutting.tool.entity</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具列表" create="0" edit="0" delete="0">
|
||||
<field name="barcode_id" invisible="1"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id"/>
|
||||
<field name="image" widget='image'/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="functional_tool_diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="coarse_middle_thin" optional="hide"/>
|
||||
<field name="new_former" optional="hide"/>
|
||||
<field name="tool_loading_length" optional="hide"/>
|
||||
<field name="functional_tool_length" optional="hide"/>
|
||||
<field name="effective_length" optional="hide"/>
|
||||
<field name="tool_room_num"/>
|
||||
<field name="line_edge_knife_library_num"/>
|
||||
<field name="machine_knife_library_num"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status"/>
|
||||
|
||||
<field name="current_location_id" optional="hide"/>
|
||||
<field name="current_location" optional="hide"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_functional_cutting_tool_list_form" model="ir.ui.view">
|
||||
<field name="name">sf.functional.cutting.tool.entity.list.form</field>
|
||||
<field name="model">sf.functional.cutting.tool.entity</field>
|
||||
<field name="arch" type="xml">
|
||||
<form create="0" edit="0" delete="0">
|
||||
<header>
|
||||
<!-- <button name="enroll_functional_tool_entity" string="功能刀具注册" type="object"-->
|
||||
<!-- class="btn-primary"/>-->
|
||||
<field name="functional_tool_status" widget="statusbar" statusbar_visible="正常,报警,已拆除"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<div class="oe_button_box" name="button_box">
|
||||
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
|
||||
name="open_functional_tool_warning"
|
||||
icon="fa-list-ul"
|
||||
type="object">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span>
|
||||
预警记录
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
|
||||
name="open_stock_move_line"
|
||||
icon="fa-list-ul"
|
||||
type="object">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span>
|
||||
出库入库记录
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
<button class="oe_stat_button" groups="sf_base.group_sf_mrp_user"
|
||||
name="open_safety_stock"
|
||||
icon="fa-list-ul"
|
||||
type="object">
|
||||
<div class="o_field_widget o_stat_info">
|
||||
<span>
|
||||
安全库存
|
||||
</span>
|
||||
</div>
|
||||
</button>
|
||||
</div>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="code" readonly="1" nolabel="True"/>
|
||||
</h1>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="barcode_id" invisible="1"/>
|
||||
<field name="rfid" readonly="1"/>
|
||||
<field name="functional_tool_name_id" invisible="False"
|
||||
placeholder="请输入20字以内的名称"/>
|
||||
<field name="sf_cutting_tool_type_id"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="cutting_tool_integral_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"
|
||||
attrs="{'invisible': [('cutting_tool_blade_model_id', '!=', False)]}"
|
||||
/>
|
||||
<field name="cutting_tool_blade_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"
|
||||
attrs="{'invisible': [('cutting_tool_integral_model_id', '!=', False)]}"
|
||||
/>
|
||||
<field name="cutting_tool_cutterbar_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"
|
||||
attrs="{'invisible': ['|',('cutting_tool_cutterpad_model_id','!=',False),('cutting_tool_blade_model_id', '=', False)]}"
|
||||
/>
|
||||
<field name="cutting_tool_cutterpad_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"
|
||||
attrs="{'invisible': ['|',('cutting_tool_cutterbar_model_id','!=',False),('cutting_tool_blade_model_id', '=', False)]}"
|
||||
/>
|
||||
<field name="cutting_tool_cutterhandle_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="cutting_tool_cutterhead_model_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="image" nolabel="1" widget="image"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1">
|
||||
<group string="适合加工方式">
|
||||
<field name="suitable_machining_method_ids" string=""
|
||||
widget="custom_many2many_checkboxes"
|
||||
domain="[('id','in',suitable_machining_method_ids)]"/>
|
||||
</group>
|
||||
<group>
|
||||
<group string="刀尖特征">
|
||||
<field name="blade_tip_characteristics_id" string=""
|
||||
widget="many2one_radio"
|
||||
domain="[('id','=',blade_tip_characteristics_id)]"/>
|
||||
</group>
|
||||
<group string="柄部类型">
|
||||
<field name="handle_type_id" string="" widget="many2one_radio"
|
||||
domain="[('id','=',handle_type_id)]"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="走刀方向">
|
||||
<field name="cutting_direction_ids" string="" widget="custom_many2many_checkboxes"
|
||||
domain="[('id','in',cutting_direction_ids)]"/>
|
||||
</group>
|
||||
<group string="适合冷却方式">
|
||||
<field name="suitable_coolant_ids" string="" widget="custom_many2many_checkboxes"
|
||||
domain="[('id','in',suitable_coolant_ids)]"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string='参数'>
|
||||
<group>
|
||||
<group>
|
||||
<field name="functional_tool_diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="whether_standard_knife"/>
|
||||
<field name="coarse_middle_thin"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="current_location_id" invisible="1"/>
|
||||
<field name="current_location"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="tool_loading_length"/>
|
||||
<field name="functional_tool_length"/>
|
||||
<field name="effective_length"/>
|
||||
<field name="L_D_number"/>
|
||||
<field name="hiding_length"/>
|
||||
<field name="new_former"/>
|
||||
<field name="cut_time" attrs="{'invisible': [('new_former','=','0')]}"/>
|
||||
<field name="cut_length" attrs="{'invisible': [('new_former','=','0')]}"/>
|
||||
<field name="cut_number" attrs="{'invisible': [('new_former','=','0')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_functional_cutting_tool_list_search" model="ir.ui.view">
|
||||
<field name="name">sf.functional.cutting.tool.entity.list.tree</field>
|
||||
<field name="model">sf.functional.cutting.tool.entity</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="barcode_id"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id"/>
|
||||
<field name="image" widget='image'/>
|
||||
<field name="functional_tool_diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="coarse_middle_thin" optional="hide"/>
|
||||
<field name="new_former" optional="hide"/>
|
||||
<field name="tool_loading_length" optional="hide"/>
|
||||
<field name="functional_tool_length" optional="hide"/>
|
||||
<field name="effective_length" optional="hide"/>
|
||||
<field name="tool_room_num"/>
|
||||
<field name="line_edge_knife_library_num"/>
|
||||
<field name="machine_knife_library_num"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status" optional="hide"/>
|
||||
|
||||
<field name="current_location_id" invisible="True"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
|
||||
<searchpanel>
|
||||
<field name="sf_cutting_tool_type_id" icon="fa-building" enable_counters="1"/>
|
||||
<field name="current_location" icon="fa-building" enable_counters="1"/>
|
||||
<field name="functional_tool_status" icon="fa-building" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_function_tool_entry_list_view_act" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具列表</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.functional.cutting.tool.entity</field>
|
||||
<field name="view_mode">tree,form,search</field>
|
||||
<field name="view_id" ref="view_functional_cutting_tool_list_tree"/>
|
||||
</record>
|
||||
|
||||
<!-- ======================================== 功能刀具预警========================================-->
|
||||
<record id="view_sf_functional_tool_warning_tree" model="ir.ui.view">
|
||||
<field name="name">sf.functional.tool.warning.tree</field>
|
||||
<field name="model">sf.functional.tool.warning</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具预警" create="0" edit="0" delete="0" editable="bottom">
|
||||
<field name="production_line_id" optional="hide"/>
|
||||
<field name="maintenance_equipment_id" optional="hide"/>
|
||||
<field name="machine_tool_code"/>
|
||||
<field name="cutter_spacing_code_id"/>
|
||||
<field name="barcode_id" invisible="1"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="install_tool_time" optional="hide"/>
|
||||
<field name="on_board_time" optional="hide"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status"/>
|
||||
<field name="alarm_time"/>
|
||||
<field name="dispose_user"/>
|
||||
<field name="dispose_time"/>
|
||||
<field name="dispose_func"/>
|
||||
<!-- <button name="enroll_functional_tool_warning" string="刀具预警注册" type="object"-->
|
||||
<!-- class="btn-primary"/>-->
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="view_sf_functional_tool_warning_search" model="ir.ui.view">
|
||||
<field name="name">sf.functional.tool.warning.search</field>
|
||||
<field name="model">sf.functional.tool.warning</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="功能刀具预警">
|
||||
<field name="machine_tool_code"/>
|
||||
<field name="cutter_spacing_code_id"/>
|
||||
<field name="barcode_id"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="install_tool_time" optional="hide"/>
|
||||
<field name="on_board_time" optional="hide"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status"/>
|
||||
<field name="alarm_time"/>
|
||||
<field name="dispose_user"/>
|
||||
<field name="dispose_time"/>
|
||||
<field name="dispose_func"/>
|
||||
<field name="production_line_id" invisible="True"/>
|
||||
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
|
||||
<searchpanel>
|
||||
<field name="production_line_id" icon="fa-building" enable_counters="1"/>
|
||||
<field name="maintenance_equipment_id" icon="fa-building" enable_counters="1"/>
|
||||
<field name="cutter_spacing_code_id" icon="fa-building" enable_counters="1"/>
|
||||
<field name="functional_tool_status" icon="fa-building" enable_counters="1"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="action_sf_functional_tool_warning" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具预警</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.functional.tool.warning</field>
|
||||
<field name="view_mode">tree,search</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- =====================================功能刀具安全库存=================================================== -->
|
||||
<record id="sf_real_time_distribution_of_functional_tools_view_tree" model="ir.ui.view">
|
||||
<field name="name">功能刀具安全库存</field>
|
||||
<field name="model">sf.real.time.distribution.of.functional.tools</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree>
|
||||
<field name="name"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="coarse_middle_thin"/>
|
||||
<field name="tool_stock_num"/>
|
||||
<field name="side_shelf_num"/>
|
||||
<field name="on_tool_stock_num"/>
|
||||
<field name="tool_stock_total"/>
|
||||
<field name="min_stock_num"/>
|
||||
<field name="max_stock_num"/>
|
||||
<field name="batch_replenishment_num"/>
|
||||
<field name="unit"/>
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_real_time_distribution_of_functional_tools_view_form" model="ir.ui.view">
|
||||
<field name="name">功能刀具安全库存</field>
|
||||
<field name="model">sf.real.time.distribution.of.functional.tools</field>
|
||||
<field name="arch" type="xml">
|
||||
<form>
|
||||
<!-- <header>-->
|
||||
<!-- <button name="enroll_functional_tool_real_time_distribution" string="安全库存注册" type="object"-->
|
||||
<!-- class="btn-primary"/>-->
|
||||
<!-- </header>-->
|
||||
<sheet>
|
||||
<div class="oe_title">
|
||||
<h1>
|
||||
<field name="name"/>
|
||||
</h1>
|
||||
</div>
|
||||
<field name="status_create" invisible="1"/>
|
||||
<group>
|
||||
<group>
|
||||
<field name="sf_cutting_tool_type_id" class="custom_required"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="tool_groups_id" class="custom_required"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="diameter" class="custom_required"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="knife_tip_r_angle" class="custom_required"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="coarse_middle_thin"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="whether_standard_knife"
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
<field name="min_stock_num" class="custom_required"/>
|
||||
<field name="max_stock_num" class="custom_required"/>
|
||||
<field name="batch_replenishment_num"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="image" widget='image'
|
||||
attrs="{'readonly': [('status_create', '=', False)]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1">
|
||||
<group string="适合加工方式">
|
||||
<field name="suitable_machining_method_ids" string=""
|
||||
widget="custom_many2many_checkboxes" readonly="1"
|
||||
domain="[('id','in',suitable_machining_method_ids)]"/>
|
||||
</group>
|
||||
<group>
|
||||
<group string="刀尖特征">
|
||||
<field name="blade_tip_characteristics_id" string=""
|
||||
widget="many2one_radio" readonly="1"
|
||||
domain="[('id','=',blade_tip_characteristics_id)]"/>
|
||||
</group>
|
||||
<group string="柄部类型">
|
||||
<field name="handle_type_id" string=""
|
||||
widget="many2one_radio" readonly="1"
|
||||
domain="[('id','=',handle_type_id)]"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group string="走刀方向">
|
||||
<field name="cutting_direction_ids" string="" widget="custom_many2many_checkboxes"
|
||||
readonly="1"
|
||||
domain="[('id','in',cutting_direction_ids)]"/>
|
||||
</group>
|
||||
<group string="适合冷却方式">
|
||||
<field name="suitable_coolant_ids" string="" widget="custom_many2many_checkboxes"
|
||||
readonly="1"
|
||||
domain="[('id','in',suitable_coolant_ids)]"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="刀具信息">
|
||||
<field name="sf_functional_cutting_tool_entity_ids" widget="many2many">
|
||||
<tree edit="0" create="0" delete="0">
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id"/>
|
||||
<field name="new_former"/>
|
||||
<field name="tool_loading_length" string="总长度(mm)"/>
|
||||
<field name="functional_tool_length"/>
|
||||
<field name="effective_length"/>
|
||||
<field name="max_lifetime_value"/>
|
||||
<field name="alarm_value"/>
|
||||
<field name="used_value"/>
|
||||
<field name="functional_tool_status"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_real_time_distribution_of_functional_tools_view_search" model="ir.ui.view">
|
||||
<field name="name">功能刀具安全库存</field>
|
||||
<field name="model">sf.real.time.distribution.of.functional.tools</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="name"/>
|
||||
<field name="sf_cutting_tool_type_id" invisible="True"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="tool_stock_num"/>
|
||||
<field name="side_shelf_num"/>
|
||||
<field name="on_tool_stock_num"/>
|
||||
<field name="tool_stock_total"/>
|
||||
<field name="min_stock_num"/>
|
||||
<field name="max_stock_num"/>
|
||||
<field name="batch_replenishment_num"/>
|
||||
<field name="unit"/>
|
||||
<filter string="已归档" name="inactive" domain="[('active', '=', False)]"/>
|
||||
<searchpanel>
|
||||
<field name="sf_cutting_tool_type_id" enable_counters="1" icon="fa-building"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_real_time_distribution_of_functional_tools_view_act" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具安全库存</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.real.time.distribution.of.functional.tools</field>
|
||||
<field name="view_mode">tree,form,search</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!-- ========================================功能刀具出入库记录================================================================== -->
|
||||
|
||||
<record id="sf_inbound_and_outbound_records_of_functional_tools_view_tree" model="ir.ui.view">
|
||||
<field name="name">功能刀具出入库记录</field>
|
||||
<field name="model">stock.move.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<tree string="功能刀具出入库记录" create="0" edit="0" delete="0">
|
||||
<field name="reference" string="单据号"/>
|
||||
<field name="lot_id" invisible="1"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id" string="功能刀具名称"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="install_tool_time"/>
|
||||
<field name="location_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="date"/>
|
||||
<field name="qty_done" string="数量"/>
|
||||
<field name="functional_tool_type_id" invisible="True"/>
|
||||
<!-- <button name="enroll_functional_tool_move" string="安全库存注册" type="object" class="btn-primary"/>-->
|
||||
</tree>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="sf_inbound_and_outbound_records_of_functional_tools_view_search" model="ir.ui.view">
|
||||
<field name="name">功能刀具出入库记录</field>
|
||||
<field name="model">stock.move.line</field>
|
||||
<field name="arch" type="xml">
|
||||
<search>
|
||||
<field name="reference"/>
|
||||
<field name="lot_id"/>
|
||||
<field name="rfid"/>
|
||||
<field name="functional_tool_name_id"/>
|
||||
<field name="diameter"/>
|
||||
<field name="knife_tip_r_angle"/>
|
||||
<field name="install_tool_time"/>
|
||||
<field name="location_id"/>
|
||||
<field name="location_dest_id"/>
|
||||
<field name="date"/>
|
||||
<field name="qty_done"/>
|
||||
<field name="functional_tool_type_id" invisible="True"/>
|
||||
<searchpanel>
|
||||
<field name="functional_tool_type_id" enable_counters="1" icon="fa-building"/>
|
||||
</searchpanel>
|
||||
</search>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_inbound_and_outbound_records_of_functional_tools_view_act" model="ir.actions.act_window">
|
||||
<field name="name">功能刀具出入库记录</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">stock.move.line</field>
|
||||
<field name="view_mode">tree,search</field>
|
||||
<field name="view_id"
|
||||
ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_tree"/>
|
||||
<field name="search_view_id"
|
||||
ref="sf_tool_management.sf_inbound_and_outbound_records_of_functional_tools_view_search"/>
|
||||
<field name="domain">[('functional_tool_name_id', '!=', False)]</field>
|
||||
</record>
|
||||
|
||||
|
||||
<!--================================================机床换刀申请================================================-->
|
||||
<record id="sf_machine_table_tool_changing_apply_tree" model="ir.ui.view">
|
||||
<field name="name">机床换刀申请</field>
|
||||
@@ -995,7 +491,7 @@
|
||||
<field name="name">功能刀具组装</field>
|
||||
<field name="model">sf.functional.tool.assembly</field>
|
||||
<field name="arch" type="xml">
|
||||
<form create="0" delete="0">
|
||||
<form create="0" delete="0" edit="0">
|
||||
<header>
|
||||
<button string="组装"
|
||||
name="%(sf_tool_management.sf_functional_tool_assembly_order_act)d"
|
||||
@@ -1056,7 +552,7 @@
|
||||
<group>
|
||||
<group>
|
||||
<field name="barcode_id" invisible="True"/>
|
||||
<field name="rfid" string="功能刀具rfid" readonly="false"/>
|
||||
<field name="rfid" string="功能刀具rfid"/>
|
||||
<field name="code"/>
|
||||
<field name="after_assembly_functional_tool_name"
|
||||
string="功能刀具名称"/>
|
||||
@@ -1093,41 +589,57 @@
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group col="1">
|
||||
<group col="1" attrs="{'invisible': [('handle_code_id', '=', False)]}">
|
||||
<div>
|
||||
<separator string="刀柄:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group col="1" attrs="{'invisible': [('handle_code_id', '=', False)]}">
|
||||
<div>
|
||||
<separator string="刀柄:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<field name="handle_code_id" string="序列号" placeholder="请选择"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="handle_freight_rfid" string="Rfid"/>
|
||||
<field name="handle_product_id" string="名称"/>
|
||||
<field name="cutting_tool_cutterhandle_model_id" string="型号"/>
|
||||
<field name="handle_specification_id" string="规格"/>
|
||||
<field name="sf_tool_brand_id_5" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1" attrs="{'invisible': [('chuck_freight_barcode', '=', False)]}">
|
||||
<div>
|
||||
<separator string="夹头:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="handle_code_id" string="序列号" placeholder="请选择"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="handle_name" string="名称"/>
|
||||
<field name="cutting_tool_cutterhandle_model_id" string="型号"/>
|
||||
<field name="handle_specification_id" string="规格"/>
|
||||
<field name="sf_tool_brand_id_5" string="品牌"/>
|
||||
<field name="chuck_freight_barcode" string="货位"/>
|
||||
<field name="chuck_product_id" string="名称"/>
|
||||
<field name="cutting_tool_cutterhead_model_id" string="型号"/>
|
||||
<field name="chuck_specification_id" string="规格"/>
|
||||
<field name="sf_tool_brand_id_6" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1" attrs="{'invisible': [('integral_code_id', '=', False)]}">
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<group col="1">
|
||||
<group col="1"
|
||||
attrs="{'invisible': [('integral_freight_barcode', '=', False)]}">
|
||||
<div>
|
||||
<separator string="整体式刀具:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<field name="integral_code_id" placeholder="请选择" string="序列号"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="integral_name" string="名称"/>
|
||||
<field name="integral_freight_barcode" string="货位"/>
|
||||
<field name="integral_product_id" string="名称"/>
|
||||
<field name="cutting_tool_integral_model_id" string="型号"/>
|
||||
<field name="integral_specification_id" string="规格"/>
|
||||
<field name="sf_tool_brand_id_1" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1" attrs="{'invisible': [('blade_code_id', '=', False)]}">
|
||||
<group col="1" attrs="{'invisible': [('blade_freight_barcode', '=', False)]}">
|
||||
<div>
|
||||
<separator string="刀片:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<field name="blade_code_id" placeholder="请选择" string="序列号"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="blade_name" string="名称"/>
|
||||
<field name="blade_freight_barcode" string="货位"/>
|
||||
<field name="blade_product_id" string="名称"/>
|
||||
<field name="cutting_tool_blade_model_id" string="型号"/>
|
||||
<field name="blade_specification_id" string="规格"/>
|
||||
<field name="sf_tool_brand_id_2" string="品牌"/>
|
||||
@@ -1135,45 +647,28 @@
|
||||
</group>
|
||||
</group>
|
||||
<group col="1">
|
||||
<group col="1" attrs="{'invisible': [('chuck_code_id', '=', False)]}">
|
||||
<div>
|
||||
<separator string="夹头:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="chuck_code_id" string="序列号" placeholder="请选择"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="chuck_name" string="名称"/>
|
||||
<field name="cutting_tool_cutterhead_model_id" string="型号"/>
|
||||
<field name="chuck_specification_id" string="规格"/>
|
||||
<field name="sf_tool_brand_id_6" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1" attrs="{'invisible': [('bar_code_id', '=', False)]}">
|
||||
<group col="1" attrs="{'invisible': [('bar_freight_barcode', '=', False)]}">
|
||||
<div>
|
||||
<separator string="刀杆:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="bar_code_id" placeholder="请选择" string="序列号"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="bar_name" string="名称"/>
|
||||
<field name="bar_freight_barcode" string="货位"/>
|
||||
<field name="bar_product_id" string="名称"/>
|
||||
<field name="cutting_tool_cutterbar_model_id" string="型号"/>
|
||||
<field name="bar_specification_id" string="规格"/>
|
||||
<field name="sf_tool_brand_id_3" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1" attrs="{'invisible': [('pad_code_id', '=', False)]}">
|
||||
<group col="1" attrs="{'invisible': [('pad_freight_barcode', '=', False)]}">
|
||||
<div>
|
||||
<separator string="刀盘:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="pad_code_id" placeholder="请选择" string="序列号"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="pad_name" string="名称"/>
|
||||
<field name="pad_freight_barcode" string="货位"/>
|
||||
<field name="pad_product_id" string="名称"/>
|
||||
<field name="cutting_tool_cutterpad_model_id" string="型号"/>
|
||||
<field name="pad_specification_id" string="规格"/>
|
||||
<field name="sf_tool_brand_id_4" string="品牌"/>
|
||||
|
||||
@@ -57,7 +57,7 @@
|
||||
</group>
|
||||
</group>
|
||||
<notebook>
|
||||
<page string="序列号">
|
||||
<page string="序列号" attrs="{'invisible': [('barcode_ids', '=', [])]}">
|
||||
<field name="barcode_ids">
|
||||
<tree>
|
||||
<field name="name"/>
|
||||
|
||||
@@ -9,7 +9,7 @@ class ToolChangeRequirementInformation(models.TransientModel):
|
||||
_description = '换刀需求信息'
|
||||
|
||||
code = fields.Char('编码', readonly=True)
|
||||
rfid = fields.Char('rfid', readonly=True)
|
||||
rfid = fields.Char('Rfid', readonly=True)
|
||||
tool_groups_id = fields.Many2one('sf.tool.groups', '刀具组', readonly=True)
|
||||
name = fields.Char('名称', related='maintenance_equipment_id.name', store=True, readonly=True)
|
||||
maintenance_equipment_id = fields.Many2one('maintenance.equipment', string='CNC机床', readonly=True)
|
||||
@@ -221,114 +221,187 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
|
||||
image = fields.Binary('图片')
|
||||
|
||||
@api.onchange('functional_tool_name')
|
||||
def _onchange_functional_tool_name(self):
|
||||
for item in self:
|
||||
if item.functional_tool_name:
|
||||
inventory = self.env['sf.tool.inventory'].sudo().search([('name', '=', item.functional_tool_name)])
|
||||
if inventory:
|
||||
item.after_name_id = inventory.id
|
||||
|
||||
# 功能刀具组装信息
|
||||
# 整体式刀具型号
|
||||
integral_code_id = fields.Many2one('stock.lot', string='整体式刀具序列号',
|
||||
domain=[('product_id.cutting_tool_material_id.name', '=', '整体式刀具'),
|
||||
('tool_material_status', '=', '可用')])
|
||||
# ===============整体式刀具型号=================
|
||||
integral_freight_barcode = fields.Char('整体式刀具货位')
|
||||
integral_product_id = fields.Many2one('product.product', string='整体式刀具名称',
|
||||
compute='_compute_integral_product_id', store=True)
|
||||
cutting_tool_integral_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='整体式刀具型号',
|
||||
related='integral_code_id.product_id.cutting_tool_model_id')
|
||||
integral_name = fields.Char('整体式刀具名称', related='integral_code_id.product_id.name')
|
||||
related='integral_product_id.cutting_tool_model_id')
|
||||
integral_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='整体式刀具规格',
|
||||
related='integral_code_id.product_id.specification_id')
|
||||
related='integral_product_id.specification_id')
|
||||
sf_tool_brand_id_1 = fields.Many2one('sf.machine.brand', string='整体式刀具品牌',
|
||||
related='integral_code_id.product_id.brand_id')
|
||||
related='integral_product_id.brand_id')
|
||||
|
||||
# 刀片型号
|
||||
blade_code_id = fields.Many2one('stock.lot', '刀片序列号',
|
||||
domain=[('product_id.cutting_tool_material_id.name', '=', '刀片'),
|
||||
('tool_material_status', '=', '可用')])
|
||||
@api.depends('integral_freight_barcode')
|
||||
def _compute_integral_product_id(self):
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.integral_freight_barcode)])
|
||||
if location:
|
||||
self.integral_product_id = location.product_id.id
|
||||
else:
|
||||
self.integral_product_id = False
|
||||
|
||||
# ===============刀片型号====================
|
||||
blade_freight_barcode = fields.Char('刀片货位')
|
||||
blade_product_id = fields.Many2one('product.product', string='刀片名称', compute='_compute_blade_product_id',
|
||||
store=True)
|
||||
cutting_tool_blade_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀片型号',
|
||||
related='blade_code_id.product_id.cutting_tool_model_id')
|
||||
blade_name = fields.Char('刀片名称', related='blade_code_id.product_id.name')
|
||||
related='blade_product_id.cutting_tool_model_id')
|
||||
blade_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀片规格',
|
||||
related='blade_code_id.product_id.specification_id')
|
||||
sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_code_id.product_id.brand_id')
|
||||
related='blade_product_id.specification_id')
|
||||
sf_tool_brand_id_2 = fields.Many2one('sf.machine.brand', '刀片品牌', related='blade_product_id.brand_id')
|
||||
|
||||
# 刀杆型号
|
||||
bar_code_id = fields.Many2one('stock.lot', '刀杆序列号',
|
||||
domain=[('product_id.cutting_tool_material_id.name', '=', '刀杆'),
|
||||
('tool_material_status', '=', '可用')])
|
||||
@api.depends('blade_freight_barcode')
|
||||
def _compute_blade_product_id(self):
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.blade_freight_barcode)])
|
||||
if location:
|
||||
self.blade_product_id = location.product_id.id
|
||||
else:
|
||||
self.blade_product_id = False
|
||||
|
||||
# ====================刀杆型号==================
|
||||
bar_freight_barcode = fields.Char('刀杆货位')
|
||||
bar_product_id = fields.Many2one('product.product', string='刀杆名称', compute='_compute_bar_product_id',
|
||||
store=True)
|
||||
cutting_tool_cutterbar_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀杆型号',
|
||||
related='bar_code_id.product_id.cutting_tool_model_id')
|
||||
bar_name = fields.Char('刀杆名称', related='bar_code_id.product_id.name')
|
||||
related='bar_product_id.cutting_tool_model_id')
|
||||
bar_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀杆规格',
|
||||
related='bar_code_id.product_id.specification_id')
|
||||
sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_code_id.product_id.brand_id')
|
||||
related='bar_product_id.specification_id')
|
||||
sf_tool_brand_id_3 = fields.Many2one('sf.machine.brand', '刀杆品牌', related='bar_product_id.brand_id')
|
||||
|
||||
# 刀盘型号
|
||||
pad_code_id = fields.Many2one('stock.lot', '刀盘序列号',
|
||||
domain=[('product_id.cutting_tool_material_id.name', '=', '刀盘'),
|
||||
('tool_material_status', '=', '可用')])
|
||||
@api.depends('bar_freight_barcode')
|
||||
def _compute_bar_product_id(self):
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.bar_freight_barcode)])
|
||||
if location:
|
||||
self.bar_product_id = location.product_id.id
|
||||
else:
|
||||
self.bar_product_id = False
|
||||
|
||||
# ===============刀盘型号===================
|
||||
pad_freight_barcode = fields.Char('刀盘货位')
|
||||
pad_product_id = fields.Many2one('product.product', string='刀盘名称', compute='_compute_pad_product_id',
|
||||
store=True)
|
||||
cutting_tool_cutterpad_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀盘型号',
|
||||
related='pad_code_id.product_id.cutting_tool_model_id')
|
||||
pad_name = fields.Char('刀盘名称', related='pad_code_id.product_id.name')
|
||||
related='pad_product_id.cutting_tool_model_id')
|
||||
pad_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀盘规格',
|
||||
related='pad_code_id.product_id.specification_id')
|
||||
sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_code_id.product_id.brand_id')
|
||||
related='pad_product_id.specification_id')
|
||||
sf_tool_brand_id_4 = fields.Many2one('sf.machine.brand', '刀盘品牌', related='pad_product_id.brand_id')
|
||||
|
||||
# 刀柄型号
|
||||
@api.depends('pad_freight_barcode')
|
||||
def _compute_pad_product_id(self):
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.pad_freight_barcode)])
|
||||
if location:
|
||||
self.pad_product_id = location.product_id.id
|
||||
else:
|
||||
self.pad_product_id = False
|
||||
|
||||
# ================刀柄型号===============
|
||||
handle_freight_rfid = fields.Char('刀柄Rfid', compute='_compute_rfid')
|
||||
handle_code_id = fields.Many2one('stock.lot', '刀柄序列号', required=True,
|
||||
domain=[('product_id.cutting_tool_material_id.name', '=', '刀柄'),
|
||||
('tool_material_status', '=', '可用')])
|
||||
handle_product_id = fields.Many2one('product.product', string='刀柄名称', compute='_compute_handle_product_id',
|
||||
store=True)
|
||||
cutting_tool_cutterhandle_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='刀柄型号',
|
||||
related='handle_code_id.product_id.cutting_tool_model_id')
|
||||
handle_name = fields.Char('刀柄名称', related='handle_code_id.product_id.name')
|
||||
handle_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='刀柄规格',
|
||||
related='handle_code_id.product_id.specification_id')
|
||||
sf_tool_brand_id_5 = fields.Many2one('sf.machine.brand', '刀柄品牌', related='handle_code_id.product_id.brand_id')
|
||||
|
||||
# 夹头型号
|
||||
chuck_code_id = fields.Many2one('stock.lot', '夹头序列号', required=True,
|
||||
domain=[('product_id.cutting_tool_material_id.name', '=', '夹头'),
|
||||
('tool_material_status', '=', '可用')])
|
||||
@api.depends('handle_code_id')
|
||||
def _compute_handle_product_id(self):
|
||||
if self.handle_code_id:
|
||||
self.handle_product_id = self.handle_code_id.product_id.id
|
||||
else:
|
||||
self.pad_product_id = False
|
||||
|
||||
# =================夹头型号==============
|
||||
chuck_freight_barcode = fields.Char('夹头货位')
|
||||
chuck_product_id = fields.Many2one('product.product', string='夹头名称', compute='_compute_chuck_product_id',
|
||||
store=True)
|
||||
cutting_tool_cutterhead_model_id = fields.Many2one('sf.cutting_tool.standard.library', string='夹头型号',
|
||||
related='chuck_code_id.product_id.cutting_tool_model_id')
|
||||
chuck_name = fields.Char('夹头名称', related='chuck_code_id.product_id.name')
|
||||
related='chuck_product_id.cutting_tool_model_id')
|
||||
chuck_specification_id = fields.Many2one('sf.tool.materials.basic.parameters', string='夹头规格',
|
||||
related='chuck_code_id.product_id.specification_id')
|
||||
sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_code_id.product_id.brand_id')
|
||||
related='chuck_product_id.specification_id')
|
||||
sf_tool_brand_id_6 = fields.Many2one('sf.machine.brand', '夹头品牌', related='chuck_product_id.brand_id')
|
||||
|
||||
@api.depends('chuck_freight_barcode')
|
||||
def _compute_chuck_product_id(self):
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.chuck_freight_barcode)])
|
||||
if location:
|
||||
self.chuck_product_id = location.product_id.id
|
||||
else:
|
||||
self.chuck_product_id = False
|
||||
|
||||
# ========================================
|
||||
|
||||
def on_barcode_scanned(self, barcode):
|
||||
"""
|
||||
智能工厂组装单处扫码绑定刀具物料')
|
||||
智能工厂组装单处扫码绑定刀具物料
|
||||
"""
|
||||
for record in self:
|
||||
if 'DJWL' in barcode:
|
||||
records = record.env['stock.lot'].search([('name', '=', barcode)])
|
||||
if not records:
|
||||
raise ValidationError('扫描的条形码数据不存在,请重新扫描!')
|
||||
for record_stock_lot in records:
|
||||
if record_stock_lot.quant_ids[-1].location_id.name == '刀具组装位置':
|
||||
raise ValidationError('该刀具物料已使用,请重新选择!!!')
|
||||
elif record_stock_lot.quant_ids[-1].location_id.name not in '刀具房':
|
||||
raise ValidationError('该刀具物料未入库,请重新选择!!!')
|
||||
tool_material_name = record_stock_lot.product_id.cutting_tool_material_id.name
|
||||
if tool_material_name == '整体式刀具':
|
||||
record.integral_code_id = record_stock_lot.id
|
||||
elif tool_material_name == '刀片':
|
||||
record.blade_code_id = record_stock_lot.id
|
||||
elif tool_material_name == '刀杆':
|
||||
record.bar_code_id = record_stock_lot.id
|
||||
elif tool_material_name == '刀盘':
|
||||
record.pad_code_id = record_stock_lot.id
|
||||
elif tool_material_name == '刀柄':
|
||||
record.handle_code_id = record_stock_lot.id
|
||||
elif tool_material_name == '夹头':
|
||||
record.chuck_code_id = record_stock_lot.id
|
||||
lot_ids = self.env['stock.lot'].sudo().search([('rfid', '=', barcode)])
|
||||
if lot_ids:
|
||||
for lot_id in lot_ids:
|
||||
if lot_id.quant_ids[-1].location_id.name in '刀具房':
|
||||
record.handle_code_id = lot_id.id
|
||||
elif lot_id.quant_ids[-1].location_id.name == '刀具组装位置':
|
||||
raise ValidationError('该刀柄已使用,请重新扫描!!!')
|
||||
else:
|
||||
raise ValidationError('该刀柄未入库,请重新扫描!!!')
|
||||
else:
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', barcode)])
|
||||
if location:
|
||||
material_name = location.product_id.cutting_tool_material_id.name
|
||||
if material_name == '夹头':
|
||||
record.chuck_freight_barcode = barcode
|
||||
elif material_name == '整体式刀具':
|
||||
record.integral_freight_barcode = barcode
|
||||
record.blade_freight_barcode = ''
|
||||
record.bar_freight_barcode = ''
|
||||
record.pad_freight_barcode = ''
|
||||
elif material_name == '刀片':
|
||||
record.blade_freight_barcode = barcode
|
||||
record.integral_freight_barcode = ''
|
||||
elif material_name == '刀杆':
|
||||
record.bar_freight_barcode = barcode
|
||||
record.integral_freight_barcode = ''
|
||||
record.pad_freight_barcode = ''
|
||||
elif material_name == '刀盘':
|
||||
record.pad_freight_barcode = barcode
|
||||
record.integral_freight_barcode = ''
|
||||
record.bar_freight_barcode = ''
|
||||
else:
|
||||
raise ValidationError('扫描的刀具物料不存在,请重新扫描!')
|
||||
else:
|
||||
raise ValidationError('扫描的刀具物料不存在,请重新扫描!')
|
||||
|
||||
@api.depends('handle_code_id')
|
||||
def _compute_rfid(self):
|
||||
for item in self:
|
||||
if item:
|
||||
item.rfid = item.handle_code_id.rfid
|
||||
item.handle_freight_rfid = item.handle_code_id.rfid
|
||||
else:
|
||||
record.rfid = barcode
|
||||
item.rfid = None
|
||||
item.handle_freight_rfid = None
|
||||
|
||||
# 组装功能刀具参数信息
|
||||
after_name_id = fields.Many2one('sf.tool.inventory', string='功能刀具名称', required=True)
|
||||
barcode_id = fields.Many2one('stock.lot', string='功能刀具序列号')
|
||||
rfid = fields.Char('rfid', required=True)
|
||||
tool_code = fields.Char(string='功能刀具编码', readonly=True, compute='_compute_tool_code')
|
||||
after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', compute='_compute_name')
|
||||
rfid = fields.Char('Rfid', compute='_compute_rfid')
|
||||
tool_code = fields.Char(string='功能刀具编码', compute='_compute_tool_code')
|
||||
after_assembly_functional_tool_name = fields.Char(string='组装后功能刀具名称', compute='_compute_name', store=True)
|
||||
after_assembly_functional_tool_type_id = fields.Many2one('sf.functional.cutting.tool.model',
|
||||
string='组装后功能刀具类型',
|
||||
compute='_compute_after_assembly_functional_tool_type_id')
|
||||
string='组装后功能刀具类型')
|
||||
after_assembly_functional_tool_diameter = fields.Integer(string='组装后功能刀具直径(mm)')
|
||||
after_assembly_knife_tip_r_angle = fields.Float(string='组装后刀尖R角(mm)')
|
||||
after_assembly_new_former = fields.Selection([('0', '新'), ('1', '旧')], string='组装后新/旧', default='0')
|
||||
@@ -347,6 +420,23 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
after_assembly_effective_length = fields.Float(string='组装后有效长(mm)')
|
||||
L_D_number = fields.Float(string='L/D值(mm)', compute='_compute_l_d_number')
|
||||
hiding_length = fields.Float(string='避空长(mm)')
|
||||
after_tool_groups_id = fields.Many2one('sf.tool.groups', string='组装后刀具组')
|
||||
|
||||
@api.onchange('after_name_id')
|
||||
def _onchange_number(self):
|
||||
for item in self:
|
||||
if item.after_name_id:
|
||||
item.after_assembly_functional_tool_diameter = item.after_name_id.diameter
|
||||
item.after_assembly_knife_tip_r_angle = item.after_name_id.angle
|
||||
item.after_assembly_max_lifetime_value = item.after_name_id.life_span
|
||||
item.after_assembly_tool_loading_length = item.after_name_id.tool_length
|
||||
item.after_assembly_functional_tool_length = item.after_name_id.extension
|
||||
item.hiding_length = item.after_name_id.blade_length
|
||||
item.after_assembly_functional_tool_type_id = item.after_name_id.functional_cutting_tool_model_id.id
|
||||
item.after_tool_groups_id = item.after_name_id.tool_groups_id.id
|
||||
else:
|
||||
item.after_assembly_functional_tool_type_id = item.functional_tool_type_id
|
||||
item.after_tool_groups_id = item.tool_groups_id.id
|
||||
|
||||
# functional_tool_cutting_type = fields.Char(string='功能刀具切削类型', readonly=False)
|
||||
# res_partner_id = fields.Many2one('res.partner', '智能工厂', domain="[('is_factory', '=', True)]")
|
||||
@@ -357,30 +447,29 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
for obj in self:
|
||||
str_1 = 'GNDJ-%s' % obj.after_assembly_functional_tool_type_id.code
|
||||
str_2 = ''
|
||||
num = None
|
||||
if obj.handle_specification_id:
|
||||
if obj.integral_specification_id:
|
||||
str_2 = '%s-D%sL%sB%sH%s-' % (
|
||||
str_1, obj.integral_specification_id.blade_diameter, obj.after_assembly_tool_loading_length,
|
||||
obj.integral_specification_id.blade_length, obj.handle_specification_id.total_length)
|
||||
num = self._get_code(str_2)
|
||||
elif obj.bar_specification_id:
|
||||
str_2 = '%s-D%sL%sB%sH%s-' % (
|
||||
str_1, obj.bar_specification_id.cutter_arbor_diameter, obj.after_assembly_tool_loading_length,
|
||||
obj.bar_specification_id.blade_length, obj.handle_specification_id.total_length)
|
||||
num = self._get_code(str_2)
|
||||
elif obj.pad_specification_id:
|
||||
str_2 = '%s-D%sL%sB%sH%s-' % (
|
||||
str_1, obj.pad_specification_id.cutter_head_diameter, obj.after_assembly_tool_loading_length,
|
||||
obj.pad_specification_id.cut_depth_max, obj.handle_specification_id.total_length,
|
||||
)
|
||||
num = self._get_code(str_2)
|
||||
obj.tool_code = str_2 + str(num)
|
||||
else:
|
||||
obj.tool_code = str_2
|
||||
return True
|
||||
obj.tool_code = str_2 + str(self._get_code(str_2))
|
||||
else:
|
||||
obj.tool_code = None
|
||||
obj.tool_code = str_2
|
||||
|
||||
def _get_code(self, str_2):
|
||||
functional_tool_assembly = self.env['sf.functional.tool.assembly'].sudo().search(
|
||||
functional_tool_assembly = self.env['sf.functional.cutting.tool.entity'].sudo().search(
|
||||
[('code', 'like', str_2)],
|
||||
limit=1,
|
||||
order="id desc"
|
||||
@@ -392,40 +481,30 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
num = "%03d" % m
|
||||
return num
|
||||
|
||||
@api.depends('after_assembly_functional_tool_diameter', 'after_assembly_knife_tip_r_angle', 'tool_groups_id')
|
||||
@api.depends('after_name_id')
|
||||
def _compute_name(self):
|
||||
for obj in self:
|
||||
if obj.tool_groups_id:
|
||||
obj.after_assembly_functional_tool_name = '%s-D%sR%s' % (
|
||||
obj.tool_groups_id.name, obj.after_assembly_functional_tool_diameter,
|
||||
obj.after_assembly_knife_tip_r_angle)
|
||||
if obj.after_name_id:
|
||||
obj.after_assembly_functional_tool_name = obj.after_name_id.name
|
||||
else:
|
||||
obj.after_assembly_functional_tool_name = None
|
||||
obj.after_assembly_functional_tool_name = ''
|
||||
|
||||
@api.onchange('integral_code_id')
|
||||
@api.onchange('integral_freight_barcode')
|
||||
def _onchange_after_assembly_functional_tool_diameter(self):
|
||||
for obj in self:
|
||||
if obj.integral_code_id:
|
||||
obj.after_assembly_functional_tool_diameter = obj.integral_code_id.product_id.cutting_tool_blade_diameter
|
||||
if obj.integral_product_id:
|
||||
obj.after_assembly_functional_tool_diameter = obj.integral_product_id.cutting_tool_blade_diameter
|
||||
else:
|
||||
obj.after_assembly_functional_tool_diameter = 0
|
||||
|
||||
@api.onchange('blade_code_id')
|
||||
@api.onchange('blade_freight_barcode')
|
||||
def _onchange_after_assembly_knife_tip_r_angle(self):
|
||||
for obj in self:
|
||||
if obj.blade_code_id:
|
||||
obj.after_assembly_knife_tip_r_angle = obj.blade_code_id.product_id.cutting_tool_blade_tip_circular_arc_radius
|
||||
if obj.blade_product_id:
|
||||
obj.after_assembly_knife_tip_r_angle = obj.blade_product_id.cutting_tool_blade_tip_circular_arc_radius
|
||||
else:
|
||||
obj.after_assembly_knife_tip_r_angle = 0
|
||||
|
||||
@api.depends('functional_tool_type_id')
|
||||
def _compute_after_assembly_functional_tool_type_id(self):
|
||||
for obj in self:
|
||||
if obj.functional_tool_type_id:
|
||||
obj.after_assembly_functional_tool_type_id = obj.functional_tool_type_id
|
||||
else:
|
||||
obj.after_assembly_functional_tool_type_id = None
|
||||
|
||||
@api.depends('hiding_length', 'after_assembly_functional_tool_diameter')
|
||||
def _compute_l_d_number(self):
|
||||
for record in self:
|
||||
@@ -434,28 +513,23 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
else:
|
||||
record.L_D_number = 0
|
||||
|
||||
@api.constrains('after_assembly_tool_loading_length', 'after_assembly_functional_tool_length')
|
||||
@api.constrains('after_assembly_tool_loading_length', 'after_assembly_functional_tool_length',
|
||||
'after_assembly_max_lifetime_value', 'after_assembly_alarm_value',
|
||||
'after_assembly_effective_length', 'hiding_length')
|
||||
def _check_length_control(self):
|
||||
for obj in self:
|
||||
if obj.after_assembly_tool_loading_length == 0:
|
||||
raise ValidationError('组装参数信息【总长度】不能为0!!!')
|
||||
if obj.after_assembly_functional_tool_length == 0:
|
||||
raise ValidationError('组装参数信息【伸出长】不能为0!!!')
|
||||
|
||||
@api.constrains('rfid')
|
||||
def _check_rfid(self):
|
||||
self.get_rfid()
|
||||
|
||||
@api.onchange('rfid')
|
||||
def _onchange_rfid(self):
|
||||
self.get_rfid()
|
||||
|
||||
def get_rfid(self):
|
||||
for obj in self:
|
||||
if obj.rfid:
|
||||
tool_entity = self.env['sf.functional.cutting.tool.entity'].sudo().search([('rfid', '=', obj.rfid)])
|
||||
if tool_entity:
|
||||
raise ValidationError('【%s】的rfid已被使用,请重新录入!!!' % obj.rfid)
|
||||
if obj.after_assembly_max_lifetime_value == 0:
|
||||
raise ValidationError('组装参数信息【最大寿命值】不能为0!!!')
|
||||
if obj.after_assembly_alarm_value == 0:
|
||||
raise ValidationError('组装参数信息【报警值】不能为0!!!')
|
||||
if obj.after_assembly_effective_length == 0:
|
||||
raise ValidationError('组装参数信息【有效长】不能为0!!!')
|
||||
if obj.hiding_length == 0:
|
||||
raise ValidationError('组装参数信息【避空长】不能为0!!!')
|
||||
|
||||
def functional_tool_assembly(self):
|
||||
"""
|
||||
@@ -479,18 +553,18 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
# 创建刀具组装入库单
|
||||
self.env['stock.picking'].create_stocking_picking(stock_lot, functional_tool_assembly, self)
|
||||
# 刀具物料出库
|
||||
if self.integral_code_id:
|
||||
product_id.tool_material_stock_moves(self.integral_code_id)
|
||||
if self.blade_code_id:
|
||||
product_id.tool_material_stock_moves(self.blade_code_id)
|
||||
if self.bar_code_id:
|
||||
product_id.tool_material_stock_moves(self.bar_code_id)
|
||||
if self.pad_code_id:
|
||||
product_id.tool_material_stock_moves(self.pad_code_id)
|
||||
if self.handle_code_id:
|
||||
product_id.tool_material_stock_moves(self.handle_code_id)
|
||||
if self.chuck_code_id:
|
||||
product_id.tool_material_stock_moves(self.chuck_code_id)
|
||||
if self.integral_product_id:
|
||||
self.integral_product_id.material_stock_moves(self.integral_freight_barcode)
|
||||
if self.blade_product_id:
|
||||
self.blade_product_id.material_stock_moves(self.blade_freight_barcode)
|
||||
if self.bar_product_id:
|
||||
self.bar_product_id.material_stock_moves(self.bar_freight_barcode)
|
||||
if self.pad_product_id:
|
||||
self.pad_product_id.material_stock_moves(self.pad_freight_barcode)
|
||||
if self.chuck_product_id:
|
||||
self.chuck_product_id.material_stock_moves(self.chuck_freight_barcode)
|
||||
|
||||
# ============================创建功能刀具列表、安全库存记录===============================
|
||||
# 封装功能刀具数据
|
||||
@@ -499,9 +573,9 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
record_1 = self.env['sf.functional.cutting.tool.entity'].create(desc_2)
|
||||
# 创建安全库存信息
|
||||
self.env['sf.real.time.distribution.of.functional.tools'].create_or_edit_safety_stock({
|
||||
'name': self.after_assembly_functional_tool_name,
|
||||
'functional_name_id': self.after_name_id.id,
|
||||
'sf_cutting_tool_type_id': self.after_assembly_functional_tool_type_id.id,
|
||||
'tool_groups_id': self.tool_groups_id.id,
|
||||
'tool_groups_id': self.after_tool_groups_id.id,
|
||||
'diameter': self.after_assembly_functional_tool_diameter,
|
||||
'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
|
||||
'coarse_middle_thin': self.after_assembly_coarse_middle_thin,
|
||||
@@ -530,10 +604,10 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
"""
|
||||
功能刀具组装物料必填判断
|
||||
"""
|
||||
if not self.integral_code_id and not self.blade_code_id:
|
||||
if not self.integral_product_id and not self.blade_product_id:
|
||||
raise ValidationError('【整体式刀具】和【刀片】必须填写一个!')
|
||||
if self.blade_code_id:
|
||||
if not self.bar_code_id and not self.pad_code_id:
|
||||
if self.blade_product_id:
|
||||
if not self.bar_product_id and not self.pad_product_id:
|
||||
raise ValidationError('【刀盘】和【刀杆】必须填写一个!')
|
||||
|
||||
def get_desc_1(self, stock_lot):
|
||||
@@ -541,13 +615,13 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
'barcode_id': stock_lot.id,
|
||||
'code': self.tool_code,
|
||||
'rfid': self.rfid,
|
||||
'tool_groups_id': self.tool_groups_id.id,
|
||||
'integral_code_id': self.integral_code_id.id,
|
||||
'blade_code_id': self.blade_code_id.id,
|
||||
'bar_code_id': self.bar_code_id.id,
|
||||
'pad_code_id': self.pad_code_id.id,
|
||||
'tool_groups_id': self.after_tool_groups_id.id,
|
||||
'integral_freight_barcode': self.integral_freight_barcode,
|
||||
'blade_freight_barcode': self.blade_freight_barcode,
|
||||
'bar_freight_barcode': self.bar_freight_barcode,
|
||||
'pad_freight_barcode': self.pad_freight_barcode,
|
||||
'handle_code_id': self.handle_code_id.id,
|
||||
'chuck_code_id': self.chuck_code_id.id,
|
||||
'chuck_freight_barcode': self.chuck_freight_barcode,
|
||||
|
||||
'after_assembly_functional_tool_name': self.after_assembly_functional_tool_name,
|
||||
'after_assembly_functional_tool_type_id': self.after_assembly_functional_tool_type_id.id,
|
||||
@@ -577,17 +651,18 @@ class FunctionalToolAssemblyOrder(models.TransientModel):
|
||||
return {
|
||||
'barcode_id': stock_lot.id,
|
||||
'code': self.tool_code,
|
||||
'name': self.after_assembly_functional_tool_name,
|
||||
'name': self.after_name_id.name,
|
||||
'tool_name_id': self.after_name_id.id,
|
||||
'rfid': self.rfid,
|
||||
'tool_groups_id': self.tool_groups_id.id,
|
||||
'tool_groups_id': self.after_tool_groups_id.id,
|
||||
'functional_tool_name_id': functional_tool_assembly_id.id,
|
||||
'sf_cutting_tool_type_id': self.after_assembly_functional_tool_type_id.id,
|
||||
'cutting_tool_integral_model_id': self.integral_code_id.product_id.id,
|
||||
'cutting_tool_blade_model_id': self.blade_code_id.product_id.id,
|
||||
'cutting_tool_cutterbar_model_id': self.bar_code_id.product_id.id,
|
||||
'cutting_tool_cutterpad_model_id': self.pad_code_id.product_id.id,
|
||||
'cutting_tool_cutterhandle_model_id': self.handle_code_id.product_id.id,
|
||||
'cutting_tool_cutterhead_model_id': self.chuck_code_id.product_id.id,
|
||||
'cutting_tool_integral_model_id': self.integral_product_id.id,
|
||||
'cutting_tool_blade_model_id': self.blade_product_id.id,
|
||||
'cutting_tool_cutterbar_model_id': self.bar_product_id.id,
|
||||
'cutting_tool_cutterpad_model_id': self.pad_product_id.id,
|
||||
'cutting_tool_cutterhandle_model_id': self.handle_product_id.id,
|
||||
'cutting_tool_cutterhead_model_id': self.chuck_product_id.id,
|
||||
|
||||
'functional_tool_diameter': self.after_assembly_functional_tool_diameter,
|
||||
'knife_tip_r_angle': self.after_assembly_knife_tip_r_angle,
|
||||
@@ -641,7 +716,7 @@ class StockPicking(models.Model):
|
||||
'code': obj.tool_code,
|
||||
'rfid': obj.rfid,
|
||||
'functional_tool_name': obj.after_assembly_functional_tool_name,
|
||||
'tool_groups_id': obj.tool_groups_id.id
|
||||
'tool_groups_id': obj.after_tool_groups_id.id
|
||||
})
|
||||
# 将刀具组装入库单的状态更改为就绪
|
||||
picking_id.action_confirm()
|
||||
@@ -718,6 +793,32 @@ class ProductProduct(models.Model):
|
||||
# 创建功能刀具该批次/序列号 库存移动和移动历史
|
||||
tool_material.create_stock_quant(location_inventory_id, stock_location_id, None, '功能刀具组装', False)
|
||||
|
||||
def material_stock_moves(self, shelf_location_barcode):
|
||||
# 创建库存移动记录
|
||||
stock_move_id = self.env['stock.move'].sudo().create({
|
||||
'name': '功能刀具组装',
|
||||
'product_id': self.id,
|
||||
'location_id': self.env['stock.location'].search([('name', '=', '刀具房')]).id,
|
||||
'location_dest_id': self.env['stock.location'].search([('name', '=', '刀具组装位置')]).id,
|
||||
'product_uom_qty': 1.00,
|
||||
'state': 'done'
|
||||
})
|
||||
|
||||
location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', shelf_location_barcode)])
|
||||
# 创建移动历史记录
|
||||
stock_move_line_id = self.env['stock.move.line'].sudo().create({
|
||||
'product_id': self.id,
|
||||
'move_id': stock_move_id.id,
|
||||
'current_location_id': location.id,
|
||||
'install_tool_time': fields.Datetime.now(),
|
||||
'qty_done': 1.0,
|
||||
'state': 'done',
|
||||
})
|
||||
|
||||
location.product_num = location.product_num - 1
|
||||
|
||||
return stock_move_id, stock_move_line_id
|
||||
|
||||
|
||||
class StockLot(models.Model):
|
||||
_inherit = 'stock.lot'
|
||||
@@ -752,7 +853,7 @@ class StockLot(models.Model):
|
||||
'code': '' if not obj else obj.tool_code,
|
||||
'rfid': '' if not obj else obj.rfid,
|
||||
'functional_tool_name': '' if not obj else obj.after_assembly_functional_tool_name,
|
||||
'tool_groups_id': False if not obj else obj.tool_groups_id.id
|
||||
'tool_groups_id': False if not obj else obj.after_tool_groups_id.id
|
||||
})
|
||||
return stock_move_id, stock_move_line_id
|
||||
|
||||
|
||||
@@ -200,97 +200,6 @@
|
||||
</group>
|
||||
<group string="组装物料信息" col="1">
|
||||
<field name="_barcode_scanned" widget="barcode_handler"/>
|
||||
<group col="1"
|
||||
attrs="{'invisible': ['|','|',('blade_code_id', '!=', False),('bar_code_id', '!=', False),('pad_code_id', '!=', False)]}">
|
||||
<div>
|
||||
<separator string="整体式刀具:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="integral_code_id" placeholder="请选择" string="序列号"
|
||||
class="custom_required"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="integral_name" string="名称"/>
|
||||
<field name="integral_specification_id" string="规格"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="cutting_tool_integral_model_id" string="型号"/>
|
||||
<field name="sf_tool_brand_id_1" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1" attrs="{'invisible': [('integral_code_id', '!=', False)]}">
|
||||
<div>
|
||||
<separator string="刀片:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="blade_code_id" placeholder="请选择" string="序列号"
|
||||
class="custom_required"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="blade_name" string="名称"/>
|
||||
<field name="blade_specification_id" string="规格"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="cutting_tool_blade_model_id" string="型号"/>
|
||||
<field name="sf_tool_brand_id_2" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1"
|
||||
attrs="{'invisible': ['|',('integral_code_id', '!=', False),('pad_code_id', '!=', False)]}">
|
||||
<div>
|
||||
<separator string="刀杆:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="bar_code_id" placeholder="请选择" string="序列号"
|
||||
class="custom_required"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="bar_name" string="名称"/>
|
||||
<field name="bar_specification_id" string="规格"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="cutting_tool_cutterbar_model_id" string="型号"/>
|
||||
<field name="sf_tool_brand_id_3" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1"
|
||||
attrs="{'invisible': ['|',('integral_code_id', '!=', False),('bar_code_id', '!=', False)]}">
|
||||
<div>
|
||||
<separator string="刀盘:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="pad_code_id" placeholder="请选择" string="序列号"
|
||||
class="custom_required"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="pad_name" string="名称"/>
|
||||
<field name="pad_specification_id" string="规格"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="cutting_tool_cutterpad_model_id" string="型号"/>
|
||||
<field name="sf_tool_brand_id_4" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1">
|
||||
<div>
|
||||
<separator string="刀柄:" style="font-size: 13px;"/>
|
||||
@@ -301,10 +210,13 @@
|
||||
class="custom_required"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="handle_freight_rfid" string="Rfid"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="handle_name" string="名称"/>
|
||||
<field name="handle_product_id" string="名称"/>
|
||||
<field name="handle_specification_id" string="规格"/>
|
||||
</group>
|
||||
<group>
|
||||
@@ -313,20 +225,101 @@
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1"
|
||||
attrs="{'invisible': ['|','|',('blade_freight_barcode', '!=', False),('bar_freight_barcode', '!=', False),('pad_freight_barcode', '!=', False)]}">
|
||||
<div>
|
||||
<separator string="整体式刀具:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="integral_freight_barcode" string="货位"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="integral_product_id" string="名称"/>
|
||||
<field name="integral_specification_id" string="规格"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="cutting_tool_integral_model_id" string="型号"/>
|
||||
<field name="sf_tool_brand_id_1" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1" attrs="{'invisible': [('integral_freight_barcode', '!=', False)]}">
|
||||
<div>
|
||||
<separator string="刀片:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="blade_freight_barcode" string="货位"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="blade_product_id" string="名称"/>
|
||||
<field name="blade_specification_id" string="规格"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="cutting_tool_blade_model_id" string="型号"/>
|
||||
<field name="sf_tool_brand_id_2" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1"
|
||||
attrs="{'invisible': ['|',('integral_freight_barcode', '!=', False),('pad_freight_barcode', '!=', False)]}">
|
||||
<div>
|
||||
<separator string="刀杆:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="bar_freight_barcode" string="货位"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="bar_product_id" string="名称"/>
|
||||
<field name="bar_specification_id" string="规格"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="cutting_tool_cutterbar_model_id" string="型号"/>
|
||||
<field name="sf_tool_brand_id_3" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1"
|
||||
attrs="{'invisible': ['|',('integral_freight_barcode', '!=', False),('bar_freight_barcode', '!=', False)]}">
|
||||
<div>
|
||||
<separator string="刀盘:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="pad_freight_barcode" string="货位"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="pad_product_id" string="名称"/>
|
||||
<field name="pad_specification_id" string="规格"/>
|
||||
</group>
|
||||
<group>
|
||||
<field name="cutting_tool_cutterpad_model_id" string="型号"/>
|
||||
<field name="sf_tool_brand_id_4" string="品牌"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
<group col="1">
|
||||
<div>
|
||||
<separator string="夹头:" style="font-size: 13px;"/>
|
||||
</div>
|
||||
<group>
|
||||
<group>
|
||||
<field name="chuck_code_id" string="序列号" placeholder="请选择"
|
||||
class="custom_required"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="chuck_freight_barcode" string="货位"/>
|
||||
</group>
|
||||
</group>
|
||||
<group col="2">
|
||||
<group>
|
||||
<field name="chuck_name" string="名称"/>
|
||||
<field name="chuck_product_id" string="名称"/>
|
||||
<field name="chuck_specification_id" string="规格"/>
|
||||
</group>
|
||||
<group>
|
||||
@@ -339,36 +332,46 @@
|
||||
|
||||
<group string="组装参数信息">
|
||||
<group>
|
||||
<field name="barcode_id" invisible="True"/>
|
||||
<field name="tool_code" readonly="True"/>
|
||||
<field name="rfid" placeholder="请输入rfid码" class="custom_required"/>
|
||||
<field name="after_assembly_functional_tool_name" string="功能刀具名称"/>
|
||||
<field name="after_assembly_functional_tool_type_id" string="功能刀具类型"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="tool_groups_id"/>
|
||||
<field name="after_assembly_functional_tool_diameter" string="刀具直径(mm)"
|
||||
class="custom_required"/>
|
||||
<field name="after_assembly_knife_tip_r_angle" string="刀尖R角(mm)"
|
||||
class="custom_required"/>
|
||||
<field name="after_assembly_new_former" string="新/旧"/>
|
||||
<field name="cut_time" attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/>
|
||||
<field name="cut_length" attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/>
|
||||
<field name="cut_number" attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/>
|
||||
<group>
|
||||
<field name="barcode_id" invisible="True"/>
|
||||
<field name="tool_code" readonly="True"/>
|
||||
<field name="rfid" class="custom_required"/>
|
||||
<field name="after_name_id" string="功能刀具名称" placeholder="请选择功能刀具名称"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="after_assembly_functional_tool_name" string="功能刀具名称" invisible="1"/>
|
||||
<field name="after_assembly_functional_tool_type_id" string="功能刀具类型"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="after_tool_groups_id"
|
||||
options="{'no_create': True, 'no_quick_create': True}"/>
|
||||
<field name="after_assembly_functional_tool_diameter" string="刀具直径(mm)"
|
||||
class="custom_required"/>
|
||||
<field name="after_assembly_knife_tip_r_angle" string="刀尖R角(mm)"
|
||||
class="custom_required"/>
|
||||
<field name="after_assembly_new_former" string="新/旧"/>
|
||||
<field name="cut_time" attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/>
|
||||
<field name="cut_length"
|
||||
attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/>
|
||||
<field name="cut_number"
|
||||
attrs="{'invisible': [('after_assembly_new_former','=','0')]}"/>
|
||||
</group>
|
||||
</group>
|
||||
<group>
|
||||
<field name="after_assembly_whether_standard_knife" string="是否标准刀"/>
|
||||
<field name="after_assembly_coarse_middle_thin" string="粗/中/精"/>
|
||||
<field name="after_assembly_max_lifetime_value" string="最大寿命值(min)"
|
||||
class="custom_required"/>
|
||||
<field name="after_assembly_alarm_value" string="报警值(min)" class="custom_required"/>
|
||||
<field name="after_assembly_used_value" string="已使用值(min)"/>
|
||||
<field name="after_assembly_tool_loading_length" string="总长度(mm)"
|
||||
class="custom_required"/>
|
||||
<field name="after_assembly_functional_tool_length" string="伸出长(mm)"
|
||||
class="custom_required"/>
|
||||
<field name="after_assembly_effective_length" string="有效长(mm)" class="custom_required"/>
|
||||
<field name="hiding_length" class="custom_required"/>
|
||||
<field name="L_D_number"/>
|
||||
<group>
|
||||
<field name="after_assembly_whether_standard_knife" string="是否标准刀"/>
|
||||
<field name="after_assembly_coarse_middle_thin" string="粗/中/精"/>
|
||||
<field name="after_assembly_max_lifetime_value" string="最大寿命值(min)"
|
||||
class="custom_required"/>
|
||||
<field name="after_assembly_alarm_value" string="报警值(min)" class="custom_required"/>
|
||||
<field name="after_assembly_used_value" string="已使用值(min)"/>
|
||||
<field name="after_assembly_tool_loading_length" string="总长度(mm)"
|
||||
class="custom_required"/>
|
||||
<field name="after_assembly_functional_tool_length" string="伸出长(mm)"
|
||||
class="custom_required"/>
|
||||
<field name="after_assembly_effective_length" string="有效长(mm)"
|
||||
class="custom_required"/>
|
||||
<field name="hiding_length" class="custom_required"/>
|
||||
<field name="L_D_number"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
|
||||
@@ -1,2 +1,3 @@
|
||||
# -*-coding:utf-8-*-
|
||||
from . import models
|
||||
from . import wizard
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
'data/ir_cron_data.xml',
|
||||
'security/sf_stock_security.xml',
|
||||
'security/ir.model.access.csv',
|
||||
'wizard/wizard_view.xml',
|
||||
'views/view.xml',
|
||||
'views/shelf_location.xml',
|
||||
'views/change_stock_move_views.xml',
|
||||
|
||||
@@ -1,4 +1,6 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
import re
|
||||
|
||||
import datetime
|
||||
import logging
|
||||
import base64
|
||||
@@ -19,14 +21,6 @@ class SfLocation(models.Model):
|
||||
name = fields.Char('Location Name', required=True, size=20)
|
||||
barcode = fields.Char('Barcode', copy=False, size=15)
|
||||
|
||||
check_state = fields.Selection([
|
||||
('enable', '启用'),
|
||||
('close', '关闭')
|
||||
], string='审核状态', default='close')
|
||||
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
|
||||
# 仓库类别(selection:库区、库位、货位)
|
||||
# location_type = fields.Selection([
|
||||
# ('库区', '库区'),
|
||||
@@ -132,7 +126,7 @@ class SfLocation(models.Model):
|
||||
for record in self:
|
||||
if record.product_sn_id:
|
||||
record.product_id = record.product_sn_id.product_id
|
||||
record.location_status = '占用'
|
||||
# record.location_status = '占用'
|
||||
else:
|
||||
record.product_id = False
|
||||
# record.location_status = '空闲'
|
||||
@@ -197,6 +191,7 @@ class SfLocation(models.Model):
|
||||
# return res
|
||||
|
||||
# 生成货位
|
||||
|
||||
def create_location(self):
|
||||
"""
|
||||
当仓库类型为货架时,自动生成其下面的货位,数量为货架层数*层数容量
|
||||
@@ -228,11 +223,14 @@ class SfLocation(models.Model):
|
||||
|
||||
class SfShelf(models.Model):
|
||||
_name = 'sf.shelf'
|
||||
_inherit = ['printing.utils']
|
||||
_description = '货架'
|
||||
_order = 'name'
|
||||
_order = 'create_date desc'
|
||||
|
||||
name = fields.Char('货架名称', required=True, size=20)
|
||||
active = fields.Boolean("有效", default=True)
|
||||
barcode = fields.Char('编码', copy=False, size=15, required=True)
|
||||
|
||||
# 货位
|
||||
location_ids = fields.One2many('sf.shelf.location', 'shelf_id', string='货位')
|
||||
|
||||
@@ -306,11 +304,41 @@ class SfShelf(models.Model):
|
||||
j_str = str(j + 1).zfill(3) # 确保是两位数,如果不足两位,左侧补0
|
||||
return area_type_barcode + self.channel + self.direction + '-' + self.barcode + '-' + i_str + '-' + j_str
|
||||
|
||||
def print_all_location_barcode(self):
|
||||
"""
|
||||
打印所有货位编码
|
||||
"""
|
||||
print('=======打印货架所有货位编码=========')
|
||||
for record in self.location_ids:
|
||||
print('record', record)
|
||||
if not record.barcode:
|
||||
continue
|
||||
record.ensure_one()
|
||||
# qr_code_data = record.lot_qr_code
|
||||
# if not qr_code_data:
|
||||
# raise UserError("没有找到二维码数据。")
|
||||
barcode = record.barcode
|
||||
# todo 待控制
|
||||
if not barcode:
|
||||
raise ValidationError("请先分配序列号")
|
||||
# host = "192.168.50.110" # 可以根据实际情况修改
|
||||
# port = 9100 # 可以根据实际情况修改
|
||||
|
||||
# 获取默认打印机配置
|
||||
printer_config = self.env['printer.configuration'].sudo().search([('model', '=', self._name)], limit=1)
|
||||
if not printer_config:
|
||||
raise UserError('请先配置打印机')
|
||||
host = printer_config.printer_id.ip_address
|
||||
port = printer_config.printer_id.port
|
||||
self.print_qr_code(barcode, host, port)
|
||||
|
||||
|
||||
class ShelfLocation(models.Model):
|
||||
_name = 'sf.shelf.location'
|
||||
_inherit = ['printing.utils']
|
||||
_description = '货位'
|
||||
_order = 'name, id'
|
||||
_rec_name = 'barcode'
|
||||
_order = 'id asc, create_date asc'
|
||||
|
||||
# current_location_id = fields.Many2one('sf.shelf.location', string='当前位置')
|
||||
# # 目的位置
|
||||
@@ -319,6 +347,7 @@ class ShelfLocation(models.Model):
|
||||
destination_move_ids = fields.One2many('stock.move.line', 'destination_location_id', '目标位置调拨单')
|
||||
storage_time = fields.Datetime('入库时间', compute='_compute_location_status')
|
||||
production_id = fields.Many2one('mrp.production', string='制造订单')
|
||||
active = fields.Boolean("有效", default=True)
|
||||
|
||||
@api.depends('location_status')
|
||||
def _compute_location_status(self):
|
||||
@@ -332,6 +361,8 @@ class ShelfLocation(models.Model):
|
||||
|
||||
name = fields.Char('货位名称', required=True, size=20)
|
||||
barcode = fields.Char('货位编码', copy=False, size=50)
|
||||
qr_code = fields.Binary(string='二维码', compute='_compute_location_qr_code', store=True)
|
||||
|
||||
# 货架
|
||||
shelf_id = fields.Many2one('sf.shelf', string='货架')
|
||||
|
||||
@@ -343,6 +374,62 @@ class ShelfLocation(models.Model):
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
|
||||
@api.depends('barcode')
|
||||
def _compute_location_qr_code(self):
|
||||
for record in self:
|
||||
if record.barcode:
|
||||
# 创建一个QRCode对象
|
||||
qr = qrcode.QRCode(
|
||||
version=1, # 设置版本, 1-40,控制二维码的大小
|
||||
error_correction=qrcode.constants.ERROR_CORRECT_L, # 设置错误校正等级
|
||||
box_size=10, # 设置每个格子的像素大小
|
||||
border=4, # 设置边框的格子宽度
|
||||
)
|
||||
# 添加数据
|
||||
qr.add_data(record.barcode)
|
||||
qr.make(fit=True)
|
||||
# 创建二维码图像
|
||||
img = qr.make_image(fill_color="black", back_color="white")
|
||||
# 创建一个内存文件
|
||||
buffer = io.BytesIO()
|
||||
img.save(buffer, format="PNG") # 将图像保存到内存文件中
|
||||
# 获取二进制数据
|
||||
binary_data = buffer.getvalue()
|
||||
# 使用Base64编码这些二进制数据
|
||||
data = base64.b64encode(binary_data)
|
||||
self.qr_code = data
|
||||
else:
|
||||
record.qr_code = False
|
||||
|
||||
def print_single_location_qr_code(self):
|
||||
self.ensure_one()
|
||||
qr_code_data = self.qr_code
|
||||
if not qr_code_data:
|
||||
raise UserError("没有找到二维码数据。")
|
||||
barcode = self.barcode
|
||||
# host = "192.168.50.110" # 可以根据实际情况修改
|
||||
# port = 9100 # 可以根据实际情况修改
|
||||
# 获取默认打印机配置
|
||||
printer_config = self.env['printer.configuration'].sudo().search([('model', '=', self._name)], limit=1)
|
||||
if not printer_config:
|
||||
raise UserError('请先配置打印机')
|
||||
host = printer_config.printer_id.ip_address
|
||||
port = printer_config.printer_id.port
|
||||
self.print_qr_code(barcode, host, port)
|
||||
# 获取当前wizard的视图ID或其他标识信息
|
||||
view_id = self.env.context.get('view_id')
|
||||
# 构造返回wizard页面的action字典
|
||||
action = {
|
||||
'type': 'ir.actions.act_window',
|
||||
'name': '返回 Wizard',
|
||||
'res_model': 'sf.shelf', # 替换为你的wizard模型名称
|
||||
'view_mode': 'form',
|
||||
'view_id': view_id, # 如果需要基于特定的视图返回
|
||||
'target': 'new', # 如果需要在新的窗口或标签页打开
|
||||
'res_id': self.shelf_id, # 如果你想要返回当前记录的视图
|
||||
}
|
||||
return action
|
||||
|
||||
# # 仓库类别(selection:库区、库位、货位)
|
||||
# location_type = fields.Selection([
|
||||
# ('货架', '货架'),
|
||||
@@ -361,10 +448,20 @@ class ShelfLocation(models.Model):
|
||||
('空闲', '空闲'),
|
||||
('占用', '占用'),
|
||||
('禁用', '禁用')
|
||||
], string='货位状态', default='空闲', readonly=True)
|
||||
], string='货位状态', default='空闲', compute='_compute_product_num', store=True)
|
||||
# product_id = fields.Many2one('product.template', string='产品')
|
||||
product_id = fields.Many2one('product.product', string='产品', readonly=True)
|
||||
product_id = fields.Many2one('product.product', string='产品', compute='_compute_product_id', store=True)
|
||||
product_sn_id = fields.Many2one('stock.lot', string='产品序列号')
|
||||
# 产品数量
|
||||
product_num = fields.Integer('数量')
|
||||
|
||||
@api.depends('product_num')
|
||||
def _compute_product_num(self):
|
||||
for record in self:
|
||||
if record.product_num > 0:
|
||||
record.location_status = '占用'
|
||||
elif record.product_num == 0:
|
||||
record.location_status = '空闲'
|
||||
|
||||
# 修改货位状态为禁用
|
||||
def action_location_status_disable(self):
|
||||
@@ -381,12 +478,20 @@ class ShelfLocation(models.Model):
|
||||
"""
|
||||
for record in self:
|
||||
if record.product_sn_id:
|
||||
record.sudo().product_id = record.product_sn_id.product_id
|
||||
record.sudo().location_status = '占用'
|
||||
try:
|
||||
record.sudo().product_id = record.product_sn_id.product_id
|
||||
# record.sudo().location_status = '占用'
|
||||
record.sudo().product_num = 1
|
||||
except Exception as e:
|
||||
print('eeeeeee占用', e)
|
||||
|
||||
else:
|
||||
record.product_id = False
|
||||
# record.location_status = '空闲'
|
||||
try:
|
||||
record.sudo().product_id = False
|
||||
# record.sudo().location_status = '空闲'
|
||||
record.sudo().product_num = 0
|
||||
except Exception as e:
|
||||
print('eeeeeee空闲', e)
|
||||
|
||||
# 调取获取货位信息接口
|
||||
def get_sf_shelf_location_info(self):
|
||||
@@ -411,6 +516,19 @@ class ShelfLocation(models.Model):
|
||||
else:
|
||||
raise UserError("该库位无产品")
|
||||
|
||||
@api.model_create_multi
|
||||
def create(self, vals_list):
|
||||
# 编码重复校验
|
||||
barcode_list = []
|
||||
for val in vals_list:
|
||||
location = self.search([('barcode', '=', val['barcode'])])
|
||||
if location:
|
||||
barcode_list.append(val['name'])
|
||||
if barcode_list:
|
||||
raise UserError("货位编码【%s】存在重复" % barcode_list)
|
||||
records = super(ShelfLocation, self).create(vals_list)
|
||||
return records
|
||||
|
||||
|
||||
class Sf_stock_move_line(models.Model):
|
||||
_name = 'stock.move.line'
|
||||
@@ -423,6 +541,16 @@ class Sf_stock_move_line(models.Model):
|
||||
location_dest_id_value = fields.Integer(compute='_compute_location_dest_id_value', store=True)
|
||||
# lot_qr_code = fields.Binary(string='二维码', compute='_compute_lot_qr_code', store=True)
|
||||
lot_qr_code = fields.Binary(string='二维码', compute='_compute_lot_qr_code', store=True)
|
||||
current_product_id = fields.Integer(compute='_compute_location_dest_id_value', store=True)
|
||||
there_is_no_sn = fields.Boolean('是否有序列号', default=False)
|
||||
|
||||
rfid = fields.Char('Rfid')
|
||||
rfid_barcode = fields.Char('Rfid', compute='_compute_rfid')
|
||||
|
||||
@api.depends('lot_id')
|
||||
def _compute_rfid(self):
|
||||
for item in self:
|
||||
item.rfid_barcode = item.lot_id.rfid
|
||||
|
||||
def action_revert_inventory(self):
|
||||
# 检查用户是否有执行操作的权限
|
||||
@@ -430,7 +558,7 @@ class Sf_stock_move_line(models.Model):
|
||||
raise UserError(_('抱歉,只有库管人员可以执行此动作'))
|
||||
|
||||
# 如果用户有权限,调用父类方法
|
||||
return super(CustomStockMoveLine, self).action_revert_inventory()
|
||||
return super().action_revert_inventory()
|
||||
|
||||
@api.depends('lot_name')
|
||||
def _compute_lot_qr_code(self):
|
||||
@@ -475,7 +603,7 @@ class Sf_stock_move_line(models.Model):
|
||||
# port = 9100 # 可以根据实际情况修改
|
||||
|
||||
# 获取默认打印机配置
|
||||
printer_config = self.env['printer.configuration'].search([('model', '=', self._name)], limit=1)
|
||||
printer_config = self.env['printer.configuration'].sudo().search([('model', '=', self._name)], limit=1)
|
||||
if not printer_config:
|
||||
raise UserError('请先配置打印机')
|
||||
host = printer_config.printer_id.ip_address
|
||||
@@ -692,30 +820,43 @@ class Sf_stock_move_line(models.Model):
|
||||
def _compute_location_dest_id_value(self):
|
||||
for record in self:
|
||||
record.location_dest_id_value = record.location_dest_id.id if record.location_dest_id else False
|
||||
record.current_product_id = record.product_id.id if record.product_id else False
|
||||
|
||||
destination_location_id = fields.Many2one(
|
||||
'sf.shelf.location', string='目标货位')
|
||||
|
||||
@api.onchange('destination_location_id')
|
||||
def _compute_destination_location_id(self):
|
||||
def compute_destination_location_id(self):
|
||||
for record in self:
|
||||
shelf_location_obj = self.env['sf.shelf.location'].search(
|
||||
[('product_sn_id', '=', record.lot_id.id)])
|
||||
if shelf_location_obj:
|
||||
shelf_location_obj.product_sn_id = False
|
||||
# obj = self.env['sf.shelf.location'].search([('location_id', '=',
|
||||
# self.destination_location_id.id)])
|
||||
obj = self.env['sf.shelf.location'].search([('name', '=',
|
||||
self.destination_location_id.name)])
|
||||
if obj:
|
||||
obj.product_sn_id = record.lot_id.id
|
||||
obj = self.env['sf.shelf.location'].search([('name', '=',
|
||||
self.destination_location_id.name)])
|
||||
if record.lot_id:
|
||||
shelf_location_obj = self.env['sf.shelf.location'].search(
|
||||
[('product_sn_id', '=', record.lot_id.id)])
|
||||
if shelf_location_obj:
|
||||
shelf_location_obj.product_sn_id = False
|
||||
if obj:
|
||||
obj.product_sn_id = record.lot_id.id
|
||||
else:
|
||||
pass
|
||||
if obj:
|
||||
obj.product_sn_id = record.lot_id.id
|
||||
else:
|
||||
obj = self.env['sf.shelf.location'].search([('name', '=',
|
||||
self.destination_location_id.name)])
|
||||
if obj:
|
||||
obj.product_sn_id = record.lot_id.id
|
||||
obj.product_id = record.product_id.id
|
||||
# obj.location_status = '占用'
|
||||
obj.product_num += record.reserved_uom_qty
|
||||
|
||||
@api.onchange('destination_location_id')
|
||||
def _check_destination_location_id(self):
|
||||
for item in self:
|
||||
if item:
|
||||
i = 0
|
||||
barcode = item.destination_location_id.barcode
|
||||
for line in item.picking_id.move_line_ids_without_package:
|
||||
if barcode and barcode == line.destination_location_id.barcode:
|
||||
i += 1
|
||||
if i > 1:
|
||||
raise ValidationError(
|
||||
'【%s】货位已经被占用,请重新选择!!!' % item.destination_location_id.barcode)
|
||||
|
||||
|
||||
class SfStockPicking(models.Model):
|
||||
@@ -739,24 +880,39 @@ class SfStockPicking(models.Model):
|
||||
res = super(SfStockPicking, self).button_validate()
|
||||
for line in self.move_line_ids:
|
||||
if line:
|
||||
# 调用入库方法进行入库
|
||||
line.compute_destination_location_id()
|
||||
if line.current_location_id:
|
||||
line.current_location_id.product_sn_id = False
|
||||
line.current_location_id.location_status = '空闲'
|
||||
if line.current_location_id.product_sn_id:
|
||||
line.current_location_id.product_sn_id = False
|
||||
# line.current_location_id.location_status = '空闲'
|
||||
line.current_location_id.product_num = 0
|
||||
|
||||
# 对入库作业的刀柄和托盘进行Rfid绑定校验
|
||||
for move in self.move_ids:
|
||||
if move and move.product_id.cutting_tool_material_id.name == '刀柄' or '托盘' in (
|
||||
move.product_id.fixture_material_id.name or ''):
|
||||
for item in move.move_line_nosuggest_ids:
|
||||
if item.location_dest_id.name == '进货':
|
||||
if not item.rfid:
|
||||
raise ValidationError('你需要提供%s的Rfid' % move.product_id.name)
|
||||
self.env['stock.lot'].search([('name', '=', item.lot_name)]).write({'rfid': item.rfid})
|
||||
return res
|
||||
|
||||
# def print_all_barcode(self):
|
||||
# """
|
||||
# 打印所有编码
|
||||
# """
|
||||
# print('================')
|
||||
# for record in self.move_ids_without_package:
|
||||
# print('record', record)
|
||||
# print('record.move_line_ids', record.move_line_ids)
|
||||
#
|
||||
# # record.move_line_ids.print_qr_code()
|
||||
#
|
||||
# print('record.move_line_ids.lot_id', record.move_line_ids.lot_id)
|
||||
# print('record.move_line_ids.lot_id.name', record.move_line_ids.lot_id.name)
|
||||
|
||||
# def print_all_barcode(self):
|
||||
# """
|
||||
# 打印所有编码
|
||||
# """
|
||||
# print('================')
|
||||
# for record in self.move_ids_without_package:
|
||||
# print('record', record)
|
||||
# print('record.move_line_ids', record.move_line_ids)
|
||||
#
|
||||
# # record.move_line_ids.print_qr_code()
|
||||
#
|
||||
# print('record.move_line_ids.lot_id', record.move_line_ids.lot_id)
|
||||
# print('record.move_line_ids.lot_id.name', record.move_line_ids.lot_id.name)
|
||||
|
||||
|
||||
class SfProcurementGroup(models.Model):
|
||||
@@ -822,117 +978,55 @@ class SfProcurementGroup(models.Model):
|
||||
return res
|
||||
|
||||
|
||||
class SfWarehouse(models.Model):
|
||||
_inherit = 'stock.warehouse'
|
||||
|
||||
check_state = fields.Selection([
|
||||
('enable', '启用'),
|
||||
('close', '关闭')
|
||||
], string='审核状态', default='close')
|
||||
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
|
||||
|
||||
class SfRule(models.Model):
|
||||
_inherit = 'stock.rule'
|
||||
|
||||
check_state = fields.Selection([
|
||||
('enable', '启用'),
|
||||
('close', '关闭')
|
||||
], string='审核状态', default='close')
|
||||
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
|
||||
|
||||
class SfRoute(models.Model):
|
||||
_inherit = 'stock.route'
|
||||
|
||||
check_state = fields.Selection([
|
||||
('enable', '启用'),
|
||||
('close', '关闭')
|
||||
], string='审核状态', default='close')
|
||||
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
|
||||
# class SfPickingType(models.Model):
|
||||
# _inherit = 'stock.picking.type'
|
||||
#
|
||||
# def _default_show_operations(self):
|
||||
# return self.user_has_groups('stock.group_production_lot,'
|
||||
# 'stock.group_stock_multi_locations,'
|
||||
# 'stock.group_tracking_lot',
|
||||
# 'sf_warehouse.group_sf_stock_user',
|
||||
# 'sf_warehouse.group_sf_stock_manager')
|
||||
|
||||
class SfPickingType(models.Model):
|
||||
_inherit = 'stock.picking.type'
|
||||
|
||||
check_state = fields.Selection([
|
||||
('enable', '启用'),
|
||||
('close', '关闭')
|
||||
], string='审核状态', default='close')
|
||||
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
|
||||
|
||||
class SfBarcodeNomenclature(models.Model):
|
||||
_inherit = 'barcode.nomenclature'
|
||||
|
||||
check_state = fields.Selection([
|
||||
('enable', '启用'),
|
||||
('close', '关闭')
|
||||
], string='审核状态', default='close')
|
||||
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
|
||||
|
||||
class SfPutawayRule(models.Model):
|
||||
_inherit = 'stock.putaway.rule'
|
||||
|
||||
check_state = fields.Selection([
|
||||
('enable', '同意'),
|
||||
('close', '不同意')
|
||||
], string='审核状态', default='close')
|
||||
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
|
||||
|
||||
class SfWarehouseOrderpoint(models.Model):
|
||||
_inherit = 'stock.warehouse.orderpoint'
|
||||
|
||||
check_state = fields.Selection([
|
||||
('enable', '同意'),
|
||||
('close', '不同意')
|
||||
], string='审核状态', default='close')
|
||||
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
|
||||
|
||||
class SfStockQuant(models.Model):
|
||||
_inherit = 'stock.quant'
|
||||
|
||||
check_state = fields.Selection([
|
||||
('enable', '同意'),
|
||||
('close', '不同意')
|
||||
], string='审核状态', default='close')
|
||||
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
|
||||
|
||||
class SfStockScrap(models.Model):
|
||||
_inherit = 'stock.scrap'
|
||||
|
||||
check_state = fields.Selection([
|
||||
('enable', '启用'),
|
||||
('close', '关闭')
|
||||
], string='审核状态', default='close')
|
||||
|
||||
def action_check(self):
|
||||
self.check_state = 'enable'
|
||||
def _default_show_operations(self):
|
||||
return self.user_has_groups(
|
||||
'stock.group_production_lot,'
|
||||
'stock.group_stock_multi_locations,'
|
||||
'stock.group_tracking_lot,'
|
||||
'sf_warehouse.group_sf_stock_user,'
|
||||
'sf_warehouse.group_sf_stock_manager'
|
||||
)
|
||||
|
||||
|
||||
class CustomStockMove(models.Model):
|
||||
_name = 'stock.move'
|
||||
_inherit = ['stock.move', 'printing.utils']
|
||||
_inherit = ['stock.move', 'printing.utils', 'barcodes.barcode_events_mixin']
|
||||
|
||||
def on_barcode_scanned(self, barcode):
|
||||
"""
|
||||
采购入库扫码绑定Rfid码
|
||||
"""
|
||||
for record in self:
|
||||
if record:
|
||||
if '刀柄' in (record.product_id.cutting_tool_material_id.name or '') or '托盘' in (
|
||||
record.product_id.fixture_material_id.name or ''):
|
||||
for move_line_nosuggest_id in record.move_line_nosuggest_ids:
|
||||
if move_line_nosuggest_id.rfid:
|
||||
if move_line_nosuggest_id.rfid == barcode:
|
||||
if record.product_id.cutting_tool_material_id.name:
|
||||
raise ValidationError('该刀柄的Rfid已经录入,请勿重复录入!!!')
|
||||
else:
|
||||
raise ValidationError('该托盘的Rfid已经录入,请勿重复录入!!!')
|
||||
else:
|
||||
line_id = int(re.sub(r"\D", "", str(move_line_nosuggest_id.id)))
|
||||
self.env['stock.move.line'].sudo().search([('id', '=', line_id)]).write({'rfid': barcode})
|
||||
move_line_nosuggest_id.rfid = barcode
|
||||
break
|
||||
else:
|
||||
raise ValidationError('该产品不需要录入Rfid!!!')
|
||||
|
||||
def action_assign_serial_show_details(self):
|
||||
# 首先执行原有逻辑
|
||||
@@ -983,7 +1077,7 @@ class CustomStockMove(models.Model):
|
||||
# port = 9100 # 可以根据实际情况修改
|
||||
|
||||
# 获取默认打印机配置
|
||||
printer_config = self.env['printer.configuration'].search([('model', '=', self._name)], limit=1)
|
||||
printer_config = self.env['printer.configuration'].sudo().search([('model', '=', self._name)], limit=1)
|
||||
if not printer_config:
|
||||
raise UserError('请先配置打印机')
|
||||
host = printer_config.printer_id.ip_address
|
||||
|
||||
@@ -104,17 +104,11 @@ access_mrp_production_group_sf_stock_user,mrp.production,mrp.model_mrp_productio
|
||||
|
||||
access_sf_shelf_location_group_plan_dispatch,sf.shelf.location,model_sf_shelf_location,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_stock_move,stock.move,stock.model_stock_move,sf_base.group_plan_dispatch,1,1,1,0
|
||||
access_stock_picking,stock.picking,stock.model_stock_picking,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_stock_picking_group_plan_dispatch,stock.picking,stock.model_stock_picking,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_stock_lot_group_plan_dispatch,stock.lot,stock.model_stock_lot,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_stock_lot_group_plan_director,stock.lot,stock.model_stock_lot,sf_base.group_plan_director,1,1,1,0
|
||||
access_stock_warehouse_orderpoint,stock.warehouse.orderpoint,stock.model_stock_warehouse_orderpoint,sf_base.group_plan_dispatch,1,1,0,0
|
||||
|
||||
|
||||
access_product_product,product.product,product.model_product_product,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_product_template,product.template,product.model_product_template,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_product_product,product.product,product.model_product_product,sf_base.group_plan_director,1,1,1,0
|
||||
access_product_template,product.template,product.model_product_template,sf_base.group_plan_director,1,1,1,0
|
||||
|
||||
access_stock_inventory_conflict,stock.inventory.conflict,stock.model_stock_inventory_conflict,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_stock_inventory_warning,stock.inventory.warning,stock.model_stock_inventory_warning,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_stock_inventory_adjustment_name,stock.inventory.adjustment.name,stock.model_stock_inventory_adjustment_name,sf_base.group_plan_dispatch,1,0,0,0
|
||||
@@ -140,6 +134,9 @@ access_sf_cutting_tool_material_group_sf_stock_manager,sf_cutting_tool_material_
|
||||
access_sf_cutting_tool_standard_library_group_sf_stock_manager,sf_cutting_tool_standard_library_group_sf_stock_manager,sf_base.model_sf_cutting_tool_standard_library,sf_warehouse.group_sf_stock_manager,1,0,1,0
|
||||
access_sf_tool_materials_basic_parameters_group_sf_stock_manager,sf_tool_materials_basic_parameters_group_sf_stock_manager,sf_base.model_sf_tool_materials_basic_parameters,sf_warehouse.group_sf_stock_manager,1,0,1,0
|
||||
|
||||
access_sf_shelf_location_wizard_group_plan_dispatch,sf_shelf_location_wizard_group_plan_dispatch,model_sf_shelf_location_wizard,sf_base.group_plan_dispatch,1,0,0,0
|
||||
access_sf_shelf_location_wizard_group_sf_stock_user_group_sf_stock_user,sf_shelf_location_wizard_group_sf_stock_user_group_sf_stock_user,model_sf_shelf_location_wizard,sf_warehouse.group_sf_stock_user,1,0,0,0
|
||||
access_sf_shelf_location_wizard_group_sf_stock_manager,sf_shelf_location_wizard_group_sf_stock_manager,model_sf_shelf_location_wizard,sf_warehouse.group_sf_stock_manager,1,1,1,0
|
||||
|
||||
|
||||
|
||||
|
||||
|
@@ -10,10 +10,18 @@
|
||||
<field name="current_location_id" force_save="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='location_dest_id'][2]" position="after">
|
||||
<field name="destination_location_id" domain="[
|
||||
('location_id', '=', location_dest_id_value),
|
||||
('location_status', '=', '空闲')
|
||||
]"/>
|
||||
<field name="current_product_id" invisible="1"/>
|
||||
<field name="there_is_no_sn" invisible="1"/>
|
||||
<!-- <field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), -->
|
||||
<!-- '|', -->
|
||||
<!-- ('location_status', '=', '空闲'), -->
|
||||
<!-- ('location_status', '=', '占用'), ('product_id', '=', current_product_id) -->
|
||||
<!-- ]"/> -->
|
||||
<field name="destination_location_id" domain="[('location_id', '=', location_dest_id_value), '|',
|
||||
('location_status', '=', '空闲'), ('product_id', '=', current_product_id), ('product_sn_id',
|
||||
'=', there_is_no_sn)]" options="{'no_create': True,'no_create_edit':True}"/>
|
||||
<field name="rfid_barcode" string="Rfid"/>
|
||||
|
||||
<!-- <field name="location_dest_id_product_type"/> -->
|
||||
<!-- <field name="location_dest_id"/> -->
|
||||
<field name="location_dest_id_value" invisible="1"/>
|
||||
@@ -31,15 +39,16 @@
|
||||
<field name="current_location_id" force_save="1"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='location_dest_id']" position="after">
|
||||
<field name="destination_location_id" />
|
||||
<!-- <field name="location_dest_id_product_type"/> -->
|
||||
<!-- <field name="location_dest_id"/> -->
|
||||
<field name="destination_location_id"/>
|
||||
<!-- <field name="location_dest_id_product_type"/> -->
|
||||
<!-- <field name="location_dest_id"/> -->
|
||||
<field name="location_dest_id_value" invisible="1"/>
|
||||
<!-- <button name="button_test" string="测试" type="object" class="oe_highlight"/> -->
|
||||
<!-- <button name="button_test" string="测试" type="object" class="oe_highlight"/> -->
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
|
||||
<record id="sf_stock_move_line_form" model="ir.ui.view">
|
||||
<field name="name">sf.stock.move.line.form</field>
|
||||
<field name="model">stock.move.line</field>
|
||||
@@ -63,6 +72,9 @@
|
||||
<field name="model">stock.move.line</field>
|
||||
<field name="inherit_id" ref="stock.view_stock_move_line_operation_tree"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='lot_name']" position="after">
|
||||
<field name="rfid"/>
|
||||
</xpath>
|
||||
<xpath expr="//field[@name='product_uom_id']" position="after">
|
||||
<field name="lot_qr_code" widget="image"/>
|
||||
<button name="print_single_method" string="打印编码" type="object" class="oe_highlight"/>
|
||||
@@ -103,10 +115,10 @@
|
||||
groups="sf_warehouse.group_sf_stock_user" data-hotkey="k"/>
|
||||
</xpath>
|
||||
|
||||
<!-- <xpath expr="//form//sheet//notebook//page//field[@name='move_ids_without_package']" position="before"> -->
|
||||
<!-- <field name="check_in" invisible="True"/> -->
|
||||
<!-- <button name="print_all_barcode" string="打印所有编码" type="object" attrs="{'invisible': [('check_in', '!=', 'IN')]}"/> -->
|
||||
<!-- </xpath> -->
|
||||
<!-- <xpath expr="//form//sheet//notebook//page//field[@name='move_ids_without_package']" position="before"> -->
|
||||
<!-- <field name="check_in" invisible="True"/> -->
|
||||
<!-- <button name="print_all_barcode" string="打印所有编码" type="object" attrs="{'invisible': [('check_in', '!=', 'IN')]}"/> -->
|
||||
<!-- </xpath> -->
|
||||
|
||||
</field>
|
||||
</record>
|
||||
@@ -117,7 +129,7 @@
|
||||
<field name="inherit_id" ref="stock.stock_scrap_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//header//button[@name='action_validate']" position="replace">
|
||||
<button name="action_validate" states="draft" string="Validate" type="object" class="oe_highlight"
|
||||
<button name="action_validate" states="draft" string="确认" type="object" class="oe_highlight"
|
||||
context="{'not_unlink_on_discard': True}" data-hotkey="v"
|
||||
groups="sf_warehouse.group_sf_stock_user"/>
|
||||
</xpath>
|
||||
@@ -145,11 +157,23 @@
|
||||
<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='move_line_ids']" position="before"> -->
|
||||
<!-- <button name="print_all_barcode" type="object" string="打印所有编码"/> -->
|
||||
<!-- </xpath> -->
|
||||
<!-- <xpath expr="//form//field[@name='move_line_ids']" position="before"> -->
|
||||
<!-- <button name="print_all_barcode" type="object" string="打印所有编码"/> -->
|
||||
<!-- </xpath> -->
|
||||
<xpath expr="//form//field[@name='product_id']" position="before">
|
||||
<button name="print_all_barcode" type="object" string="打印所有编码" class="oe_highlight"/> -->
|
||||
<button name="print_all_barcode" type="object" string="打印所有编码" class="oe_highlight"/>
|
||||
-->
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="mrp_subcontracting_view_stock_move_barcode_scanned" model="ir.ui.view">
|
||||
<field name="name">mrp.subcontracting.stock.move.barcode.scanned.form</field>
|
||||
<field name="model">stock.move</field>
|
||||
<field name="inherit_id" ref="stock.view_stock_move_nosuggest_operations"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//field[@name='move_line_nosuggest_ids']" position="before">
|
||||
<field name="_barcode_scanned" widget="barcode_handler"/>
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -1,7 +1,7 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<odoo>
|
||||
<data>
|
||||
<!-- 货架视图 -->
|
||||
<!-- 货架视图 -->
|
||||
<record id="view_sf_shelf" model="ir.ui.view">
|
||||
<field name="name">Sf Shelf</field>
|
||||
<field name="model">sf.shelf</field>
|
||||
@@ -9,7 +9,8 @@
|
||||
<form string="Sf Shelf">
|
||||
<header>
|
||||
<field name="is_there_area" invisible="1"/>
|
||||
<button string="生成货位" name="create_location" type="object" class="oe_highlight" attrs="{'invisible': [('is_there_area', '=', True)]}"/>
|
||||
<button string="生成货位" name="create_location" type="object" class="oe_highlight"
|
||||
attrs="{'invisible': [('is_there_area', '=', True)]}"/>
|
||||
</header>
|
||||
<sheet>
|
||||
<group>
|
||||
@@ -23,12 +24,21 @@
|
||||
<field name="shelf_layer" string="货架层数"/>
|
||||
<field name="layer_capacity" string="层数容量"/>
|
||||
</group>
|
||||
<field name="location_ids" widget="one2many_list">
|
||||
<tree string="Shelf Location">
|
||||
<field name="barcode" string="编码"/>
|
||||
<field name="name" string="名称"/>
|
||||
</tree>
|
||||
</field>
|
||||
<notebook>
|
||||
<page string="货位">
|
||||
<button name="print_all_location_barcode" type="object" string="一键打印"
|
||||
class="oe_highlight"/>
|
||||
<field name="location_ids" widget="one2many_list">
|
||||
<tree string="Shelf Location">
|
||||
<field name="barcode" string="编码"/>
|
||||
<field name="name" string="名称"/>
|
||||
<field name="qr_code" string="条码" widget="image"/>
|
||||
<button string="打印" name="print_single_location_qr_code" type="object"
|
||||
class="oe_highlight"/>
|
||||
</tree>
|
||||
</field>
|
||||
</page>
|
||||
</notebook>
|
||||
</sheet>
|
||||
</form>
|
||||
</field>
|
||||
@@ -46,23 +56,23 @@
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<!-- 货架action -->
|
||||
<!-- 货架action -->
|
||||
<record id="sf_shelf_action" model="ir.actions.act_window">
|
||||
<field name="name">货架</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.shelf</field>
|
||||
<field name="view_mode">tree,form</field>
|
||||
<!-- <field name="view_id" ref="view_sf_shelf_tree"/> -->
|
||||
<!-- <field name="view_id" ref="view_sf_shelf_tree"/> -->
|
||||
</record>
|
||||
|
||||
<!-- 货架菜单 -->
|
||||
<!-- 货架菜单 -->
|
||||
<menuitem
|
||||
id="sf_shelf_menu"
|
||||
name="货架"
|
||||
parent="stock.menu_warehouse_config"
|
||||
sequence="19"
|
||||
action="sf_shelf_action"
|
||||
groups="sf_warehouse.group_sf_stock_user"/>
|
||||
id="sf_shelf_menu"
|
||||
name="货架"
|
||||
parent="stock.menu_warehouse_config"
|
||||
sequence="19"
|
||||
action="sf_shelf_action"
|
||||
groups="sf_warehouse.group_sf_stock_user"/>
|
||||
|
||||
|
||||
<record id="view_shelf_location_tree" model="ir.ui.view">
|
||||
@@ -116,13 +126,25 @@
|
||||
<field name="name">Shelf Location form</field>
|
||||
<field name="model">sf.shelf.location</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="Shelf Location">
|
||||
<form string="Shelf Location" create="0">
|
||||
<header>
|
||||
|
||||
<button string="货位变更"
|
||||
name="%(sf_warehouse.sf_shelf_location_wizard_act)d"
|
||||
type="action"
|
||||
context="{'default_name':name,
|
||||
'default_current_name':name,
|
||||
'default_current_shelf_id':shelf_id,
|
||||
'default_current_location_id':location_id,
|
||||
'default_current_barcode':barcode,
|
||||
'default_current_product_id':product_id,
|
||||
}"
|
||||
class="btn-primary" attrs="{'invisible':[('location_status','!=','占用')]}"/>
|
||||
<field name="location_status" invisible="1"/>
|
||||
<button string="禁用货位" name="action_location_status_disable" type="object" class="oe_highlight"
|
||||
<button string="禁用货位" name="action_location_status_disable" type="object"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': [('location_status', '!=', '空闲')]}"/>
|
||||
<button string="启用货位" name="action_location_status_enable" type="object" class="oe_highlight"
|
||||
<button string="启用货位" name="action_location_status_enable" type="object"
|
||||
class="oe_highlight"
|
||||
attrs="{'invisible': [('location_status', '!=', '禁用')]}"/>
|
||||
</header>
|
||||
<sheet>
|
||||
@@ -143,12 +165,13 @@
|
||||
</button>
|
||||
</div>
|
||||
<group>
|
||||
<field name="barcode"/>
|
||||
<field name="name"/>
|
||||
<field name="shelf_id"/>
|
||||
<field name="location_id"/>
|
||||
<field name="product_sn_id"/>
|
||||
<field name="barcode" readonly="1"/>
|
||||
<field name="name" readonly="1"/>
|
||||
<field name="shelf_id" readonly="1"/>
|
||||
<field name="location_id" readonly="1"/>
|
||||
<field name="product_sn_id" options="{'no_create': True}"/>
|
||||
<field name="product_id"/>
|
||||
<field name="product_num" readonly="1"/>
|
||||
<field name="location_status"/>
|
||||
<field name="storage_time" widget="datetime"/>
|
||||
<field name="production_id" readonly="1"/>
|
||||
@@ -162,20 +185,20 @@
|
||||
<field name="name">shelf.location.kanban</field>
|
||||
<field name="model">sf.shelf.location</field>
|
||||
<field name="arch" type="xml">
|
||||
<kanban class="o_kanban_mobile" js_class="custom_kanban">
|
||||
<kanban class="o_kanban_mobile" js_class="custom_kanban" create="0">
|
||||
<templates>
|
||||
<t t-name="kanban-box">
|
||||
<div t-attf-class="oe_kanban_card oe_kanban_global_click
|
||||
#{record.location_status.raw_value == '空闲' ? 'kanban_color_1' : ''}
|
||||
#{record.location_status.raw_value == '占用' ? 'kanban_color_2' : ''}
|
||||
#{record.location_status.raw_value == '禁用' ? 'kanban_color_3' : ''}">
|
||||
<!-- 标题 -->
|
||||
<!-- 标题 -->
|
||||
<div class="o_kanban_card_header">
|
||||
<div class="o_kanban_card_header_title">
|
||||
<field name="name"/>
|
||||
</div>
|
||||
</div>
|
||||
<!-- 内容 -->
|
||||
<!-- 内容 -->
|
||||
<div class="o_kanban_record_bottom">
|
||||
<field name="location_status"/>
|
||||
</div>
|
||||
@@ -186,31 +209,31 @@
|
||||
</div>
|
||||
</div>
|
||||
</t>
|
||||
<!-- <t t-name="kanban-box"> -->
|
||||
<!-- <div t-attf-class="oe_kanban_card oe_kanban_global_click -->
|
||||
<!-- #{record.location_status.raw_value == '空闲' ? 'kanban_color_1' : ''} -->
|
||||
<!-- #{record.location_status.raw_value == '占用' ? 'kanban_color_2' : ''} -->
|
||||
<!-- #{record.location_status.raw_value == '禁用' ? 'kanban_color_3' : ''}"> -->
|
||||
<!-- 看板内容 -->
|
||||
<!-- </div> -->
|
||||
<!-- <div t-attf-class="oe_kanban_card"> -->
|
||||
<!-- 标题 -->
|
||||
<!-- <div class="o_kanban_card_header"> -->
|
||||
<!-- <div class="o_kanban_card_header_title"> -->
|
||||
<!-- <field name="name"/> -->
|
||||
<!-- </div> -->
|
||||
<!-- </div> -->
|
||||
<!-- 内容 -->
|
||||
<!-- <div class="o_kanban_record_bottom"> -->
|
||||
<!-- <field name="location_status"/> -->
|
||||
<!-- </div> -->
|
||||
<!-- <div class="o_kanban_record_bottom"> -->
|
||||
<!-- <field name="product_sn_id"/> -->
|
||||
<!-- <span> | </span> -->
|
||||
<!-- <field name="product_id"/> -->
|
||||
<!-- </div> -->
|
||||
<!-- </div> -->
|
||||
<!-- </t> -->
|
||||
<!-- <t t-name="kanban-box"> -->
|
||||
<!-- <div t-attf-class="oe_kanban_card oe_kanban_global_click -->
|
||||
<!-- #{record.location_status.raw_value == '空闲' ? 'kanban_color_1' : ''} -->
|
||||
<!-- #{record.location_status.raw_value == '占用' ? 'kanban_color_2' : ''} -->
|
||||
<!-- #{record.location_status.raw_value == '禁用' ? 'kanban_color_3' : ''}"> -->
|
||||
<!-- 看板内容 -->
|
||||
<!-- </div> -->
|
||||
<!-- <div t-attf-class="oe_kanban_card"> -->
|
||||
<!-- 标题 -->
|
||||
<!-- <div class="o_kanban_card_header"> -->
|
||||
<!-- <div class="o_kanban_card_header_title"> -->
|
||||
<!-- <field name="name"/> -->
|
||||
<!-- </div> -->
|
||||
<!-- </div> -->
|
||||
<!-- 内容 -->
|
||||
<!-- <div class="o_kanban_record_bottom"> -->
|
||||
<!-- <field name="location_status"/> -->
|
||||
<!-- </div> -->
|
||||
<!-- <div class="o_kanban_record_bottom"> -->
|
||||
<!-- <field name="product_sn_id"/> -->
|
||||
<!-- <span> | </span> -->
|
||||
<!-- <field name="product_id"/> -->
|
||||
<!-- </div> -->
|
||||
<!-- </div> -->
|
||||
<!-- </t> -->
|
||||
</templates>
|
||||
</kanban>
|
||||
</field>
|
||||
@@ -222,9 +245,10 @@
|
||||
<field name="model">sf.shelf.location</field>
|
||||
<field name="arch" type="xml">
|
||||
<search string="货位">
|
||||
<field name="barcode"/>
|
||||
<searchpanel class="account_root">
|
||||
<!-- <field name="location_type" icon="fa-filter"/> -->
|
||||
<!-- <field name="location_id" select="multi" icon="fa-filter"/> -->
|
||||
<!-- <field name="location_id" select="multi" icon="fa-filter"/> -->
|
||||
<field name="location_id" string="所属库区" icon="fa-filter"/>
|
||||
<field name="shelf_id" string="货架"/>
|
||||
<!-- <field name="location_status" icon="fa-filter"/> -->
|
||||
@@ -238,7 +262,7 @@
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.shelf.location</field>
|
||||
<field name="view_mode">kanban,form</field>
|
||||
<!-- <field name="domain">[('check_state','=','enable')]</field> -->
|
||||
<!-- <field name="domain">[('check_state','=','enable')]</field> -->
|
||||
</record>
|
||||
|
||||
<!-- <record id="example_action" model="ir.actions.act_window"> -->
|
||||
|
||||
@@ -67,16 +67,16 @@
|
||||
</notebook>
|
||||
</xpath>
|
||||
|
||||
<xpath expr="//sheet" position="before">
|
||||
<header>
|
||||
<field name="check_state" invisible="1"/>
|
||||
<button name="action_check" string="审核" type="object"
|
||||
attrs="{'invisible': [('check_state','=', 'enable')]}"
|
||||
groups="sf_warehouse.group_sf_stock_manager"
|
||||
class="oe_highlight"/>
|
||||
</header>
|
||||
<!-- <xpath expr="//sheet" position="before">-->
|
||||
<!-- <header>-->
|
||||
<!-- <field name="check_state" invisible="1"/>-->
|
||||
<!-- <button name="action_check" string="审核" type="object"-->
|
||||
<!-- attrs="{'invisible': [('check_state','=', 'enable')]}"-->
|
||||
<!-- groups="sf_warehouse.group_sf_stock_manager"-->
|
||||
<!-- class="oe_highlight"/>-->
|
||||
<!-- </header>-->
|
||||
|
||||
</xpath>
|
||||
<!-- </xpath>-->
|
||||
</field>
|
||||
</record>
|
||||
|
||||
@@ -188,23 +188,23 @@
|
||||
<!-- </record>-->
|
||||
|
||||
<!--仓库根据权限增加审核按钮-->
|
||||
<record id="view_warehouse_form_sf_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.warehouse.form.sf.inherit</field>
|
||||
<field name="model">stock.warehouse</field>
|
||||
<field name="inherit_id" ref="stock.view_warehouse"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet" position="before">
|
||||
<header>
|
||||
<field name="check_state" invisible="1"/>
|
||||
<button name="action_check" string="审核" type="object"
|
||||
attrs="{'invisible': [('check_state','=', 'enable')]}"
|
||||
groups="sf_warehouse.group_sf_stock_manager"
|
||||
class="oe_highlight"/>
|
||||
</header>
|
||||
<!-- <record id="view_warehouse_form_sf_inherit" model="ir.ui.view">-->
|
||||
<!-- <field name="name">stock.warehouse.form.sf.inherit</field>-->
|
||||
<!-- <field name="model">stock.warehouse</field>-->
|
||||
<!-- <field name="inherit_id" ref="stock.view_warehouse"/>-->
|
||||
<!-- <field name="arch" type="xml">-->
|
||||
<!-- <xpath expr="//sheet" position="before">-->
|
||||
<!-- <header>-->
|
||||
<!-- <field name="check_state" invisible="1"/>-->
|
||||
<!-- <button name="action_check" string="审核" type="object"-->
|
||||
<!-- attrs="{'invisible': [('check_state','=', 'enable')]}"-->
|
||||
<!-- groups="sf_warehouse.group_sf_stock_manager"-->
|
||||
<!-- class="oe_highlight"/>-->
|
||||
<!-- </header>-->
|
||||
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<!-- </xpath>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<!-- <record id="view_warehouse_tree_sf_inherit" model="ir.ui.view">-->
|
||||
<!-- <field name="name">stock.warehouse.tree.sf.inherit</field>-->
|
||||
@@ -220,23 +220,23 @@
|
||||
|
||||
|
||||
<!--路线根据权限增加审核按钮-->
|
||||
<record id="view_route_form_sf_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.route.form.sf.inherit</field>
|
||||
<field name="model">stock.route</field>
|
||||
<field name="inherit_id" ref="stock.stock_location_route_form_view"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet" position="before">
|
||||
<header>
|
||||
<field name="check_state" invisible="1"/>
|
||||
<button name="action_check" string="审核" type="object"
|
||||
attrs="{'invisible': [('check_state','=', 'enable')]}"
|
||||
groups="sf_warehouse.group_sf_stock_manager"
|
||||
class="oe_highlight"/>
|
||||
</header>
|
||||
<!-- <record id="view_route_form_sf_inherit" model="ir.ui.view">-->
|
||||
<!-- <field name="name">stock.route.form.sf.inherit</field>-->
|
||||
<!-- <field name="model">stock.route</field>-->
|
||||
<!-- <field name="inherit_id" ref="stock.stock_location_route_form_view"/>-->
|
||||
<!-- <field name="arch" type="xml">-->
|
||||
<!-- <xpath expr="//sheet" position="before">-->
|
||||
<!-- <header>-->
|
||||
<!-- <field name="check_state" invisible="1"/>-->
|
||||
<!-- <button name="action_check" string="审核" type="object"-->
|
||||
<!-- attrs="{'invisible': [('check_state','=', 'enable')]}"-->
|
||||
<!-- groups="sf_warehouse.group_sf_stock_manager"-->
|
||||
<!-- class="oe_highlight"/>-->
|
||||
<!-- </header>-->
|
||||
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<!-- </xpath>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<!-- <record id="view_route_tree_sf_inherit" model="ir.ui.view">-->
|
||||
<!-- <field name="name">stock.route.tree.sf.inherit</field>-->
|
||||
@@ -251,23 +251,23 @@
|
||||
<!-- </record>-->
|
||||
|
||||
<!--规则根据权限增加审核按钮-->
|
||||
<record id="view_rule_form_sf_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.rule.form.sf.inherit</field>
|
||||
<field name="model">stock.rule</field>
|
||||
<field name="inherit_id" ref="stock.view_stock_rule_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet" position="before">
|
||||
<header>
|
||||
<field name="check_state" invisible="1"/>
|
||||
<button name="action_check" string="审核" type="object"
|
||||
attrs="{'invisible': [('check_state','=', 'enable')]}"
|
||||
groups="sf_warehouse.group_sf_stock_manager"
|
||||
class="oe_highlight"/>
|
||||
</header>
|
||||
<!-- <record id="view_rule_form_sf_inherit" model="ir.ui.view">-->
|
||||
<!-- <field name="name">stock.rule.form.sf.inherit</field>-->
|
||||
<!-- <field name="model">stock.rule</field>-->
|
||||
<!-- <field name="inherit_id" ref="stock.view_stock_rule_form"/>-->
|
||||
<!-- <field name="arch" type="xml">-->
|
||||
<!-- <xpath expr="//sheet" position="before">-->
|
||||
<!-- <header>-->
|
||||
<!-- <field name="check_state" invisible="1"/>-->
|
||||
<!-- <button name="action_check" string="审核" type="object"-->
|
||||
<!-- attrs="{'invisible': [('check_state','=', 'enable')]}"-->
|
||||
<!-- groups="sf_warehouse.group_sf_stock_manager"-->
|
||||
<!-- class="oe_highlight"/>-->
|
||||
<!-- </header>-->
|
||||
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<!-- </xpath>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<!-- <record id="view_rule_tree_sf_inherit" model="ir.ui.view">-->
|
||||
<!-- <field name="name">stock.rule.tree.sf.inherit</field>-->
|
||||
@@ -282,23 +282,23 @@
|
||||
<!-- </record>-->
|
||||
|
||||
<!--作业类型根据权限增加审核按钮-->
|
||||
<record id="view_picking_type_form_sf_inherit" model="ir.ui.view">
|
||||
<field name="name">stock.picking.type.form.sf.inherit</field>
|
||||
<field name="model">stock.picking.type</field>
|
||||
<field name="inherit_id" ref="stock.view_picking_type_form"/>
|
||||
<field name="arch" type="xml">
|
||||
<xpath expr="//sheet" position="before">
|
||||
<header>
|
||||
<field name="check_state" invisible="1"/>
|
||||
<button name="action_check" string="审核" type="object"
|
||||
attrs="{'invisible': [('check_state','=', 'enable')]}"
|
||||
groups="sf_warehouse.group_sf_stock_manager"
|
||||
class="oe_highlight"/>
|
||||
</header>
|
||||
<!-- <record id="view_picking_type_form_sf_inherit" model="ir.ui.view">-->
|
||||
<!-- <field name="name">stock.picking.type.form.sf.inherit</field>-->
|
||||
<!-- <field name="model">stock.picking.type</field>-->
|
||||
<!-- <field name="inherit_id" ref="stock.view_picking_type_form"/>-->
|
||||
<!-- <field name="arch" type="xml">-->
|
||||
<!-- <xpath expr="//sheet" position="before">-->
|
||||
<!-- <header>-->
|
||||
<!-- <field name="check_state" invisible="1"/>-->
|
||||
<!-- <button name="action_check" string="审核" type="object"-->
|
||||
<!-- attrs="{'invisible': [('check_state','=', 'enable')]}"-->
|
||||
<!-- groups="sf_warehouse.group_sf_stock_manager"-->
|
||||
<!-- class="oe_highlight"/>-->
|
||||
<!-- </header>-->
|
||||
|
||||
</xpath>
|
||||
</field>
|
||||
</record>
|
||||
<!-- </xpath>-->
|
||||
<!-- </field>-->
|
||||
<!-- </record>-->
|
||||
|
||||
<!-- <record id="view_picking_type_tree_sf_inherit" model="ir.ui.view">-->
|
||||
<!-- <field name="name">stock.picking.type.tree.sf.inherit</field>-->
|
||||
|
||||
1
sf_warehouse/wizard/__init__.py
Normal file
1
sf_warehouse/wizard/__init__.py
Normal file
@@ -0,0 +1 @@
|
||||
from . import wizard
|
||||
64
sf_warehouse/wizard/wizard.py
Normal file
64
sf_warehouse/wizard/wizard.py
Normal file
@@ -0,0 +1,64 @@
|
||||
from odoo import fields, models, api
|
||||
from odoo.exceptions import UserError, ValidationError
|
||||
|
||||
|
||||
class ShelfLocationWizard(models.TransientModel):
|
||||
_name = 'sf.shelf.location.wizard'
|
||||
_description = '货位变更'
|
||||
|
||||
name = fields.Char('')
|
||||
|
||||
current_location_id = fields.Many2one('stock.location', string='所属库区', readonly=True)
|
||||
|
||||
current_shelf_id = fields.Many2one('sf.shelf', string='当前货架', readonly=True)
|
||||
current_barcode = fields.Char('当前货位编码', readonly=True)
|
||||
current_name = fields.Char('当前货位名称', readonly=True)
|
||||
current_product_id = fields.Many2one('product.product', string='产品', readonly=True)
|
||||
|
||||
destination_shelf_id = fields.Many2one('sf.shelf', string='目标货架', compute='_compute_destination_name')
|
||||
destination_barcode_id = fields.Many2one('sf.shelf.location', string='目标货位编码', required=True,
|
||||
domain="")
|
||||
destination_name = fields.Char('目标货位名称', compute='_compute_destination_name')
|
||||
|
||||
def return_domain(self):
|
||||
val = [('location_status', '=', '空闲')]
|
||||
if self.current_product_id:
|
||||
val = ['|', ('location_status', '=', '空闲'), ('product_id', '=', self.current_product_id)]
|
||||
if self.destination_shelf_id:
|
||||
val.append(('shelf_id', '=', self.destination_shelf_id))
|
||||
return "%s" % val
|
||||
|
||||
@api.depends('destination_barcode_id')
|
||||
def _compute_destination_name(self):
|
||||
if self.destination_barcode_id:
|
||||
self.destination_name = self.destination_barcode_id.name
|
||||
self.destination_shelf_id = self.destination_barcode_id.shelf_id.id
|
||||
else:
|
||||
self.destination_name = ''
|
||||
self.destination_shelf_id = False
|
||||
|
||||
#
|
||||
# @api.onchange('destination_barcode_id')
|
||||
# def _onchange_destination_shelf_id(self):
|
||||
# if self.destination_barcode_id:
|
||||
# self.destination_shelf_id = self.destination_barcode_id.shelf_id.id
|
||||
|
||||
def confirm_the_change(self):
|
||||
shelf_location = self.env['sf.shelf.location'].sudo().search([('barcode', '=', self.current_barcode)])
|
||||
# 变更货位
|
||||
if self.destination_barcode_id and shelf_location:
|
||||
if self.destination_barcode_id.product_id and self.destination_barcode_id.product_id == shelf_location.product_id and not self.destination_barcode_id.product_sn_id:
|
||||
self.destination_barcode_id.product_num += shelf_location.product_num
|
||||
else:
|
||||
self.destination_barcode_id.product_sn_id = shelf_location.product_sn_id.id
|
||||
self.destination_barcode_id.product_id = shelf_location.product_id.id
|
||||
self.destination_barcode_id.product_num = shelf_location.product_num
|
||||
|
||||
shelf_location.product_sn_id = False
|
||||
shelf_location.product_id = False
|
||||
shelf_location.product_num = 0
|
||||
else:
|
||||
raise ValidationError('目标货位出错,请联系管理员!')
|
||||
|
||||
# 关闭弹出窗口
|
||||
return {'type': 'ir.actions.act_window_close'}
|
||||
49
sf_warehouse/wizard/wizard_view.xml
Normal file
49
sf_warehouse/wizard/wizard_view.xml
Normal file
@@ -0,0 +1,49 @@
|
||||
<?xml version="1.0" encoding="UTF-8" ?>
|
||||
<odoo>
|
||||
<record id="sf_shelf_location_wizard_form" model="ir.ui.view">
|
||||
<field name="name">货位变更</field>
|
||||
<field name="model">sf.shelf.location.wizard</field>
|
||||
<field name="arch" type="xml">
|
||||
<form string="货位变更">
|
||||
<sheet>
|
||||
<group>
|
||||
<group string="初始货位">
|
||||
<group>
|
||||
<field name="current_location_id"/>
|
||||
<field name="current_shelf_id" string="货架"/>
|
||||
<field name="current_barcode" string="编码"/>
|
||||
<field name="current_name" string="名称"/>
|
||||
</group>
|
||||
</group>
|
||||
<group string="目标货位">
|
||||
<group>
|
||||
<field name="current_location_id"/>
|
||||
<field name="destination_shelf_id" string="货架" options="{'no_create': True}"
|
||||
placeholder="请选择目标货架"/>
|
||||
<field name="destination_barcode_id" string="编码" options="{'no_create': True}"
|
||||
placeholder="请选择目标货位"
|
||||
domain="['|', ('location_status', '=', '空闲'), ('product_id', '=', current_product_id)]"/>
|
||||
<field name="destination_name" string="名称"/>
|
||||
<field name="current_product_id" invisible="1"/>
|
||||
</group>
|
||||
</group>
|
||||
</group>
|
||||
</sheet>
|
||||
<footer>
|
||||
<button string="确定" name="confirm_the_change" type="object" class="btn-primary"
|
||||
confirm="是否确认变更货位"/>
|
||||
<button string="取消" class="btn-secondary" special="cancel"/>
|
||||
</footer>
|
||||
</form>
|
||||
</field>
|
||||
</record>
|
||||
|
||||
<record id="sf_shelf_location_wizard_act" model="ir.actions.act_window">
|
||||
<field name="name">货位变更</field>
|
||||
<field name="type">ir.actions.act_window</field>
|
||||
<field name="res_model">sf.shelf.location.wizard</field>
|
||||
<field name="view_mode">form</field>
|
||||
<field name="view_id" ref="sf_shelf_location_wizard_form"/>
|
||||
<field name="target">new</field>
|
||||
</record>
|
||||
</odoo>
|
||||
Reference in New Issue
Block a user